web-dev-qa-db-ja.com

「ピン」演算子とは何ですか?Elixir変数は変更可能ですか?

現在、Elixirの「^」演算子を理解しようとしています。ウェブサイトから:

Pin演算子^は、変数を再バインドする必要がなく、一致する前の値と照合する場合に使用できます。

ソース- http://elixir-lang.org/getting_started/4.html

これを念頭に置いて、次のようにシンボルに新しい値をアタッチできます。

iex> x = 1  # Outputs "1"
iex> x = 2  # Outputs "2"

私もできます:

iex> x = x + 1  # Outputs "3"!

だから私の最初の質問は; Elixir変数は変更可能ですか?それは確かにそうであるように見えます...関数型プログラミング言語ではそれが可能ではないでしょうか?

それでは、「^」演算子に行きます...

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」をそれにバインドされている最後の値にロックすることです。それで全部ですか?すべての「一致」/割り当てがErlang自体のように不変であることを確認しないでください。

慣れてきました...

40
Charlie

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.

エリクサーでは、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]
57
tkowal

Elixirのデータは不変ですが、変数は再割り当て可能です。エリクサーを少し混乱させるのは、表示されている割り当てとパターンマッチングの組み合わせです。

左側のエリクサーに変数参照がある等号を使用すると、最初に構造とパターンが一致し、次に割り当てが実行されます。左側に唯一の変数参照がある場合、それは任意の構造に一致するため、次のように割り当てられます。

 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's previous value

変数の内容に対して値を一致させたい場合は、ピン '^'を使用できます。

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)**

これらの単純な例では、ピンマッチングとパターンマッチングの使用はすぐには価値がありませんが、エリクサーを学び、パターンマッチングを開始するにつれて、エリクサーが提供する表現力の一部になります。

25
greggreg