Что такое оператор "pin", и являются ли переменные Elixir изменчивыми?
В настоящее время пытается понять оператор "^" в Эликсире.
На веб-сайте:
Оператор булавки ^ может использоваться, когда нет интереса к переплетению переменная, а скорее соответствует ее значению до матч:
Источник - http://elixir-lang.org/getting_started/4.html
С учетом этого вы можете прикрепить новое значение к символу так:
iex> x = 1 # Outputs "1"
iex> x = 2 # Outputs "2"
Я также могу сделать:
iex> x = x + 1 # Outputs "3"!
Итак, мой первый вопрос; Изменены ли переменные Эликсира?
Это, конечно, похоже, если это так... Не должно ли это быть возможным на функциональном языке программирования?
Итак, теперь мы приходим к оператору "^" ...
iex> x = 1 # Outputs "1"
iex> x = 2 # Outputs "2"
iex> x = 1 # Outputs "1"
iex> ^x = 2 # "MatchError"
iex> ^x = 1 # Outputs "1"
Я думаю, что эффект "^" заключается в том, чтобы зафиксировать "x" до последнего привязанного к нему значения. Это все?
Почему бы просто не обеспечить, чтобы все "совпадения" /назначения были неизменными, как сам Эрланг?
Я просто привык к этому...
Ответы
Ответ 1
Данные в Elixir по-прежнему неизменяемы, но есть несколько сокращений, которые позволяют вам вводить меньше или не беспокоиться о поиске новых имен. В Erlang вы часто можете увидеть код следующим образом:
SortedList = sort(List),
FilteredList = filter(SortedList),
List3 = do_something_with(FilteredList),
List4 = another_thing_with(List3)
В Elixir вы можете просто написать:
list = sort(list)
list = filter(list)
list = do_something_with(list)
list = another_thing_with(list)
Это точно то же самое, но выглядит немного лучше. Конечно, лучшим решением было бы написать вот так:
list |> sort |> filter |> do_something |> another_thing_with
Каждый раз, когда вы назначаете новую вещь переменной list
, вы получаете новый экземпляр:
iex(1)> a = 1
1
iex(2)> b = [a, 2]
[1, 2]
iex(3)> a = 2
2
iex(4)> b
[1, 2] # first a did not change, it is immutable, currently a just points to something else
Вы просто говорите, что вас больше не интересует старый a
, и пусть он указывает на что-то еще. Если вы исходите из фона Erlang, вы, вероятно, знаете функцию f
из оболочки.
A = 1.
f(A).
A = 2.
В Elixir вам просто не нужно писать f
. Это делается автоматически для вас. Это означает, что каждый раз у вас есть переменная с левой стороны совпадения с шаблоном, вы присваиваете ей новое значение.
Без оператора ^
вы не сможете иметь переменную в левой части шаблона, потому что она получит новое значение с правой стороны. ^
означает, что вы не присваиваете новую информацию этой переменной - рассматривайте ее как литеральное значение.
Вот почему в Эликсире
x = 1
[1, x, 3] = [1, 2, 3]
эквивалентен в Erlang для:
X = 1,
[1, CompletelyNewVariableName, 3] = [1, 2, 3]
и
x = 1
[1, ^x, 3] = [1, 2, 3]
эквивалентно:
x = 1
[1, 1, 3] = [1, 2, 3]
который в Erlang:
X = 1,
[1, X, 3] = [1, 2, 3]
Ответ 2
Данные в эликсире неизменяемы, переменные, однако, переустанавливаются. Что может сделать эликсир немного запутанным, это комбинированное присваивание и сопоставление шаблонов, которые вы видите.
Когда вы используете знак равенства с ссылкой на переменную в левом элексире, первый шаблон будет соответствовать структуре, а затем выполнить присвоение. Если у вас есть единственная ссылка для переменной слева, она будет соответствовать любой структуре и поэтому будет назначена так:
a = 1 # 'a' now equals 1
a = [1,2,3,4] # 'a' now equals [1,2,3,4]
a = %{:what => "ever"} # 'a' now equals %{:what => "ever"}
Если у вас более сложная структура на левом элексире, первый шаблон будет соответствовать структурам, а затем выполнить назначение.
[1, a, 3] = [1,2,3]
# 'a' now equals 2 because the structures match
[1, a] = [1,2,3]
# **(MatchError)** because the structures are incongruent.
# 'a' still equals it previous value
Если вы хотите оценить совпадение с содержимым переменной, вы можете использовать pin '^':
a = [1,2] # 'a' now equals [1,2]
%{:key => ^a} = %{:key => [1,2]} # pattern match successful, a still equals [1,2]
%{:key => ^a} = %{:key => [3,4]} # **(MatchError)**
Этот надуманный пример также мог быть написан с "a" с правой стороны и без вывода:
%{:key => [1,2]} = %{:key => a}
Теперь скажите, что вы хотите назначить переменную частичной структуре, но только если часть этой структуры соответствует чему-то, хранящемуся в 'a', в elixir это тривиально:
a = %{:from => "greg"}
[message, ^a] = ["Hello", %{:from => "greg"}] # 'message' equals "Hello"
[message, ^a] = ["Hello", %{:from => "notgreg"}] # **(MatchError)**
В этих простых примерах использование совпадения штырей и шаблонов не является сразу очень ценным, но поскольку вы узнаете больше эликсира и начинаете шаблон, все больше и больше становится частью выразительности, которую дает эликсир.