実際、この質問は表面的に見えるよりも微妙であり、実際に適切に答えるには、コンパイラの内部について少し学ぶ必要があります。その理由は、入れ子になったパターンや複数の用語にまたがるパターンを持つことができることを当然のことと考えているからです。実際には、コンパイラの目的で唯一できることは、単一の最上位コンストラクターで分岐することだけです。価値。したがって、コンパイラの最初の段階では、ネストされたパターン (および複数の値にまたがるパターン) をより単純なパターンに変換します。たとえば、単純なアルゴリズムは、関数を次のように変換する可能性があります。
myFunc = \x y -> case x of
0 -> case y of
0 -> 0
_ -> x `someoperation` y
1 -> case y of
1 -> 1
_ -> x `someoperation` y
_ -> x `someoperation` y
ここには最適ではないものがたくさんあることがすでにわかります。someoperation
項は何度も繰り返されており、関数は a を実行し始める前に両方の引数を想定していcase
ます。これを改善する方法については、有限オートマトン理論に触発された用語パターン マッチ コンパイラを参照してください。
とにかく、この形式では、実際にはカリー化ステップがどのように行われるかがもう少し明確になるはずです。x
この式でfor を直接代入して、何をmyFunc 0
行うかを確認できます。
myFunc 0 = \y -> case 0 of
0 -> case y of
0 -> 0
_ -> 0 `someoperation` y
1 -> case y of
1 -> 1
_ -> 0 `someoperation` y
_ -> 0 `someoperation` y
これはまだラムダであるため、それ以上の削減は行われません。十分にスマートなコンパイラがもう少し多くのことを行うことを望むかもしれませんが、GHC は明示的にそれ以上のことを行いません。引数を 1 つだけ指定した後でさらに計算を実行したい場合は、定義を変更する必要があります。(ここには時間/空間のトレードオフがあり、正しく選択することは確実に行うには難しすぎます。したがって、GHC はプログラマーの手にこの選択を任せます。) たとえば、明示的に次のように書くことができます。
myFunc 0 = \y -> case y of
0 -> 0
_ -> 0 `someoperation` y
myFunc 1 = \y -> case y of
1 -> 1
_ -> 1 `someoperation` y
myFunc x = \y -> x `someoperation` y
そしてmyFunc 0
、はるかに小さな式に縮小されます。