Все, что я читал об Эликсире, говорит о том, что присваивание следует рассматривать как сопоставление с образцом. Если да, то почему x = x + 1 работает в Эликсире? Не существует значения х, для которого х = х + 1.


Во время сопоставления с образцом ценности справа от совпадения равны назначенный их совпадающему переменные слева:
iex(1)> {x, y} = {1, 2}
{1, 2}
iex(2)> x
1
iex(3)> y
2
С правой стороны используются значения переменных до совпадения. Слева установлены переменные.
Вы также можете заставить левую сторону использовать значение переменной с помощью ^ контактный оператор:
iex(4)> x = 1
1
iex(5)> ^x = x + 1
** (MatchError) no match of right hand side value: 2
Это не удается, потому что это эквивалентно 1 = 1 + 1, что является условием отказа, которое вы ожидали.
Everything I've read about Elixir says that assignment should be thought of as pattern matching.
В Elixir =является вызывает оператор сопоставления с образцом, но он работает не так, как оператор сопоставления с образцом в Erlang. Это потому, что переменные в Эликсире не являются одиночными присваиваниями, как в Эрланге. Вот как работает Erlang:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> X = 15.
15
2> X = 100.
** exception error: no match of right hand side value 100
3> X.
15
4>
Следовательно, в Erlang это не работает:
4> X = X + 1.
** exception error: no match of right hand side value 16
С единичным присваиванием в Erlang все довольно просто: поскольку у X уже есть значение, строка X = X + 1 не может быть попыткой присвоить X новое значение, поэтому эта строка является попыткой сопоставления с образцом (15 = 15 + 1), которая всегда терпит неудачу.
С другой стороны, в Эликсире переменные не имеют одинарного присваивания:
Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> x = 15
15
iex(2)> x = 100
100
iex(3)> x
100
iex(4)>
Тот факт, что переменные не являются одиночными присваиваниями в Эликсире, означает, что Эликсиру нужно сделать выбор, когда вы пишете:
x = 10
x = x + 1 #or even x = 15
Вариант 1) Следует ли интерпретировать вторую строку как присвоение x?
Вариант 2. Следует ли интерпретировать вторую строку как попытку сопоставления с образцом (т. е. 10 = 11)?
Эликсир идет с Вариантом 1. Это означает, что на самом деле выполнить сопоставление шаблона с так называемым оператором сопоставления шаблонов в Эликсире сложнее: вы должны использовать оператор булавки (^) в сочетании с оператором сопоставления (=):
x = 10
^x = x + 1
Теперь вторая линия всегда будет терпеть неудачу. Существует также трюк, который будет работать в некоторых ситуациях, если вы хотите выполнить сопоставление с образцом без использования оператора вывода:
x = 10
12 = x
Во второй строке вы помещаете переменную справа. Я думаю, что правило можно сформулировать так: в правой части оператора сопоставления с образцом (=) переменные всегда оцениваются, т. е. заменяются их значениями. В левой части переменные всегда присваиваются, если только не используется оператор закрепления, в этом случае закрепленная переменная заменяется ее текущим значением, а затем шаблон сопоставляется с правой стороной. В результате, вероятно, правильнее будет называть оператор Эликсира = гибридным оператором присваивания/сопоставления с образцом.
Вы можете представить, что x = x + 1 переписывается компилятором во что-то вроде x2 = x1 + 1.
Это очень близко к тому, как это работает. Это не просто порядковый номер, как я использовал здесь, но концепция та же. Переменные, видимые BEAM, неизменяемы, и на этом уровне не происходит повторного связывания.
В программах на Erlang вы повсюду найдете код, похожий на X2 = X1 + 1. У обоих подходов есть недостатки. Хосе Валим сделал сознательный выбор, разрешив повторное связывание переменных, когда разрабатывал Эликсир, и он написал сообщение в блоге, в котором сравнил два подхода и различные ошибки, с которыми вы рискуете:
http://blog.plataformatec.com.br/2016/01/comparing-elixir-and-erlang-variables/
Потому что Эликсир полностью упускает суть. Вместо этого используйте Erlang везде, где это возможно. Гораздо меньше путаницы.