ラムダと組み合わせ項を表すデータ型がいくつかあるとします。
data Lam α = Var α -- v
| Abs α (Lam α) -- λv . e1
| App (Lam α) (Lam α) -- e1 e2
deriving (Eq, Show)
infixl 0 :@
data SKI α = V α -- x
| SKI α :@ SKI α -- e1 e2
| I -- I
| K -- K
| S -- S
deriving (Eq, Show)
ラムダ項の自由変数のリストを取得する関数もあります。
fv ∷ Eq α ⇒ Lam α → [α]
fv (Var v) = [v]
fv (Abs x e) = filter (/= x) $ fv e
fv (App e1 e2) = fv e1 ++ fv e2
ラムダ項を組み合わせ項に変換するには、抽象的な排除規則が役立ちます。
convert ∷ Eq α ⇒ Lam α → SKI α
1) T[x] => x
convert (Var x) = V x
2) T[(E₁ E₂)] => (T[E₁] T[E₂])
convert (App e1 e2) = (convert e1) :@ (convert e2)
3) T[λx.E] => (KT[E]) (E で x が自由に発生しない場合)
convert (Abs x e) | x `notElem` fv e = K :@ (convert e)
4) T[λx.x] => I
convert (Abs x (Var y)) = if x == y then I else K :@ V y
5) T[λx.λy.E] => T[λx.T[λy.E]] (x が E に自由に現れる場合)
convert (Abs x (Abs y e)) | x `elem` fv e = convert (Abs x (convert (Abs y e)))
6) T[λx.(E₁ E₂)] => (ST[λx.E₁] T[λx.E₂])
convert (Abs x (App y z)) = S :@ (convert (Abs x y)) :@ (convert (Abs x z))
convert _ = error ":["
この定義は次の理由で有効ではありません5)
:
Couldn't match expected type `Lam α' with actual type `SKI α'
In the return type of a call of `convert'
In the second argument of `Abs', namely `(convert (Abs y e))'
In the first argument of `convert', namely
`(Abs x (convert (Abs y e)))'
だから、私が今持っているものは次のとおりです。
> convert $ Abs "x" $ Abs "y" $ App (Var "y") (Var "x")
*** Exception: :[
私が欲しいのは(私がそれを正しく計算することを願っています):
> convert $ Abs "x" $ Abs "y" $ App (Var "y") (Var "x")
S :@ (S (KS) (S (KK) I)) (S (KK) I)
質問:
ラムダ項と組み合わせ項が異なるタイプの表現を持っている場合、どの5)
ように定式化できますか?