自然数の高階関数としての表現
数学 において 、 チャーチ符号化は、 ラムダ計算 でデータと演算子を表現する手段です 。 チャーチ数字は、ラムダ表記法を使用して自然数を表します。この方法は、ラムダ計算でこの方法で初めてデータを符号化した アロンゾ・チャーチ にちなんで名付けられました 。
他の表記法では通常プリミティブと見なされる用語 (整数、ブール値、ペア、リスト、タグ付き共用体など) は、チャーチ符号化では 高階関数 にマッピングされます。 チャーチ-チューリングのテーゼは 、計算可能な演算子 (およびそのオペランド) はどれもチャーチ符号化で表現できると主張しています。 [ 疑わしい – 議論する ] 型なしラムダ計算 では 、関数だけがプリミティブ データ型です。
使用
チャーチ符号化方式を単純に実装すると、 から へのアクセス操作が遅くなります 。 ここで は データ構造のサイズであり、チャーチ符号化方式は実用的ではありません。 [1] 研究では、この問題は対象を絞った最適化によって対処できることが示されていますが、ほとんどの 関数型プログラミング言語では、中間表現を拡張して 代数データ型 を含めます 。 [2] それでも、チャーチ符号化方式は部分評価や定理証明の自然な表現であるため、理論的な議論ではよく使用されます。 [1]操作は、 より高位の型 を使用して型付けでき 、 [3] プリミティブ再帰に簡単にアクセスできます。 [1] 関数が唯一のプリミティブデータ型であるという仮定により、多くの証明が合理化されます。
お
(
1
)
{\displaystyle O(1)}
お
(
ん
)
{\displaystyle O(n)}
ん
{\displaystyle n}
チャーチ符号化は完全ですが、表現上のみです。人々に表示するために、表現を一般的なデータ型に変換するには、追加の関数が必要です。 チャーチの定理 による 同値の決定不能性 のため、一般に 2 つの関数が 外延的に 等しいかどうかを判断することはできません。変換では、関数を何らかの方法で適用してそれが表す値を取得するか、その値をリテラル ラムダ項として検索します。ラムダ計算は通常、 内包的等式 を使用するものとして解釈されます。内包的等式と外延的等式の定義が異なるため、結果の解釈に
潜在的な問題 があります。
教会の数字
チャーチ数値は、チャーチ符号化による 自然数 の表現です。 自然数 nを表す 高階関数は、 任意の関数をその n 倍の 構成 にマッピングする関数です 。簡単に言えば、数値の「値」は、関数がその引数をカプセル化する回数に相当します。
ふ
{\displaystyle f}
ふ
∘
ん
=
ふ
∘
ふ
∘
⋯
∘
ふ
⏟
ん
回
。
{\displaystyle f^{\circ n}=\underbrace {f\circ f\circ \cdots \circ f} _{n{\text{ 回}}}.\,}
すべてのチャーチ数値は2つ の パラメータを取る関数です。チャーチ数値 0、1、2 、 ... は、 ラムダ計算 で 次のように定義されます 。
0 で 関数をまったく適用しないことから始めて、 1 で 関数を 1 回適用し、 2 で 関数を 2 回適用し、 3 で 関数を 3 回適用する、というように 進めます。
番号
関数定義
ラムダ式
0
0
ふ
x
=
x
0
=
λ
ふ
。
λ
x
。
x
1
1
ふ
x
=
ふ
x
1
=
λ
ふ
。
λ
x
。
ふ
x
2
2
ふ
x
=
ふ
(
ふ
x
)
2
=
λ
ふ
。
λ
x
。
ふ
(
ふ
x
)
3
3
ふ
x
=
ふ
(
ふ
(
ふ
x
)
)
3
=
λ
ふ
。
λ
x
。
ふ
(
ふ
(
ふ
x
)
)
⋮
⋮
⋮
ん
ん
ふ
x
=
ふ
ん
x
ん
=
λ
ふ
。
λ
x
。
ふ
∘
ん
x
{\displaystyle {\begin{array}{r|l|l}{\text{Number}}&{\text{Function definition}}&{\text{Lambda expression}}\\\hline 0&0\ f\ x=x&0=\lambda f.\lambda x.x\\1&1\ f\ x=f\ x&1=\lambda f.\lambda x.f\ x\\2&2\ f\ x=f\ (f\ x)&2=\lambda f.\lambda x.f\ (f\ x)\\3&3\ f\ x=f\ (f\ (f\ x))&3=\lambda f.\lambda x.f\ (f\ (f\ x))\\\vdots &\vdots &\vdots \\n&n\ f\ x=f^{n}\ x&n=\lambda f.\lambda x.f^{\circ n}\ x\end{array}}}
チャーチ数字 3 は 、任意の関数を値に 3 回適用するアクションを表します。指定された関数は、最初に指定されたパラメータに適用され、次に関数自体の結果に連続して適用されます。最終結果は数値 3 ではありません (指定されたパラメータがたまたま 0 で、関数が 後続関数 である場合を除く)。関数自体 (最終結果ではありません) がチャーチ数字 3 です。チャーチ数字 3 は 、単に何かを 3 回実行することを意味します。これは、「3 回」が何を意味するかを示す
明示的な デモンストレーションです。
教会数字による計算
数値の算術 演算は、チャーチ数値の関数で表すことができます。これらの関数は、 ラムダ計算 で定義するか、ほとんどの関数型プログラミング言語で実装できます ( ラムダ式から関数への変換を 参照)。
加算関数は 恒等式を使用します 。
plus
(
m
,
n
)
=
m
+
n
{\displaystyle \operatorname {plus} (m,n)=m+n}
f
∘
(
m
+
n
)
(
x
)
=
f
∘
m
(
f
∘
n
(
x
)
)
{\displaystyle f^{\circ (m+n)}(x)=f^{\circ m}(f^{\circ n}(x))}
plus
≡
λ
m
.
λ
n
.
λ
f
.
λ
x
.
m
f
(
n
f
x
)
{\displaystyle \operatorname {plus} \equiv \lambda m.\lambda n.\lambda f.\lambda x.m\ f\ (n\ f\ x)}
後継関数は と β 等価 です 。
succ
(
n
)
=
n
+
1
{\displaystyle \operatorname {succ} (n)=n+1}
(
plus
1
)
{\displaystyle (\operatorname {plus} \ 1)}
succ
≡
λ
n
.
λ
f
.
λ
x
.
f
(
n
f
x
)
{\displaystyle \operatorname {succ} \equiv \lambda n.\lambda f.\lambda x.f\ (n\ f\ x)}
乗算関数は 恒等式を使用します 。
mult
(
m
,
n
)
=
m
∗
n
{\displaystyle \operatorname {mult} (m,n)=m*n}
f
∘
(
m
∗
n
)
(
x
)
=
(
f
∘
n
)
∘
m
(
x
)
{\displaystyle f^{\circ (m*n)}(x)=(f^{\circ n})^{\circ m}(x)}
mult
≡
λ
m
.
λ
n
.
λ
f
.
λ
x
.
m
(
n
f
)
x
{\displaystyle \operatorname {mult} \equiv \lambda m.\lambda n.\lambda f.\lambda x.m\ (n\ f)\ x}
指数関数は チャーチ数の定義によって与えられます 。定義で を代入する と 、次の式が得られます。
exp
(
m
,
n
)
=
m
n
{\displaystyle \operatorname {exp} (m,n)=m^{n}}
n
h
x
=
h
n
x
{\displaystyle n\ h\ x=h^{n}\ x}
h
→
m
,
x
→
f
{\displaystyle h\to m,x\to f}
n
m
f
=
m
n
f
{\displaystyle n\ m\ f=m^{n}\ f}
exp
m
n
=
m
n
=
n
m
{\displaystyle \operatorname {exp} \ m\ n=m^{n}=n\ m}
これはラムダ式を与える。
exp
≡
λ
m
.
λ
n
.
n
m
{\displaystyle \operatorname {exp} \equiv \lambda m.\lambda n.n\ m}
機能 は理解するのがより困難です。
pred
(
n
)
{\displaystyle \operatorname {pred} (n)}
pred
≡
λ
n
.
λ
f
.
λ
x
.
n
(
λ
g
.
λ
h
.
h
(
g
f
)
)
(
λ
u
.
x
)
(
λ
u
.
u
)
{\displaystyle \operatorname {pred} \equiv \lambda n.\lambda f.\lambda x.n\ (\lambda g.\lambda h.h\ (g\ f))\ (\lambda u.x)\ (\lambda u.u)}
チャーチ数値は関数を n 回適用します。先行関数は、そのパラメータを n - 1回適用する関数を返す必要があります。これは、関数の最初の適用を省略する方法で初期化される f と x の 周りにコンテナを構築することによって実現されます 。詳細な説明については、先行関数を参照してください。
減算関数は、先行関数に基づいて記述できます。
minus
≡
λ
m
.
λ
n
.
(
n
pred
)
m
{\displaystyle \operatorname {minus} \equiv \lambda m.\lambda n.(n\operatorname {pred} )\ m}
教会数字の機能表
注記 :
^この式は、チャーチ数 n の 定義です 。
f
→
m
,
x
→
f
{\displaystyle f\to m,x\to f}
^ ab 教会のエンコーディングでは、
pred
(
0
)
=
0
{\displaystyle \operatorname {pred} (0)=0}
m
≤
n
→
m
−
n
=
0
{\displaystyle m\leq n\to m-n=0}
先行関数の導出
チャーチエンコーディングで使用される先行関数は、
pred
(
n
)
=
{
0
if
n
=
0
,
n
−
1
otherwise
{\displaystyle \operatorname {pred} (n)={\begin{cases}0&{\mbox{if }}n=0,\\n-1&{\mbox{otherwise}}\end{cases}}}
。
先行関数を構築するには、関数を 1 回少なく適用する方法が必要です。数値 n は 関数 f を x に n 回適用します。先行関数は、数値 n を 使用して関数を n -1 回適用する必要があります。
先行関数を実装する前に、値をコンテナ関数にラップするスキームを次に示します。 f と x の代わりに使用する inc と init という新しい関数を定義します 。コンテナ関数は value と呼ばれます。表の左側には、 inc と init に適用された数値 n が表示されています。
Number
Using init
Using const
0
init
=
value
x
1
inc
init
=
value
(
f
x
)
inc
const
=
value
x
2
inc
(
inc
init
)
=
value
(
f
(
f
x
)
)
inc
(
inc
const
)
=
value
(
f
x
)
3
inc
(
inc
(
inc
init
)
)
=
value
(
f
(
f
(
f
x
)
)
)
inc
(
inc
(
inc
const
)
)
=
value
(
f
(
f
x
)
)
⋮
⋮
⋮
n
n
inc
init
=
value
(
f
n
x
)
=
value
(
n
f
x
)
n
inc
const
=
value
(
f
n
−
1
x
)
=
value
(
(
n
−
1
)
f
x
)
{\displaystyle {\begin{array}{r|r|r}{\text{Number}}&{\text{Using init}}&{\text{Using const}}\\\hline 0&\operatorname {init} =\operatorname {value} \ x&\\1&\operatorname {inc} \ \operatorname {init} =\operatorname {value} \ (f\ x)&\operatorname {inc} \ \operatorname {const} =\operatorname {value} \ x\\2&\operatorname {inc} \ (\operatorname {inc} \ \operatorname {init} )=\operatorname {value} \ (f\ (f\ x))&\operatorname {inc} \ (\operatorname {inc} \ \operatorname {const} )=\operatorname {value} \ (f\ x)\\3&\operatorname {inc} \ (\operatorname {inc} \ (\operatorname {inc} \ \operatorname {init} ))=\operatorname {value} \ (f\ (f\ (f\ x)))&\operatorname {inc} \ (\operatorname {inc} \ (\operatorname {inc} \ \operatorname {const} ))=\operatorname {value} \ (f\ (f\ x))\\\vdots &\vdots &\vdots \\n&n\operatorname {inc} \ \operatorname {init} =\operatorname {value} \ (f^{n}\ x)=\operatorname {value} \ (n\ f\ x)&n\operatorname {inc} \ \operatorname {const} =\operatorname {value} \ (f^{n-1}\ x)=\operatorname {value} \ ((n-1)\ f\ x)\\\end{array}}}
一般的な繰り返し規則は、
inc
(
value
v
)
=
value
(
f
v
)
{\displaystyle \operatorname {inc} \ (\operatorname {value} \ v)=\operatorname {value} \ (f\ v)}
コンテナから値を取得する関数( extract と呼ばれる)もある場合、
extract
(
value
v
)
=
v
{\displaystyle \operatorname {extract} \ (\operatorname {value} \ v)=v}
次に、 extractを 使用して、 samenum 関数を次のように定義します。
samenum
=
λ
n
.
λ
f
.
λ
x
.
extract
(
n
inc
init
)
=
λ
n
.
λ
f
.
λ
x
.
extract
(
value
(
n
f
x
)
)
=
λ
n
.
λ
f
.
λ
x
.
n
f
x
=
λ
n
.
n
{\displaystyle \operatorname {samenum} =\lambda n.\lambda f.\lambda x.\operatorname {extract} \ (n\operatorname {inc} \operatorname {init} )=\lambda n.\lambda f.\lambda x.\operatorname {extract} \ (\operatorname {value} \ (n\ f\ x))=\lambda n.\lambda f.\lambda x.n\ f\ x=\lambda n.n}
samenum関数は 、 本質的には役に立ちません。ただし、 inc は f の呼び出しを そのコンテナ引数に委任するため、最初の適用時に inc が引数を無視する特別なコンテナを受け取り、 f の最初の適用をスキップするように設定できます 。この新しい初期コンテナを const と 呼びます。上記の表の右側は、 n inc constの展開を示しています。次に、 同じ 関数の式で init を const に 置き換えると 、先行関数が得られます。
pred
=
λ
n
.
λ
f
.
λ
x
.
extract
(
n
inc
const
)
=
λ
n
.
λ
f
.
λ
x
.
extract
(
value
(
(
n
−
1
)
f
x
)
)
=
λ
n
.
λ
f
.
λ
x
.
(
n
−
1
)
f
x
=
λ
n
.
(
n
−
1
)
{\displaystyle \operatorname {pred} =\lambda n.\lambda f.\lambda x.\operatorname {extract} \ (n\operatorname {inc} \operatorname {const} )=\lambda n.\lambda f.\lambda x.\operatorname {extract} \ (\operatorname {value} \ ((n-1)\ f\ x))=\lambda n.\lambda f.\lambda x.(n-1)\ f\ x=\lambda n.(n-1)}
以下に説明するように、関数 inc 、 init 、 const 、 value 、 extract は 次のように定義できます。
value
=
λ
v
.
(
λ
h
.
h
v
)
extract
k
=
k
λ
u
.
u
inc
=
λ
g
.
λ
h
.
h
(
g
f
)
init
=
λ
h
.
h
x
const
=
λ
u
.
x
{\displaystyle {\begin{aligned}\operatorname {value} &=\lambda v.(\lambda h.h\ v)\\\operatorname {extract} k&=k\ \lambda u.u\\\operatorname {inc} &=\lambda g.\lambda h.h\ (g\ f)\\\operatorname {init} &=\lambda h.h\ x\\\operatorname {const} &=\lambda u.x\end{aligned}}}
これにより、 pred のラムダ式は 次のようになります。
pred
=
λ
n
.
λ
f
.
λ
x
.
n
(
λ
g
.
λ
h
.
h
(
g
f
)
)
(
λ
u
.
x
)
(
λ
u
.
u
)
{\displaystyle \operatorname {pred} =\lambda n.\lambda f.\lambda x.n\ (\lambda g.\lambda h.h\ (g\ f))\ (\lambda u.x)\ (\lambda u.u)}
predを定義する別の方法
Pred はペアを使用して定義することもできます。
f
=
λ
p
.
pair
(
second
p
)
(
succ
(
second
p
)
)
zero
=
(
λ
f
.
λ
x
.
x
)
pc0
=
pair
zero
zero
pred
=
λ
n
.
first
(
n
f
pc0
)
{\displaystyle {\begin{aligned}\operatorname {f} =&\ \lambda p.\ \operatorname {pair} \ (\operatorname {second} \ p)\ (\operatorname {succ} \ (\operatorname {second} \ p))\\\operatorname {zero} =&\ (\lambda f.\lambda x.\ x)\\\operatorname {pc0} =&\ \operatorname {pair} \ \operatorname {zero} \ \operatorname {zero} \\\operatorname {pred} =&\ \lambda n.\ \operatorname {first} \ (n\ \operatorname {f} \ \operatorname {pc0} )\\\end{aligned}}}
これはより単純な定義ですが、pred の表現はより複雑になります。 の展開は次のようになります 。
pred
three
{\displaystyle \operatorname {pred} \operatorname {three} }
pred
three
=
first
(
f
(
f
(
f
(
pair
zero
zero
)
)
)
)
=
first
(
f
(
f
(
pair
zero
one
)
)
)
=
first
(
f
(
pair
one
two
)
)
=
first
(
pair
two
three
)
=
two
{\displaystyle {\begin{aligned}\operatorname {pred} \operatorname {three} =&\ \operatorname {first} \ (\operatorname {f} \ (\operatorname {f} \ (\operatorname {f} \ (\operatorname {pair} \ \operatorname {zero} \ \operatorname {zero} ))))\\=&\ \operatorname {first} \ (\operatorname {f} \ (\operatorname {f} \ (\operatorname {pair} \ \operatorname {zero} \ \operatorname {one} )))\\=&\ \operatorname {first} \ (\operatorname {f} \ (\operatorname {pair} \ \operatorname {one} \ \operatorname {two} ))\\=&\ \operatorname {first} \ (\operatorname {pair} \ \operatorname {two} \ \operatorname {three} )\\=&\ \operatorname {two} \end{aligned}}}
分割
自然数の除算は 次のように実装できる。 [4]
n
/
m
=
if
n
≥
m
then
1
+
(
n
−
m
)
/
m
else
0
{\displaystyle n/m=\operatorname {if} \ n\geq m\ \operatorname {then} \ 1+(n-m)/m\ \operatorname {else} \ 0}
計算には 多くのベータ削減が必要です。削減を手動で行わない限り、これはそれほど重要ではありませんが、この計算を 2 回実行しない方が望ましいです。数値をテストするための最も単純な述語は IsZero なので、条件を検討してください。
n
−
m
{\displaystyle n-m}
IsZero
(
minus
n
m
)
{\displaystyle \operatorname {IsZero} \ (\operatorname {minus} \ n\ m)}
しかし、この条件は と等価であり 、 ではありません 。この表現を使用すると、上記の除算の数学的定義は、チャーチ数上の関数に変換され、
n
≤
m
{\displaystyle n\leq m}
n
<
m
{\displaystyle n<m}
divide1
n
m
f
x
=
(
λ
d
.
IsZero
d
(
0
f
x
)
(
f
(
divide1
d
m
f
x
)
)
)
(
minus
n
m
)
{\displaystyle \operatorname {divide1} \ n\ m\ f\ x=(\lambda d.\operatorname {IsZero} \ d\ (0\ f\ x)\ (f\ (\operatorname {divide1} \ d\ m\ f\ x)))\ (\operatorname {minus} \ n\ m)}
希望どおり、この定義には の呼び出しが 1 回あります 。ただし、結果として、この式は の値を返します 。
minus
n
m
{\displaystyle \operatorname {minus} \ n\ m}
(
n
−
1
)
/
m
{\displaystyle (n-1)/m}
この問題は、 divideを 呼び出す 前に n に1を加算することで修正できます 。divideの定義は 次のようになります。
divide
n
=
divide1
(
succ
n
)
{\displaystyle \operatorname {divide} \ n=\operatorname {divide1} \ (\operatorname {succ} \ n)}
division1 は 再帰的な定義です。 再帰を実装するには、 Y コンビネータを使用できます。div by という 新しい関数を作成します。
左側に
divide1
→
div
c
{\displaystyle \operatorname {divide1} \rightarrow \operatorname {div} \ c}
右側には
divide1
→
c
{\displaystyle \operatorname {divide1} \rightarrow c}
取得するため、
div
=
λ
c
.
λ
n
.
λ
m
.
λ
f
.
λ
x
.
(
λ
d
.
IsZero
d
(
0
f
x
)
(
f
(
c
d
m
f
x
)
)
)
(
minus
n
m
)
{\displaystyle \operatorname {div} =\lambda c.\lambda n.\lambda m.\lambda f.\lambda x.(\lambda d.\operatorname {IsZero} \ d\ (0\ f\ x)\ (f\ (c\ d\ m\ f\ x)))\ (\operatorname {minus} \ n\ m)}
それから、
divide
=
λ
n
.
divide1
(
succ
n
)
{\displaystyle \operatorname {divide} =\lambda n.\operatorname {divide1} \ (\operatorname {succ} \ n)}
どこ、
divide1
=
Y
div
succ
=
λ
n
.
λ
f
.
λ
x
.
f
(
n
f
x
)
Y
=
λ
f
.
(
λ
x
.
f
(
x
x
)
)
(
λ
x
.
f
(
x
x
)
)
0
=
λ
f
.
λ
x
.
x
IsZero
=
λ
n
.
n
(
λ
x
.
false
)
true
{\displaystyle {\begin{aligned}\operatorname {divide1} &=Y\ \operatorname {div} \\\operatorname {succ} &=\lambda n.\lambda f.\lambda x.f\ (n\ f\ x)\\Y&=\lambda f.(\lambda x.f\ (x\ x))\ (\lambda x.f\ (x\ x))\\0&=\lambda f.\lambda x.x\\\operatorname {IsZero} &=\lambda n.n\ (\lambda x.\operatorname {false} )\ \operatorname {true} \end{aligned}}}
true
≡
λ
a
.
λ
b
.
a
false
≡
λ
a
.
λ
b
.
b
{\displaystyle {\begin{aligned}\operatorname {true} &\equiv \lambda a.\lambda b.a\\\operatorname {false} &\equiv \lambda a.\lambda b.b\end{aligned}}}
minus
=
λ
m
.
λ
n
.
n
pred
m
pred
=
λ
n
.
λ
f
.
λ
x
.
n
(
λ
g
.
λ
h
.
h
(
g
f
)
)
(
λ
u
.
x
)
(
λ
u
.
u
)
{\displaystyle {\begin{aligned}\operatorname {minus} &=\lambda m.\lambda n.n\operatorname {pred} m\\\operatorname {pred} &=\lambda n.\lambda f.\lambda x.n\ (\lambda g.\lambda h.h\ (g\ f))\ (\lambda u.x)\ (\lambda u.u)\end{aligned}}}
与える、
divide
=
λ
n
.
(
(
λ
f
.
(
λ
x
.
x
x
)
(
λ
x
.
f
(
x
x
)
)
)
(
λ
c
.
λ
n
.
λ
m
.
λ
f
.
λ
x
.
(
λ
d
.
(
λ
n
.
n
(
λ
x
.
(
λ
a
.
λ
b
.
b
)
)
(
λ
a
.
λ
b
.
a
)
)
d
(
(
λ
f
.
λ
x
.
x
)
f
x
)
(
f
(
c
d
m
f
x
)
)
)
(
(
λ
m
.
λ
n
.
n
(
λ
n
.
λ
f
.
λ
x
.
n
(
λ
g
.
λ
h
.
h
(
g
f
)
)
(
λ
u
.
x
)
(
λ
u
.
u
)
)
m
)
n
m
)
)
)
(
(
λ
n
.
λ
f
.
λ
x
.
f
(
n
f
x
)
)
n
)
{\displaystyle \scriptstyle \operatorname {divide} =\lambda n.((\lambda f.(\lambda x.x\ x)\ (\lambda x.f\ (x\ x)))\ (\lambda c.\lambda n.\lambda m.\lambda f.\lambda x.(\lambda d.(\lambda n.n\ (\lambda x.(\lambda a.\lambda b.b))\ (\lambda a.\lambda b.a))\ d\ ((\lambda f.\lambda x.x)\ f\ x)\ (f\ (c\ d\ m\ f\ x)))\ ((\lambda m.\lambda n.n(\lambda n.\lambda f.\lambda x.n\ (\lambda g.\lambda h.h\ (g\ f))\ (\lambda u.x)\ (\lambda u.u))m)\ n\ m)))\ ((\lambda n.\lambda f.\lambda x.f\ (n\ f\ x))\ n)}
またはテキストとして、 λ の代わりに\を使用する。
除算 = (\n.((\f.(\xx x) (\xf (xx))) (\c.\n.\m.\f.\x.(\d.(\nn (\x .(\a.\bb)) (\a.\ba)) d ((\f.\xx) fx) (f (cdmfx))) ((\m.\nn (\n.\f.\ xn (\g.\hh (gf)) (\ux) (\uu)) m) nm))) ((\n.\f.\x. f (nfx)) n))
例えば、9/3は次のように表されます。
割り算 (\f.\xf (f (f (f (f (f (f (f (f (f (f (f (f (f (fx))))))))) (\f.\xf (f (fx)))
ラムダ計算計算機を使用すると、上記の式は通常の順序で 3 に簡約されます。
\f.\xf (f (f (x)))
符号付き数字
チャーチ数字を符号付き数 に拡張する簡単な方法の1つは 、正の値と負の値を表すチャーチ数字を含むチャーチペアを使用することです。 [5] 整数値は2つのチャーチ数字の差です。
自然数は次のように符号付き数に変換される。
convert
s
=
λ
x
.
pair
x
0
{\displaystyle \operatorname {convert} _{s}=\lambda x.\operatorname {pair} \ x\ 0}
否定は値を交換することによって実行されます。
neg
s
=
λ
x
.
pair
(
second
x
)
(
first
x
)
{\displaystyle \operatorname {neg} _{s}=\lambda x.\operatorname {pair} \ (\operatorname {second} \ x)\ (\operatorname {first} \ x)}
整数 値は、ペアの1つがゼロの場合に、より自然に表現されます。OneZero 関数はこの条件を実現します。
OneZero
=
λ
x
.
IsZero
(
first
x
)
x
(
IsZero
(
second
x
)
x
(
OneZero
(
pair
(
pred
(
first
x
)
)
(
pred
(
second
x
)
)
)
)
)
{\displaystyle \operatorname {OneZero} =\lambda x.\operatorname {IsZero} \ (\operatorname {first} \ x)\ x\ (\operatorname {IsZero} \ (\operatorname {second} \ x)\ x\ (\operatorname {OneZero} \ (\operatorname {pair} \ (\operatorname {pred} \ (\operatorname {first} \ x))\ (\operatorname {pred} \ (\operatorname {second} \ x)))))}
再帰はYコンビネータを使用して実装できます。
OneZ
=
λ
c
.
λ
x
.
IsZero
(
first
x
)
x
(
IsZero
(
second
x
)
x
(
c
(
pair
(
pred
(
first
x
)
)
(
pred
(
second
x
)
)
)
)
)
{\displaystyle \operatorname {OneZ} =\lambda c.\lambda x.\operatorname {IsZero} \ (\operatorname {first} \ x)\ x\ (\operatorname {IsZero} \ (\operatorname {second} \ x)\ x\ (c\ (\operatorname {pair} \ (\operatorname {pred} \ (\operatorname {first} \ x))\ (\operatorname {pred} \ (\operatorname {second} \ x)))))}
OneZero
=
Y
OneZ
{\displaystyle \operatorname {OneZero} =Y\operatorname {OneZ} }
プラスとマイナス
加算は数学的には次のように定義されます。
x
+
y
=
[
x
p
,
x
n
]
+
[
y
p
,
y
n
]
=
x
p
−
x
n
+
y
p
−
y
n
=
(
x
p
+
y
p
)
−
(
x
n
+
y
n
)
=
[
x
p
+
y
p
,
x
n
+
y
n
]
{\displaystyle x+y=[x_{p},x_{n}]+[y_{p},y_{n}]=x_{p}-x_{n}+y_{p}-y_{n}=(x_{p}+y_{p})-(x_{n}+y_{n})=[x_{p}+y_{p},x_{n}+y_{n}]}
最後の式はラムダ計算では次のように翻訳される。
plus
s
=
λ
x
.
λ
y
.
OneZero
(
pair
(
plus
(
first
x
)
(
first
y
)
)
(
plus
(
second
x
)
(
second
y
)
)
)
{\displaystyle \operatorname {plus} _{s}=\lambda x.\lambda y.\operatorname {OneZero} \ (\operatorname {pair} \ (\operatorname {plus} \ (\operatorname {first} \ x)\ (\operatorname {first} \ y))\ (\operatorname {plus} \ (\operatorname {second} \ x)\ (\operatorname {second} \ y)))}
同様に減算も定義される。
x
−
y
=
[
x
p
,
x
n
]
−
[
y
p
,
y
n
]
=
x
p
−
x
n
−
y
p
+
y
n
=
(
x
p
+
y
n
)
−
(
x
n
+
y
p
)
=
[
x
p
+
y
n
,
x
n
+
y
p
]
{\displaystyle x-y=[x_{p},x_{n}]-[y_{p},y_{n}]=x_{p}-x_{n}-y_{p}+y_{n}=(x_{p}+y_{n})-(x_{n}+y_{p})=[x_{p}+y_{n},x_{n}+y_{p}]}
与える、
minus
s
=
λ
x
.
λ
y
.
OneZero
(
pair
(
plus
(
first
x
)
(
second
y
)
)
(
plus
(
second
x
)
(
first
y
)
)
)
{\displaystyle \operatorname {minus} _{s}=\lambda x.\lambda y.\operatorname {OneZero} \ (\operatorname {pair} \ (\operatorname {plus} \ (\operatorname {first} \ x)\ (\operatorname {second} \ y))\ (\operatorname {plus} \ (\operatorname {second} \ x)\ (\operatorname {first} \ y)))}
掛け算と割り算
乗算は次のように定義される。
x
∗
y
=
[
x
p
,
x
n
]
∗
[
y
p
,
y
n
]
=
(
x
p
−
x
n
)
∗
(
y
p
−
y
n
)
=
(
x
p
∗
y
p
+
x
n
∗
y
n
)
−
(
x
p
∗
y
n
+
x
n
∗
y
p
)
=
[
x
p
∗
y
p
+
x
n
∗
y
n
,
x
p
∗
y
n
+
x
n
∗
y
p
]
{\displaystyle x*y=[x_{p},x_{n}]*[y_{p},y_{n}]=(x_{p}-x_{n})*(y_{p}-y_{n})=(x_{p}*y_{p}+x_{n}*y_{n})-(x_{p}*y_{n}+x_{n}*y_{p})=[x_{p}*y_{p}+x_{n}*y_{n},x_{p}*y_{n}+x_{n}*y_{p}]}
最後の式はラムダ計算では次のように翻訳される。
mult
s
=
λ
x
.
λ
y
.
pair
(
plus
(
mult
(
first
x
)
(
first
y
)
)
(
mult
(
second
x
)
(
second
y
)
)
)
(
plus
(
mult
(
first
x
)
(
second
y
)
)
(
mult
(
second
x
)
(
first
y
)
)
)
{\displaystyle \operatorname {mult} _{s}=\lambda x.\lambda y.\operatorname {pair} \ (\operatorname {plus} \ (\operatorname {mult} \ (\operatorname {first} \ x)\ (\operatorname {first} \ y))\ (\operatorname {mult} \ (\operatorname {second} \ x)\ (\operatorname {second} \ y)))\ (\operatorname {plus} \ (\operatorname {mult} \ (\operatorname {first} \ x)\ (\operatorname {second} \ y))\ (\operatorname {mult} \ (\operatorname {second} \ x)\ (\operatorname {first} \ y)))}
除算についても同様の定義がここに示されていますが、この定義では、各ペアの 1 つの値はゼロでなければなりません (上記の OneZero を参照)。divZ 関数 を使用すると、ゼロ要素を持つ値を無視できます。
divZ
=
λ
x
.
λ
y
.
IsZero
y
0
(
divide
x
y
)
{\displaystyle \operatorname {divZ} =\lambda x.\lambda y.\operatorname {IsZero} \ y\ 0\ (\operatorname {divide} \ x\ y)}
次に、 divZ が次の式で使用されます。これは乗算の場合と同じですが、 multが divZ に置き換えられます 。
divide
s
=
λ
x
.
λ
y
.
pair
(
plus
(
divZ
(
first
x
)
(
first
y
)
)
(
divZ
(
second
x
)
(
second
y
)
)
)
(
plus
(
divZ
(
first
x
)
(
second
y
)
)
(
divZ
(
second
x
)
(
first
y
)
)
)
{\displaystyle \operatorname {divide} _{s}=\lambda x.\lambda y.\operatorname {pair} \ (\operatorname {plus} \ (\operatorname {divZ} \ (\operatorname {first} \ x)\ (\operatorname {first} \ y))\ (\operatorname {divZ} \ (\operatorname {second} \ x)\ (\operatorname {second} \ y)))\ (\operatorname {plus} \ (\operatorname {divZ} \ (\operatorname {first} \ x)\ (\operatorname {second} \ y))\ (\operatorname {divZ} \ (\operatorname {second} \ x)\ (\operatorname {first} \ y)))}
有理数と実数
有理数と 計算可能な実数 もラムダ計算でエンコードできます。有理数は符号付きの数のペアとしてエンコードできます。計算可能な実数は、実数値との差が、必要なだけ小さくできる数値だけ異なることを保証する制限プロセスによってエンコードできます。 [6]
[7] 示されている参考文献では、理論的にはラムダ計算に変換できるソフトウェアについて説明しています。実数が定義されると、複素数は自然に実数のペアとしてエンコードされます。
上で説明したデータ型と関数は、あらゆるデータ型や計算をラムダ計算でエンコードできることを示しています。これがチャーチ =チューリングのテーゼ です。
他の表現による翻訳
現実世界の言語のほとんどは、マシン固有の整数をサポートしています。 church 関数 と unchurch関数は、非負整数とそれに対応する Church 数値を変換します。これらの関数は、ここでは Haskell で提供されています 。ここで、 は \ラムダ計算の λ に対応します。他の言語での実装も同様です。
タイプ Church a = ( a -> a ) -> a -> a
church :: Integer -> Church Integer church 0 = \ f -> \ x -> x church n = \ f -> \ x -> f ( church ( n - 1 ) f x )
unchurch :: 教会 整数 -> 整数 unchurch cn = cn ( + 1 ) 0
教会のブール値
Church ブール値は、ブール値 true とfalse の Church エンコードです 。 一部のプログラミング言語では、これをブール演算の実装モデルとして使用します。例としては、 Smalltalk や Pico など があります。
ブール論理は選択肢として考えられます。 true と false の Church エンコードは、2 つのパラメータの関数です。
true は 最初のパラメータを選択します。
false は 2 番目のパラメータを選択します。
次の 2 つの定義は Church ブール値として知られています。
true
≡
λ
a
.
λ
b
.
a
false
≡
λ
a
.
λ
b
.
b
{\displaystyle {\begin{aligned}\operatorname {true} &\equiv \lambda a.\lambda b.a\\\operatorname {false} &\equiv \lambda a.\lambda b.b\end{aligned}}}
この定義により、述語 (つまり、 論理値を 返す関数) が直接 if 節として動作できるようになります。ブール値を返す関数は、2 つのパラメータに適用され、最初のパラメータまたは 2 番目のパラメータのいずれかを返します。
p
r
e
d
i
c
a
t
e
-
x
t
h
e
n
-
c
l
a
u
s
e
e
l
s
e
-
c
l
a
u
s
e
{\displaystyle \operatorname {predicate-} x\ \operatorname {then-clause} \ \operatorname {else-clause} }
述語 x が true と評価された 場合は then 節 に評価され 、 述語 x が false と評価された 場合は else 節に評価されます。
true と false は 最初のパラメータまたは 2 番目のパラメータを選択する ため、これらを組み合わせて論理演算子を提供できます 。not の実装は複数可能であることに注意してください。
and
=
λ
p
.
λ
q
.
p
q
p
or
=
λ
p
.
λ
q
.
p
p
q
not
1
=
λ
p
.
λ
a
.
λ
b
.
p
b
a
not
2
=
λ
p
.
p
(
λ
a
.
λ
b
.
b
)
(
λ
a
.
λ
b
.
a
)
=
λ
p
.
p
false
true
xor
=
λ
a
.
λ
b
.
a
(
not
b
)
b
if
=
λ
p
.
λ
a
.
λ
b
.
p
a
b
{\displaystyle {\begin{aligned}\operatorname {and} &=\lambda p.\lambda q.p\ q\ p\\\operatorname {or} &=\lambda p.\lambda q.p\ p\ q\\\operatorname {not} _{1}&=\lambda p.\lambda a.\lambda b.p\ b\ a\\\operatorname {not} _{2}&=\lambda p.p\ (\lambda a.\lambda b.b)\ (\lambda a.\lambda b.a)=\lambda p.p\operatorname {false} \operatorname {true} \\\operatorname {xor} &=\lambda a.\lambda b.a\ (\operatorname {not} \ b)\ b\\\operatorname {if} &=\lambda p.\lambda a.\lambda b.p\ a\ b\end{aligned}}}
例:
and
true
false
=
(
λ
p
.
λ
q
.
p
q
p
)
true
false
=
true
false
true
=
(
λ
a
.
λ
b
.
a
)
false
true
=
false
or
true
false
=
(
λ
p
.
λ
q
.
p
p
q
)
(
λ
a
.
λ
b
.
a
)
(
λ
a
.
λ
b
.
b
)
=
(
λ
a
.
λ
b
.
a
)
(
λ
a
.
λ
b
.
a
)
(
λ
a
.
λ
b
.
b
)
=
(
λ
a
.
λ
b
.
a
)
=
true
not
1
true
=
(
λ
p
.
λ
a
.
λ
b
.
p
b
a
)
(
λ
a
.
λ
b
.
a
)
=
λ
a
.
λ
b
.
(
λ
a
.
λ
b
.
a
)
b
a
=
λ
a
.
λ
b
.
(
λ
c
.
b
)
a
=
λ
a
.
λ
b
.
b
=
false
not
2
true
=
(
λ
p
.
p
(
λ
a
.
λ
b
.
b
)
(
λ
a
.
λ
b
.
a
)
)
(
λ
a
.
λ
b
.
a
)
=
(
λ
a
.
λ
b
.
a
)
(
λ
a
.
λ
b
.
b
)
(
λ
a
.
λ
b
.
a
)
=
(
λ
b
.
(
λ
a
.
λ
b
.
b
)
)
(
λ
a
.
λ
b
.
a
)
=
λ
a
.
λ
b
.
b
=
false
{\displaystyle {\begin{aligned}\operatorname {and} \operatorname {true} \operatorname {false} &=(\lambda p.\lambda q.p\ q\ p)\ \operatorname {true} \ \operatorname {false} =\operatorname {true} \operatorname {false} \operatorname {true} =(\lambda a.\lambda b.a)\operatorname {false} \operatorname {true} =\operatorname {false} \\\operatorname {or} \operatorname {true} \operatorname {false} &=(\lambda p.\lambda q.p\ p\ q)\ (\lambda a.\lambda b.a)\ (\lambda a.\lambda b.b)=(\lambda a.\lambda b.a)\ (\lambda a.\lambda b.a)\ (\lambda a.\lambda b.b)=(\lambda a.\lambda b.a)=\operatorname {true} \\\operatorname {not} _{1}\ \operatorname {true} &=(\lambda p.\lambda a.\lambda b.p\ b\ a)(\lambda a.\lambda b.a)=\lambda a.\lambda b.(\lambda a.\lambda b.a)\ b\ a=\lambda a.\lambda b.(\lambda c.b)\ a=\lambda a.\lambda b.b=\operatorname {false} \\\operatorname {not} _{2}\ \operatorname {true} &=(\lambda p.p\ (\lambda a.\lambda b.b)(\lambda a.\lambda b.a))(\lambda a.\lambda b.a)=(\lambda a.\lambda b.a)(\lambda a.\lambda b.b)(\lambda a.\lambda b.a)=(\lambda b.(\lambda a.\lambda b.b))\ (\lambda a.\lambda b.a)=\lambda a.\lambda b.b=\operatorname {false} \end{aligned}}}
述語
述語 は ブール値を返す関数です。最も基本的な述語は で 、 引数がチャーチ数値 の場合はを返し 、 引数がその他のチャーチ数値の場合は を返します。
IsZero
{\displaystyle \operatorname {IsZero} }
true
{\displaystyle \operatorname {true} }
0
{\displaystyle 0}
false
{\displaystyle \operatorname {false} }
IsZero
=
λ
n
.
n
(
λ
x
.
false
)
true
{\displaystyle \operatorname {IsZero} =\lambda n.n\ (\lambda x.\operatorname {false} )\ \operatorname {true} }
次の述語は、最初の引数が 2 番目の引数以下かどうかをテストします。
LEQ
=
λ
m
.
λ
n
.
IsZero
(
minus
m
n
)
{\displaystyle \operatorname {LEQ} =\lambda m.\lambda n.\operatorname {IsZero} \ (\operatorname {minus} \ m\ n)}
、
アイデンティティのため、
x
=
y
≡
(
x
≤
y
∧
y
≤
x
)
{\displaystyle x=y\equiv (x\leq y\land y\leq x)}
等価性のテストは次のように実装できます。
EQ
=
λ
m
.
λ
n
.
and
(
LEQ
m
n
)
(
LEQ
n
m
)
{\displaystyle \operatorname {EQ} =\lambda m.\lambda n.\operatorname {and} \ (\operatorname {LEQ} \ m\ n)\ (\operatorname {LEQ} \ n\ m)}
教会のペア
チャーチペアは、ペア (2組)型のチャーチエンコーディングです。ペアは、関数引数を取る関数として表されます。引数が与えられると、ペアの2つのコンポーネントに引数が適用されます。 ラムダ計算 の定義は 、
pair
≡
λ
x
.
λ
y
.
λ
z
.
z
x
y
first
≡
λ
p
.
p
(
λ
x
.
λ
y
.
x
)
second
≡
λ
p
.
p
(
λ
x
.
λ
y
.
y
)
{\displaystyle {\begin{aligned}\operatorname {pair} &\equiv \lambda x.\lambda y.\lambda z.z\ x\ y\\\operatorname {first} &\equiv \lambda p.p\ (\lambda x.\lambda y.x)\\\operatorname {second} &\equiv \lambda p.p\ (\lambda x.\lambda y.y)\end{aligned}}}
例えば、
first
(
pair
a
b
)
=
(
λ
p
.
p
(
λ
x
.
λ
y
.
x
)
)
(
(
λ
x
.
λ
y
.
λ
z
.
z
x
y
)
a
b
)
=
(
λ
p
.
p
(
λ
x
.
λ
y
.
x
)
)
(
λ
z
.
z
a
b
)
=
(
λ
z
.
z
a
b
)
(
λ
x
.
λ
y
.
x
)
=
(
λ
x
.
λ
y
.
x
)
a
b
=
a
{\displaystyle {\begin{aligned}&\operatorname {first} \ (\operatorname {pair} \ a\ b)\\=&(\lambda p.p\ (\lambda x.\lambda y.x))\ ((\lambda x.\lambda y.\lambda z.z\ x\ y)\ a\ b)\\=&(\lambda p.p\ (\lambda x.\lambda y.x))\ (\lambda z.z\ a\ b)\\=&(\lambda z.z\ a\ b)\ (\lambda x.\lambda y.x)\\=&(\lambda x.\lambda y.x)\ a\ b=a\end{aligned}}}
リストエンコーディング
( 不変の ) リスト はリストノードから構築されます。リストに対する基本的な操作は次のとおりです。
以下にリストの 4 つの異なる表現を示します。
各リスト ノードを 2 つのペアから構築します (空のリストを許可するため)。
各リスト ノードを 1 つのペアから構築します。
右折り畳み関数 を使用してリストを表します 。
一致式のケースを引数として取るスコットのエンコーディングを使用してリストを表現する
リストノードとしての2つのペア
空でないリストは Church ペアによって実装できます。
まず 頭が入っています。
2番目には 尾が含まれています。
ただし、これは「null」ポインタがないため、空のリストを表すものではありません。null を表すには、ペアを別のペアでラップして、次の 3 つの値を指定します。
まず 、ヌルポインター(空のリスト)。
Second.Firstには ヘッドが含まれます。
2番目。2番目には 末尾が含まれます。
この考え方を用いると、基本的なリスト操作は次のように定義できる。 [8]
nil ノード では、 head と tail が 空でないリストにのみ適用される
場合、 second は アクセスされません。
リストノードとして1組
あるいは、 [9]を定義する。
cons
≡
pair
head
≡
first
tail
≡
second
nil
≡
false
isnil
≡
λ
l
.
l
(
λ
h
.
λ
t
.
λ
d
.
false
)
true
{\displaystyle {\begin{aligned}\operatorname {cons} &\equiv \operatorname {pair} \\\operatorname {head} &\equiv \operatorname {first} \\\operatorname {tail} &\equiv \operatorname {second} \\\operatorname {nil} &\equiv \operatorname {false} \\\operatorname {isnil} &\equiv \lambda l.l(\lambda h.\lambda t.\lambda d.\operatorname {false} )\operatorname {true} \end{aligned}}}
最後の定義は一般的な定義の特別なケースである
p
r
o
c
e
s
s
-
l
i
s
t
≡
λ
l
.
l
(
λ
h
.
λ
t
.
λ
d
.
h
e
a
d
-
a
n
d
-
t
a
i
l
-
c
l
a
u
s
e
)
n
i
l
-
c
l
a
u
s
e
{\displaystyle \operatorname {process-list} \equiv \lambda l.l(\lambda h.\lambda t.\lambda d.\operatorname {head-and-tail-clause} )\operatorname {nil-clause} }
リストを次のように表す 右折り
チャーチペアを使用したエンコードの代替として、リストは 右折り畳み関数 で識別することによってエンコードできます。たとえば、3 つの要素 x、y、z のリストは、コンビネータ c と値 n に適用すると cx (cy (czn)) を返す高階関数によってエンコードできます。
nil
≡
λ
c
.
λ
n
.
n
isnil
≡
λ
l
.
l
(
λ
h
.
λ
t
.
false
)
true
cons
≡
λ
h
.
λ
t
.
λ
c
.
λ
n
.
c
h
(
t
c
n
)
head
≡
λ
l
.
l
(
λ
h
.
λ
t
.
h
)
false
tail
≡
λ
l
.
λ
c
.
λ
n
.
l
(
λ
h
.
λ
t
.
λ
g
.
g
h
(
t
c
)
)
(
λ
t
.
n
)
(
λ
h
.
λ
t
.
t
)
{\displaystyle {\begin{aligned}\operatorname {nil} &\equiv \lambda c.\lambda n.n\\\operatorname {isnil} &\equiv \lambda l.l\ (\lambda h.\lambda t.\operatorname {false} )\ \operatorname {true} \\\operatorname {cons} &\equiv \lambda h.\lambda t.\lambda c.\lambda n.c\ h\ (t\ c\ n)\\\operatorname {head} &\equiv \lambda l.l\ (\lambda h.\lambda t.h)\ \operatorname {false} \\\operatorname {tail} &\equiv \lambda l.\lambda c.\lambda n.l\ (\lambda h.\lambda t.\lambda g.g\ h\ (t\ c))\ (\lambda t.n)\ (\lambda h.\lambda t.t)\end{aligned}}}
このリスト表現はSystem F の型で指定できます 。
Scottエンコーディングを使用してリストを表す
代替表現としてスコット符号化があり、 継続 の考え方を利用してよりシンプルなコードを実現できる。 [10] ( モーゲンセン・スコット符号化 も参照)。
このアプローチでは、パターン マッチング式を使用してリストを観察できるという事実を利用します。たとえば、 Scala 表記法を使用すると、が 空のリスト とコンストラクタを持つ list型の値を表す場合、リストを検査して、 リストが空の場合と リストが空でない場合
を計算できます。 ListNilCons(h, t)nilCodeconsCode(h, t)
リスト 一致 { case Nil => nilCode case Cons ( h , t ) => consCode ( h , t ) }
は 、 および listにどのように作用するかによって決まります。したがって、リストを 、 および を引数として 受け取る関数として定義する と、上記のパターン マッチの代わりに、次のように簡単に記述できます。
nilCodeconsCodenilCodeconsCode
list
nilCode
consCode
{\displaystyle \operatorname {list} \ \operatorname {nilCode} \ \operatorname {consCode} }
nに対応するパラメータを で表し nilCode、 cに対応するパラメータを で 表します consCode。空のリストは nil 引数を返すリストです。
nil
≡
λ
n
.
λ
c
.
n
{\displaystyle \operatorname {nil} \equiv \lambda n.\lambda c.\ n}
h先頭と末尾を 持つ空でないリストは t次のように与えられる。
cons
h
t
≡
λ
n
.
λ
c
.
c
h
t
{\displaystyle \operatorname {cons} \ h\ t\ \ \equiv \ \ \lambda n.\lambda c.\ c\ h\ t}
より一般的には、選択肢 を持つ 代数データ型は 、パラメータを持つ関数になります 。 番目のコンストラクタに引数がある場合 、エンコーディングの対応するパラメータ も引数を取ります。
m
{\displaystyle m}
m
{\displaystyle m}
i
{\displaystyle i}
n
i
{\displaystyle n_{i}}
n
i
{\displaystyle n_{i}}
スコット エンコーディングは型なしラムダ計算で実行できますが、型で使用するには再帰と型多態性を備えた型システムが必要です。この表現で要素型 E を持ち、型 C の値を計算するために使用されるリストには、次の再帰型定義があります。ここで、'=>' は関数型を示します。
type List = C => // nil 引数 ( E => List => C ) => // cons 引数 C // パターンマッチングの結果
任意の型を計算するために使用できるリストは、 を量化する型を持ちます。 のジェネリック [ 明確化が必要 ] Cなリストも、 型引数として
を取ります。 EE
参照
参考文献
^ abc Trancón y Widemann, Baltasar; Parnas, David Lorge (2008). 「表形式表現と全関数型プログラミング」。 Olaf Chitil、Zoltán Horváth、Viktória Zsók (編)。 関数型言語の実装と応用。 第 19 回国際ワークショップ、IFL 2007、ドイツ、フライブルク、2007 年 9 月 27 ~ 29 日 改訂版選択論文。 コンピュータ サイエンスの講義ノート。 第 5083 巻。 pp. 228 ~ 229。 doi :10.1007/978-3-540-85373-2_13。 ISBN 978-3-540-85372-5 。
^ Jansen, Jan Martin; Koopman, Pieter WM; Plasmeijer, Marinus J. (2006). 「データ型とパターンを関数に変換することによる効率的な解釈」。Nilsson, Henrik (編)。 関数 型 プログラミングのトレンド。第 7 巻。ブリストル: Intellect。pp . 73–90。CiteSeerX 10.1.1.73.9841。ISBN 978-1-84150-188-8 。
^ 「先行処理とリストは、単純に型付けされたラムダ計算では表現できません」。 ラムダ計算とラムダ計算機 。okmij.org。
^ アリソン、ロイド。「ラムダ計算整数」。
^ Bauer, Andrej. 「質問に対するAndrejの回答; 「ラムダ計算を使用した負の数と複素数の表現」」
^ 「正確な実数演算」。Haskell 。 2015年3月26日時点のオリジナルよりアーカイブ。
^ Bauer, Andrej (2022年9月26日). 「実数計算ソフトウェア」. GitHub .
^ ピアス、ベンジャミン C. (2002)。 型とプログラミング言語 。MIT プレス 。p. 500。ISBN 978-0-262-16209-8 。
^ Tromp, John (2007). 「14. バイナリラムダ計算と組み合わせ論理」。Calude, Cristian S (編)。 ランダム性と複雑性、ライプニッツからチャイティンまで 。World Scientific。pp. 237–262。ISBN 978-981-4474-39-9 。 PDF: Tromp, John (2014 年 5 月 14 日)。「バイナリ ラムダ計算と組み合わせ論理」 (PDF) 。2017 年 11 月 24 日 閲覧 。
^ Jansen, Jan Martin (2013)。「λ-計算によるプログラミング: チャーチからスコットへ、そしてチャーチからスコットへ」。Achten, Peter、Koopman, Pieter WM (編)。 関数型コードの美しさ - Rinus Plasmeijer の 61 歳の誕生日に捧げるエッセイ 。Lecture Notes in Computer Science。Vol. 8106。Springer。pp. 168–180。doi : 10.1007 /978-3-642-40355-2_12。ISBN 978-3-642-40354-5 。
Stump, A. (2009). 「直接反射メタプログラミング」 (PDF) . High-Order Symb Comput . 22 (2): 115–144. CiteSeerX 10.1.1.489.5018 . doi :10.1007/s10990-007-9022-0. S2CID 16124152.
Cartwright, Robert. 「Church の数字とブール値の説明」 (PDF) 。Comp 311 — レビュー 2 。 ライス大学 。
Kemp, Colin (2007)。「§2.4.1 Church Naturals、§2.4.2 Church Booleans、第 5 章 TFP の導出テクニック」。 実用的な「完全関数型プログラミング」の理論的基礎 (PhD). クイーンズランド大学情報技術・電気工学部. pp. 14–17, 93–145. CiteSeerX 10.1.1.149.3505 . Church やその他の類似のエンコーディングについて、その導出方法や操作方法など、基本原理からすべて説明します。
教会数字のインタラクティブな例
ラムダ計算ライブチュートリアル: ブール代数