gpt4 book ai didi

erlang - 为什么shell中这两个erlang表达式序列的输出不同?

转载 作者:行者123 更新时间:2023-12-04 17:15:55 25 4
gpt4 key购买 nike

在 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是未绑定(bind)的(尚不作为标签存在),它现在被永远赋值为 1 - 直到执行范围发生变化。那么当我告诉它 A = 2它试图断言 A 的值是 2,它不是。所以我们在一场糟糕的比赛中崩溃了。

Erlang 中的作用域由两件事定义:
  • 当前函数的定义。此范围在函数定义期间是绝对的。
  • 当前 lambda 或列表理解的定义。此范围是 lambda 的本地范围,但也会关闭外部范围中引用的任何值。

  • 这些作用域总是在它们被外部作用域中的任何东西声明时被取代。这就是我们使用匿名函数创建闭包的方式。例如,假设我有一个要发送数据列表的套接字。套接字已经绑定(bind)到变量名 Socket在函数的头部,我们想使用列表操作将要发送的值列表映射到通过该特定套接字发送的副作用。我可以关闭 lambda 主体内的套接字值,这具有将该值从“发送一些数据”的更一般操作中删除的效果:
    send_stuff(Socket, ListOfMessages) ->
    Send = fun(Message) -> ok = gen_tcp:send(Socket, Message) end,
    lists:foreach(Send, ListOfMessages).

    列表操作的每次迭代 lists:foreach/2只能接受 arity 1 的函数作为其第一个参数。我们创建了一个捕获 Socket 值的闭包。已经在内部(因为它已经绑定(bind)在外部范围内)并将其与未绑定(bind)的内部变量 Message 结合.另请注意,我们正在检查 gen_tcp:send/2通过断言 gen_tcp:send/2 的返回值每次在 lambda 中工作真的是 ok .

    这是一个 super 有用的属性。

    因此,考虑到这一点,让我们看看您的代码:
    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, 4, 6]
    >>> b
    3

    顺便说一句,这已在 Python 3 中修复:
    >>> a = 2                                                                                                                                                                                                                                                                    
    >>> a
    2
    >>> [a * b for b in range(1,4)]
    [2, 4, 6]
    >>> b
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    NameError: name 'b' is not defined

    (我也会提供一个 JavaScript 示例进行比较,但是那里的范围规则绝对是疯狂的,它甚至都没有关系......)

    关于erlang - 为什么shell中这两个erlang表达式序列的输出不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46583932/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com