Elixirでは、関数は第一級オブジェクトとして扱われます。つまり、次のようなことができます。
無名関数は、名前付き関数とは異なり、静的な参照を持ちません。変数に代入するか、その場で呼び出す場合にのみ利用できます。
無名関数は、次のような場面で使うことがあります。
無名関数は予約語fnで始まり、引数は->トークンで関数の本体と区切られ、endで終わります。名前付き関数と同じく、関数内の最後の式は、呼び出し元に_暗黙的に返され_ ます。
関数の参照を呼び出すには、参照を保持する変数と引数のリストの間に.を書く必要があります。
function_variable = fn param ->
param + 1
end
function_variable.(1)
# => 2
さらに、省略記法のキャプチャ構文を使うと、もっと簡潔に書くこともできます。
variable = &(&1 + 1)
variable.(1)
# => 2
Elixirには、ビットを扱うための多くの関数が用意されており、それらは_Bitwise_モジュールにあります。
band/2: ビット単位のANDbsl/2: ビット単位の左シフトbsr/2: ビット単位の右シフトbxor/2: ビット単位のXORbor/2: ビット単位のORbnot/1: ビット単位のNOTビット演算の関数を使う例を次に示します。
Bitwise.bsl(1, 3)
# => 8
ビット演算の関数は、すべて整数に対してのみ動作します。
Elixirのバージョン1.9以前を使っている場合は、_Bitwise_モジュールを利用するために、モジュール定義の先頭でrequire Bitwiseを呼び出す必要があります。
この演習では、データを変換することで動作する暗号化デバイスのソフトウェアを書くという課題に取り組みます。より単純な関数を組み合わせて複雑な関数を柔軟に作る方法が必要です。
各タスクでは、呼び出し元のスコープから呼び出せる無名関数を返します。
どの関数も整数の引数を取るものとします。また、Elixirでビット演算を行う場合にも整数が適しています。
Secrets.secret_add/1を実装します。これは、1つの引数を取り、それにsecret_addへ渡された引数を加算する関数を返します。
adder = Secrets.secret_add(3)
adder.(2)
# => 5
Secrets.secret_subtract/1を実装します。これは、1つの引数を取り、その引数からsecret_subtractへ渡された秘密の値を引く関数を返します。
subtractor = Secrets.secret_subtract(2)
subtractor.(3)
# => 1
Secrets.secret_multiply/1を実装します。これは、1つの引数を取り、それにsecret_multiplyへ渡された秘密の値を掛ける関数を返します。
multiplier = Secrets.secret_multiply(7)
multiplier.(3)
# => 21
Secrets.secret_divide/1を実装します。これは、1つの引数を取り、それをsecret_divideへ渡された秘密の値で割る関数を返します。
divider = Secrets.secret_divide(3)
divider.(32)
# => 10
出力が他の関数の期待する入力と互換になるように、整数除算を利用します。
Secrets.secret_and/1を実装します。これは、1つの引数を取り、その引数とsecret_andへ渡された秘密の値に対してビット単位の_and_演算を行う関数を返します。
ander = Secrets.secret_and(1)
ander.(2)
# => 0
Secrets.secret_xor/1を実装します。これは、1つの引数を取り、その引数とsecret_xorへ渡された秘密の値に対してビット単位の_xor_演算を行う関数を返します。
xorer = Secrets.secret_xor(1)
xorer.(3)
# => 2
Secrets.secret_combine/2を実装します。これは、1つの引数を取り、secret_combineへ渡された2つの関数を順番にその引数へ適用する関数を返します。
add_one = Secrets.secret_add(1)
multiply_by_2 = Secrets.secret_multiply(2)
combined = Secrets.secret_combine(add_one, multiply_by_2)
combined.(3)
# => 8