2015-09-26 3 views
2

Недавно я начал изучать Erlang, исходя из императивного фона вещи несколько иначе ...Почему это выражение не сбрасывает переменную?

я делаю хорошо (обучение Erlang), пока я не наткнулся на что-то я не понял, работая в Eshell, может кто-нибудь объяснить мне что происходит?

17> One. 
1 
18> One = 1. 
1 
19> true andalso f(One). 
ok 
20> One. 
1 

Почему One по-прежнему связан со значением? Так как правая часть выражения была действительно оценена. Теперь, если я использую f() в одиночку, все работает, как ожидалось

21> f(One). 
ok 
22> One. 
* 1: variable 'One' is unbound 

Почему?

+0

Посмотрите это: http://erlang.org/doc/reference_manual/expressions.html#id81160 –

+0

@Atomic_alarm, что именно? ... это на самом деле моя точка, второе выражение было оценено, я знаю это, потому что оно вернуло 'ok', но переменная не была несвязана. я что-то упускаю? – yeyo

ответ

4

Предполагая, что не существует какая-либо текущая переменная привязки, команда

1> One = 1. 

добавляет привязку для One по телефону erl_eval:add_binding('One',1,[]), где последний аргумент является списком существующих привязок. Затем привязки [{'One',1}].

Далее мы запускаем andalso выражение:

2> true andalso f(One). 
ok 
3> b(). 
One = 1 
ok 

Что происходит для этой команды является то, что, когда true получает оценку, переплеты являются [{One,1}]. Так как true делает левую сторону andalso успешной, правая сторона затем оценивается, также с привязками [{One,1}], а команда f(One) приводит к вызову erl_eval:del_binding('One',[{'One',1}]), изменяя привязки только для правого сторона до пустого списка []. Результатом этой части выражения, ok, становится общий результат из-за того, как работает andalso. Как только этот результат будет доступен, привязки для правой стороны будут отброшены, потому что все, что необходимо, является результатом. Исходные привязки все еще вокруг из-за левой стороны, и эти привязки остаются в силе. Последующая команда b() для отображения привязок, следовательно, по-прежнему показывает One = 1.

Очень похожий эффект происходит, если вы запустите это:

4> true andalso (Two = 2). 
2 
5> b(). 
One = 1 
ok 

Вторая часть andalso, (Two = 2), добавляет привязку для Two только креплениями для той части оценки. Результат, 2, сохраняется, но привязки для этой части отбрасываются, и только привязки для левой половины остаются в силе. Когда мы снова запустим b(), чтобы увидеть все привязки, мы по-прежнему видим только One = 1.

+0

Хорошо, я понимаю, большое спасибо. Но что происходит? Я имею в виду, вы сказали: «Оригинальные привязки все еще вокруг из-за левой стороны», что это значит? вы имеете в виду, что Erlang создает другую область только для булевых выражений? Кроме того, эта логика применяется вне оболочки? – yeyo

+2

Во-первых, это происходит только в оболочке, так как 'f' является специфичной для оболочки функцией, и если вы попытаетесь скомпилировать мой второй пример (содержащий' Two = 2'), компилятор завершится с ошибкой 'variable 'Two' unsafe в 'andalso'', что означает, что не все ветви выражения, установленные «Два». Erlang не создает новую область для булевых выражений; скорее, когда оболочка оценивает выражения, она переносит привязки переменных для этих выражений, и в этом случае привязки для правой части 'andalso' отбрасываются после ее оценки, в то время как для левой стороны сохраняются. Я думаю, что это ошибка оболочки. –

+2

Возможно, это ошибка в 'erl_eval'. [Его код для обработки andalso] (https://github.com/erlang/otp/blob/maint/lib/stdlib/src/erl_eval.erl#L448-L457) показывает, как привязки для оценки второй части 'andalso 'отбрасываются (строка 452), и сохраняются только те, для первой части. Если привязки для части 2 вместо этого сохраняются и объединены с «Bs1» в строке 457, то мой пример «true andalso (Two = 2)» приводит к добавленной привязке в оболочке для «Two», но она все еще не имеет значения, t исправить исходный случай с участием 'f (One)'. Я думаю, что для этой оболочки потребуется дополнительная специальная обработка. –

Смежные вопросы