Erlang中的函数相等性和排序

10

在 Erlang 中,使用运算符 =:=,==,<,>,=<,>= 来比较函数意味着什么?我在解释器中尝试了一些操作,并得到了以下结果:

Eshell V5.9.2  (abort with ^G)
1> X = fun() -> {} end.
#Fun<erl_eval.20.82930912>
2> Y = fun() -> {} end.
#Fun<erl_eval.20.82930912>
3> 
3> {X == X, X =:= X}.
{true,true}
4> {X >= X, X =< X}.
{true,true}
5> {X > X, X < X}.
{false,false}
6> 
6> {X == Y, X =:= Y}.
{true,true}
7> {X >= Y, X =< Y}.
{true,true}
8> {X > Y, X < Y}.
{false,false}

这很有道理。它似乎在比较这两个函数的抽象语法树。

但在这个会话中,XY再次被定义为相同的内容,但实际上是不同的,现在X<Y了吗?

Eshell V5.9.2  (abort with ^G)
1> X = fun() -> {} end.
#Fun<erl_eval.20.82930912>
2> 
2> {X == X, X =:= X}.
{true,true}
3> {X >= X, X =< X}.
{true,true}
4> {X > X, X < X}.
{false,false}
5> 
5> Y = fun() -> {} end.
#Fun<erl_eval.20.82930912>
6> 
6> {X == Y, X =:= Y}.
{false,false}
7> {X >= Y, X =< Y}.
{false,true}
8> {X > Y, X < Y}.
{false,true}

看起来它并没有比较AST任何独特的引用。也许它正在比较引用,只是发生了一些优化,并且XY被绑定到同一个引用上?如果有一些解释,那么在不同的VM或不同的节点中会发生什么呢?


1
在Erlang R15B01上,我在6>中得到了{true, true} - Roberto Aloi
R15B02 在这里也得到了 {true, true},在 6> - halfelf
在 R14B02 版本中,第 6 行也是 {true,true} - Tilman
2个回答

4
在shell中,两种求值方式的区别在于第6行的空白行。如果您查看使用函数erlang:fun_info/1的fun,您将看到在该情况下,子句存储了一个不同的数字(即2而不是1)。
如果您再次输入Y的定义(没有空白行),则会出现匹配错误;如果在之前输入一个空白行,则可以正常运行。
我认为这是使用shell的副作用,但行为在程序内是一致的。当然,对于fun来说,>或<的含义并不明显,但==是可以的。还有一个好处是Erlang术语的顺序已经定义,因此可以对任何术语的列表进行排序,并具有可预测的行为:
number < atom < reference < fun < port < pid < tuple < list < bit string

我猜==仅在比较数字时有用。 - halfelf
3
@halfelf 不,==可以用来比较任何东西。你只需要知道比较的语义。我不会认真地比较函数,因为“相等”的函数有太多的方式是不相等的。例如,如果你期望它比较 AST,则要注意 AST 包含行号。 - rvirding

1
这种行为在shell和编译模块中是不同的。至于模块中的===:=运算符,我很确定只有当以下条件成立时才返回true
  • 两个函数在代码中定义的位置相同(在shell中并非如此!)
  • 它们的有效闭包根据相应的(==/=:=)运算符相等。

例如:

test(A, B) ->
  fun(C) -> {A, C} end.

以下内容应当适用:
> test(1, x) == test(1, y).
true.
> test(1, x) =:= test(1, y).
true.
> test(1, x) == test(1.0, y).
true.
> test(1, x) =:= test(1.0, y).
false.

请注意,B不属于内部函数的闭包,因此不会影响比较结果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接