Haskell 您是否发现仍然需要可以更改的变量,如果需要,原因是什么?
我听到的反对函数式语言的一个论点是,单赋值编码太难了,或者至少比“普通”编程要困难得多 但是通过查看我的代码,我意识到我真的没有太多(任何?)的使用模式,如果你用一种相当现代的语言编写的话,就不能像使用单一赋值形式那样编写 那么,在一次范围调用中变化的变量的用例是什么呢?请记住,在这种情况下,循环索引、参数和其他在调用之间变化的范围绑定值不是多个赋值(除非您出于某种原因必须在主体中更改它们),并假设您正在使用远高于汇编语言级别的语言编写,在这里您可以编写以下内容Haskell 您是否发现仍然需要可以更改的变量,如果需要,原因是什么?,haskell,variables,functional-programming,ssa,modern-languages,Haskell,Variables,Functional Programming,Ssa,Modern Languages,我听到的反对函数式语言的一个论点是,单赋值编码太难了,或者至少比“普通”编程要困难得多 但是通过查看我的代码,我意识到我真的没有太多(任何?)的使用模式,如果你用一种相当现代的语言编写的话,就不能像使用单一赋值形式那样编写 那么,在一次范围调用中变化的变量的用例是什么呢?请记住,在这种情况下,循环索引、参数和其他在调用之间变化的范围绑定值不是多个赋值(除非您出于某种原因必须在主体中更改它们),并假设您正在使用远高于汇编语言级别的语言编写,在这里您可以编写以下内容 values.sum 或(如果
values.sum
或(如果未提供金额)
及
或
当您需要时,可以使用列表理解、地图/收集等
您是否发现在这样的环境中仍然需要可变变量?如果需要,原因是什么
为了澄清,我不是要求背诵对SSA表格的反对意见,而是要求列举那些反对意见适用的具体例子。我正在寻找一些代码,这些代码对于可变变量来说是清晰简洁的,如果没有它们就无法编写
到目前为止,我最喜欢的例子(以及我对它们的最大异议):
shuffle(Lst) ->
array:to_list(shuffle(array:from_list(Lst), erlang:length(Lst) - 1)).
shuffle(Array, 0) -> Array;
shuffle(Array, N) ->
K = random:uniform(N) - 1,
Ek = array:get(K, Array),
En = array:get(N, Array),
shuffle(array:set(K, En, array:set(N, Ek, Array)), N-1).
谢谢大家的努力。由于大多数答案被证明是1)基于可变数据结构,而不是基于单个赋值,以及2)在某种程度上,它们是关于单个赋值形式的,很容易被本领域技术人员反驳,因此我将从我的演讲和/或重组中划出一条线(可能会把它作为一个讨论主题放在备份中,以防在我没时间之前就说不出话来)
再次感谢。当您需要对大型数据结构进行小的更改时,该怎么办?您并不是真的希望每次修改几个元素时都复制整个数组或大型类。如果您想进行学术论证,那么从技术上讲,当然不需要多次指定变量。证明不是这样的所有的代码都可以用形式表示。事实上,对于许多静态和动态分析来说,这是最有用的形式 同时,有一些原因使我们不能从SSA表单开始编写代码:
案例
语句为例。如果有一个管理选项决定是否允许'*'
,并有一个单独的选项决定是否允许'?'
呢?此外,整数案例不允许为零,除非用户具有系统权限,否则所有的好的
这是一个更真实的例子,有分支和条件。你能把它写成一个“语句”吗?如果可以,是你的“语句”与许多单独的语句真的不同吗?如果不是,您需要多少临时的只写变量?这种情况是否比只有一个变量要好得多?回应Jason--
我从来没有发现过这样的情况。虽然你总是可以发明新的名称,比如在转换为SSA形式时,我实际上发现每个值都有自己的名称是很容易和自然的。像Haskell这样的语言为我提供了很多选择,关于命名哪些值,以及放置名称绑定的两个不同位置(
let
和where
)。我觉得单一的作业形式很自然,一点也不难
我偶尔会错过在堆上有指向可变对象的指针。但是这些东西没有名字,所以这不是同一个问题。(我还发现,当我在堆上使用可变对象时,我倾向于编写更多的bug!)本地(方法)变量当然不必被赋值两次。但即使在函数式编程中,重新赋值也是允许的。它改变了(部分)不允许的值。正如dsimcha已经回答的,对于非常大的结构(可能在应用程序的根上)对我来说,替换整个结构似乎不可行。想想看。应用程序的状态最终都由应用程序的入口点方法包含。如果绝对没有任何状态可以不被替换而更改,那么
x = if a > b then a else b
n = case s
/^\d*$/ : s.to_int
'' : 0
'*' : a.length
'?' : a.length.random
else fail "I don't know how many you want"
shuffle(Lst) ->
array:to_list(shuffle(array:from_list(Lst), erlang:length(Lst) - 1)).
shuffle(Array, 0) -> Array;
shuffle(Array, N) ->
K = random:uniform(N) - 1,
Ek = array:get(K, Array),
En = array:get(N, Array),
shuffle(array:set(K, En, array:set(N, Ek, Array)), N-1).
def area(figure : List[Point]) : Float = {
if(figure.empty) return 0
val last = figure(0)
var first= figure(0)
val ret = 0
for (pt <- figure) {
ret+=crossprod(last - first, pt - first)
last = pt
}
ret
}
def area(figure : List[Point]) : Float = {
if figure.length < 3
0
else
var a = figure(0)
var b = figure(1)
var c = figure(2)
if figure.length == 3
magnitude(crossproduct(b-a,c-a))
else
foldLeft((0,a,b))(figure.rest)) {
((t,a,b),c) => (t+area([a,b,c]),a,c)
}
def area([]) = 0.0 # An empty figure has no area
def area([_]) = 0.0 # ...nor does a point
def area([_,_]) = 0.0 # ...or a line segment
def area([a,b,c]) = # The area of a triangle can be found directly
magnitude(crossproduct(b-a,c-a))
def area(figure) = # For larger figures, reduce to triangles and sum
as_triangles(figure).collect(area).sum
def as_triangles([]) = [] # No triangles without at least three points
def as_triangles([_]) = []
def as_triangles([_,_]) = []
def as_triangles([a,b,c | rest) = [[a,b,c] | as_triangles([a,c | rest])]
function forbidden_input?(s)
(s = '?' and not administration.qmark_ok) ||
(s = '*' and not administration.stat_ok) ||
(s = '0' and not 'root node visible' in system.permissions_for(current_user))
n = if forbidden_input?(s)
fail "'" + s + "' is not allowed."
else
case s
/^\d*$/ : s.to_int
'' : 0
'*' : a.length
'?' : a.length.random
else fail "I don't know how many you want"
start = self.offset%n
if start:
start = n-start
def quant[A](x : List[A], q : A) = {
var tmp : A=0
for (el <- x) { tmp+= el; if(tmp > q) return el; }
// throw exception here, there is no prefix of the list with sum > q
}
def area(figure : List[Point]) : Float = {
if(figure.empty) return 0
val last = figure(0)
var first= figure(0)
val ret = 0
for (pt <- figure) {
ret+=crossprod(last - first, pt - first)
last = pt
}
ret
}
-- | Implementation of the random swap algorithm for shuffling. Reads a list
-- into a mutable ST array, shuffles it in place, and reads out the result
-- as a list.
module Data.Shuffle (shuffle) where
import Control.Monad
import Control.Monad.ST
import Data.Array.ST
import Data.STRef
import System.Random
-- | Shuffle a value based on a random seed.
shuffle :: (RandomGen g) => g -> [a] -> [a]
shuffle _ [] = []
shuffle g xs =
runST $ do
sg <- newSTRef g
let n = length xs
v <- newListArray (1, n) xs
mapM_ (shuffle1 sg v) [1..n]
getElems v
-- Internal function to swap element i with a random element at or above it.
shuffle1 :: (RandomGen g) => STRef s g -> STArray s Int a -> Int -> ST s ()
shuffle1 sg v i = do
(_, n) <- getBounds v
r <- getRnd sg $ randomR (i, n)
when (r /= i) $ do
vi <- readArray v i
vr <- readArray v r
writeArray v i vr
writeArray v r vi
-- Internal function for using random numbers
getRnd :: (RandomGen g) => STRef s g -> (g -> (a, g)) -> ST s a
getRnd sg f = do
g1 <- readSTRef sg
let (v, g2) = f g1
writeSTRef sg g2
return v
shuffle(Lst) ->
array:to_list(shuffle(array:from_list(Lst), erlang:length(Lst) - 1)).
shuffle(Array, 0) -> Array;
shuffle(Array, N) ->
K = random:uniform(N) - 1,
Ek = array:get(K, Array),
En = array:get(N, Array),
shuffle(array:set(K, En, array:set(N, Ek, Array)), N-1).
module Vector =
type point =
{ x : float; y : float}
with
static member ( + ) ((p1 : point), (p2 : point)) =
{ x = p1.x + p2.x;
y = p1.y + p2.y;}
static member ( * ) ((p : point), (scalar : float)) =
{ x = p.x * scalar;
y = p.y * scalar;}
static member ( - ) ((p1 : point), (p2 : point)) =
{ x = p1.x - p2.x;
y = p1.y - p2.y;}
let empty = { x = 0.; y = 0.;}
let to_tuple2 (p : point) = (p.x, p.y)
let from_tuple2 (x, y) = { x = x; y = y;}
let crossproduct (p1 : point) (p2 : point) =
{ x = p1.x * p2.y; y = -p1.y * p2.x }
let area (figure : point list) =
figure
|> Seq.map to_tuple2
|> Seq.fold
(fun (sum, (a, b)) (c, d) -> (sum + a*d - b*c, (c, d) ) )
(0., to_tuple2 (List.hd figure))
|> fun (sum, _) -> abs(sum) / 2.0
let area2 (figure : point list) =
figure
|> Seq.fold
(fun (acc, prev) cur -> (acc + (crossproduct prev cur), cur))
(empty, List.hd figure)
|> fun (acc, _) -> abs(acc.x + acc.y) / 2.0