等式推論1と抽象化を適用します。あなたが持っている
one f x = f x -- :: (a -> b) -> a -> b
two f x = f (f x) -- = f (one f x) -- :: (a -> a) -> a -> a
three f x = f (f (f x)) -- = f (two f x) -- :: (a -> a) -> a -> a
-- ~~~~~~~~~~~
したがって、後続関数next
が自然に定義されるため、three = next two
. はい、上の式のnext two
代わりに書くのと同じくらい簡単です。three
next :: ((b -> c) -> a -> b) -> (b -> c) -> a -> c
-- three f x = next two f x = f (two f x) -- `two` is a formal parameter
-- ~~~~~~~~~~~
next num f x = f (num f x) -- generic name `num`
zero :: t -> a -> a
zero f x = x
これは、継承のパターンをキャプチャします。後続関数として、およびゼロ値としてf
使用されます。残りは次のとおりです。例えば、x
plus :: (t -> b -> c) -> (t -> a -> b) -> t -> a -> c
plus two one f x = two f (one f x) -- formal parameters two, one
-- = f (f (one f x)) -- an example substitution
-- = f (f (f x) -- uses the global definitions
-- = three f x -- for one, two, three
つまり、 (「通常の」の代わりに)one f x
によってゼロ値として使用されるため、 を表します。「数」はn回の操作の連続を表します。two
x
three
n
+1
上記でも、 と は 2 つの正式な関数パラメーターにすぎないため、実際には一般的な操作を定義していますplus
。two
one
Prelude> plus three two succ 0 -- built-in `succ :: Enum a => a -> a`
5
Prelude> :t plus three two
plus three two :: (a -> a) -> a -> a
Prelude> plus three two (1:) [0]
[1,1,1,1,1,0]
ここで重要なことは、関数は呼び出されたときに値を生成するオブジェクトであるということです。それ自体は不透明なオブジェクトです。それに適用する「オブザーバー」引数は、ゼロであることの「意味」を提供するか、後続の値を見つけることを意味し、数値の値を観察したときにどのような結果が生成されるかを定義します。
1つまり、任意の式で LHS を定義の RHS に、または RHS を LHS に自由に置き換えます (もちろん、既存の自由変数をキャプチャ/シャドーしないように、変数の名前を変更するまで)。