2016-06-24 4 views
2

Я не понимаю, что именно означает равный знак в Эликсире. Непонятно, что это похоже на сочетание между назначением и операцией сопоставления шаблонов.Каково точное значение знака равенства в Эликсире?

iex(1)> x=4 
4 
iex(2)> y=5 
5 
iex(3)> 3=y 
** (MatchError) no match of right hand side value: 5 

iex(3)> y=3 
3 
iex(4)> y=x 
4 

Я понимаю, что в эликсире, то равно оператор означает, в соответствии с левой стороны знака = на правую сторону. Первые две строки имеют смысл для меня. x и y - несвязанные переменные, поэтому они могут соответствовать любому. Они связаны друг с другом. Следовательно, я понимаю третью строку. Вы не можете сопоставить 3 с 5.

Где я начинаю размахивать головой, почему, черт возьми, две последние строки выполнены без такой же ошибки. Похоже, что знак равенства возвращается только к оператору присваивания.

Я пытаюсь принять это поведение как факт без полного понимания и попытался пойти дальше в изучении языка. Но поскольку сопоставление образцов является одним из основных механизмов Elixir, я постоянно блокируюсь и чувствую, что должен вернуться к этому оригинальному вопросу. Я больше не пойду, прежде чем я полностью пойму, что именно происходит с знаком «=» и какова логика.

+0

http://elixir-lang.org/getting-started/pattern-matching.html#the-pin-operator – AbM

ответ

4

знак равенства означает: «пытаются втиснуть значение выраженияна праве на форме на левой и присвоения значений соответствующим образом». Таким образом, левая и правая стороны разные, и вы не можете их переключать. С правой стороны все переменные должны быть связаны, потому что это выражение. С левой стороны, даже если вы используете переменные, которые уже связаны, они будут переназначены.

Так первая вещь в том, что на правой стороне вы можете иметь любое выражение ваше хотение:

{:error, :enoent} = File.open("foo") 

, но вы не можете иметь выражение на левой стороне:

iex(1)> File.open("foo") = {:error, :enoent} 
** (CompileError) iex:1: cannot invoke remote function File.open/1 inside match 

В случае

y=3 
5=y # y gets evaluated to 3 and then you pattern match 3=5 

и он не работает.Но вы можете сделать

y=3 
y=5 # y gets reassigned. 

На левой стороне вы можете иметь только «форму», которая может быть arbitrarly вложенной структуры данных:

[a, b, %{"a" => {1, c}}] = [1, 2, %{"a" => {1, 2}] 
# c is now assigned value of 2 

Так соответствующий шаблон используется для либо данных destructure или утверждать некоторые состояние как

case File.open("foo") do 
    {:ok, contents} -> enjoy_the_file(contents) 
    {:error, reason} -> print_error(reason) 
end 

или если вы хотите, чтобы утверждать, что существует только один объект в базе данных вместо того, чтобы, во-первых, утверждая, что существует и то, что есть только один вы можете PATT Эрн матч:

[entity] = Repo.all(query) 

Если вы хотите, чтобы утверждать, что первое значение в списке один, вы можете шаблон матча:

[1 | rest] = [1, 2, 3] 

Есть несколько подводных камней при сопоставлении с образцом. Например это:

%{} = %{a: "a"} 

будет соответствовать, потому что форма на левой стороне карты и не требует ничего более, любая карта будет соответствовать. Однако это не будет соответствовать:

%{a: "a"} = %{} 

, потому что форма слева говорит «дайте мне карту с ключом атома :a

Если вы хотите, чтобы соответствовать на переменную вы можете написать что-то подобное. это:

a = 1 
{a, b} = {2, 3} 

, но это будет назначать a значение 2.Вместо этого вам нужно использовать пин-оператор:

a = 1 
{^a, b} = {2, 3} #match fails 

я написал больше о операторе контактного в этом ответе: What is the "pin" operator for, and are Elixir variables mutable?

+0

В gotchas также может быть полезно указать, что в то время как '% {} =% {a:: b}' будет соответствовать, '[] = [: a,: b]' не будет соответствовать. Но это может выходить за рамки вашего ответа. ¯ \ _ (ツ) _/¯ –

+0

Спасибо за подробное объяснение. Мне нравится метафор формы и выражения, который делает вещи немного яснее для меня. Я также нашел этот https://bordeltabernacle.github.io/2015/12/31/notes-on-elixir-pattern-matching.html, который помог мне продвинуться дальше. – Melicerte

+0

Из вышеупомянутого поста, особенно эта цитата от Джо Амстронга, создателя Эрланга, что знак равенства работает более сродни символу = в алгебре (подумайте о x +5 = 10). – Melicerte

3

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

Это потому, что имя переменной на левой стороне не соответствует его значению в эликсира. Вместо этого переменная переназначается с соответствующим значением с правой стороны.

Это отличается от Erlang, где именно то, что вы ожидаете, произойдет:

1> X = 4. 
4 
2> Y = 5. 
5 
3> 3 = Y. 
** exception error: no match of right hand side value 5 
4> Y = 3. 
** exception error: no match of right hand side value 3 
5> Y = X. 
** exception error: no match of right hand side value 4 

Чтобы получить такое же поведение в эликсира, вам нужно использовать «контактный» оператор по каждой переменной, которую вы хотите, чтобы соответствовать по значению на левая сторона:

iex(1)> x = 4 
4 
iex(2)> y = 5 
5 
iex(3)> 3 = y 
** (MatchError) no match of right hand side value: 5 

iex(3)> ^y = 3 
** (MatchError) no match of right hand side value: 3 

iex(3)> ^y = x 
** (MatchError) no match of right hand side value: 4 
+0

Таким образом, оператор контактный заставить знак равенства быть оператор совпадения. Без штифта это совпадение и назначение. правильно ? – Melicerte

0

два случая:

1) Left hand side является заполнителя/переменной :

  • Независимо в правом получит назначен

Пример:

x = 5 
y = x (y gets value 5) 
x = y (x gets value 5) 

2) Left hand side является значение

  • Совпадение со значением в правильное значение руки/переменной

Пример:

5 = x (Error: as x is undefined) 
x = 5 
5 = x (5 matches with 5) 
6 = x (Error: 6 is not matches with 5) 
Смежные вопросы