为什么shell中这两个erlang表达式序列的输出不同?
在Erlang
shell中为什么以下产生不同的结果?
1> Total=15. 2> Calculate=fun(Number)-> Total=2*Number end. 3> Calculate(6). 异常错误:右侧值12不匹配 1> Calculate=fun(Number)-> Total=2*Number end. 2> Total=15. 3> Calculate(6). 12 解决方法
在Erlang中,=运算符既是赋值也是断言.
如果我这样做: A = 1,A = 2, 我的程序会崩溃.我刚刚告诉它A = 1,当A未绑定(尚未作为标签存在)时,它现在永远被赋予值1 – 直到执行范围发生变化.那么当我告诉它A = 2时,它试图断言A的值是2,而不是.所以我们在糟糕的比赛中遇到了崩溃. Erlang中的范围由两件事来定义: >当前功能的定义.此范围在函数定义的持续时间内是绝对的. 这些范围在它们被外部范围内的任何内容声明时总是被取代.这就是我们用匿名函数创建闭包的方法.例如,假设我有一个套接字我想通过发送数据列表.套接字已绑定到函数头部的变量名Socket,我们希望使用列表操作映射值列表以发送到通过该特定套接字发送的副作用.我可以在lambda体内关闭套接字的值,这样可以将“发送一些数据”的更一般操作中的值调整为: send_stuff(Socket,ListOfMessages) -> Send = fun(Message) -> ok = gen_tcp:send(Socket,Message) end,lists:foreach(Send,ListOfMessages). 列表操作列表的每次迭代:foreach / 2只能接受arity 1的函数作为其第一个参数.我们已经创建了一个闭包,它已经在内部捕获了Socket的值(因为它已经绑定在外部作用域中)并将它与未绑定的内部变量Message结合起来.另请注意,我们通过断言gen_tcp:send / 2的返回值确实正常,检查gen_tcp:send / 2是否每次都在lambda中工作. 这是一个非常有用的属性. 所以考虑到这一点,让我们来看看你的代码: 1> Total = 15. 2> Calculate = fun(Number)-> Total = 2 * Number end. 3> Calculate(6). 在上面的代码中,您刚刚为Total分配了一个值,这意味着您已为该值创建了一个标签(就像我们在上面的例子中指定了Socket一样).然后你断言Total的值是2 * Number可能的结果 – 由于Total是一个整数所以永远不会是真的所以2 * 7.5也不会削减它,因为结果将是15.0,不是15. 1> Calculate = fun(Number)-> Total = 2 * Number end. 2> Total = 15. 3> Calculate(6). 但是,在这个例子中,你有一个名为Total的内部变量,它不会关闭外部作用域中声明的任何值.稍后,您在外部作用域中声明了一个名为Total的标签,但此时第一行上的lambda定义已转换为抽象函数,并且在此处使用的标签Total已完全转换为不可变空间.新函数定义对Calculate的赋值表示.因此,没有冲突. 考虑一下会发生什么,例如,尝试从列表推导中引用内部值: 1> A = 2. 2 2> [A * B || B <- lists:seq(1,3)]. [2,4,6] 3> A. 2 4> B. * 1: variable 'B' is unbound 这不是你所期望的,比方说,Python 2: >>> a = 2 >>> a 2 >>> [a * b for b in range(1,4)] [2,6] >>> b 3 顺便说一句,这已在Python 3中修复: >>> a = 2 >>> a 2 >>> [a * b for b in range(1,6] >>> b Traceback (most recent call last): File "<stdin>",line 1,in <module> NameError: name 'b' is not defined (我会提供一个JavaScript示例进行比较,但是那里的范围规则是如此绝对疯狂,甚至不重要……) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |