Подтвердить что ты не робот

Что такое оператор "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" до последнего привязанного к нему значения. Это все? Почему бы просто не обеспечить, чтобы все "совпадения" /назначения были неизменными, как сам Эрланг?

Я просто привык к этому...

4b9b3361

Ответ 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)**

В этих простых примерах использование совпадения штырей и шаблонов не является сразу очень ценным, но поскольку вы узнаете больше эликсира и начинаете шаблон, все больше и больше становится частью выразительности, которую дает эликсир.