我听到过反对函数式语言的一个观点是,单赋值编程太难了,或者至少比“正常”编程要困难得多。
但是看着我的代码,我意识到如果你使用一个相当现代化的语言编写,那么我真的没有许多(或任何?)不能用单赋值形式编写的使用模式。
那么,在作用域的单个调用中变化的变量有哪些用例呢?请记住,循环索引、参数和其他在调用之间变化的作用域绑定值在这种情况下不是多次赋值(除非你必须因为某种原因在主体中改变它们),并且假设你正在使用一个足够高于汇编语言级别的东西,你可以像写html标签一样书写:
values.sum
或者(如果没有提供sum)
function collection.sum --> inject(zero, function (v,t) --> t+v )
并且
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"
当你需要时,可以使用列表推导式、map/collect等功能。
在这样的环境中,您是否仍然希望/需要可变变量?如果是,是为了什么?
澄清一下,我不是要求重复阐述对SSA形式的反对意见,而是要具体举例说明这些反对意见适用的情况。我正在寻找清晰简洁的代码片段,其中包含可变变量,并且如果没有它们就无法编写。
到目前为止,我最喜欢的例子(也是我期望的最好反驳意见):
Paul Johnson's Fisher-Yates algorithm answer, which is pretty strong when you include the big-O constraints. But then, as catulahoops points out, the big-O issue isn't tied to the SSA question, but rather to having mutable data types, and with that set aside the algorithm can be written rather clearly in 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).
jpalecek's area of a polygon example:
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 }
which might still be written something like:
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) }
Or, since some people object to the density of this formulation, it could be recast:
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])]
Princess's point about the difficulty of implementing O(1) queues with immutable structures is interesting (and may well provide the basis for a compelling example) but as stated it's fundamentally about the mutability of the data structure, and not directly about the multiple assignment issue.
I'm intrigued by the Sieve of Eratosthenes answer, but unconvinced. The proper big-O, pull as many primes as you'd like generator given in the paper he cited does not look easy to implement correctly with or without SSA.
谢谢大家的尝试。由于大部分答案都是基于可变数据结构而非单赋值,且在单赋值形式上容易被熟练掌握技术的从业者反驳,因此我将从我的演讲中删去这一句话,或者重新组织结构(也许可以将其作为备选话题进行讨论,以防在时间用完之前用完所有的词)。
再次感谢。