Mat*_*hid 12 haskell types lambda-calculus
我们偶尔会有人询问在Haskell中实现无类型的lambda演算.[当然,我现在找不到任何这些问题,但我确定我已经看过了!]只是为了咯咯笑,我以为我会花一些时间玩这个.
做一些像这样的事情是微不足道的
i = \ x -> x
k = \ x y -> x
s = \ f g x -> (f x) (g x)
Run Code Online (Sandbox Code Playgroud)
这非常有效.但是,只要你尝试做类似的事情
s i i
Run Code Online (Sandbox Code Playgroud)
类型检查员正确地抱怨无限类型.基本上,无类型lambda演算中的所有东西都是一个函数 - 这实际上意味着所有函数都具有无限的特征.但是Haskell只允许有限度的函数.(因为,真的,为什么你想要无限的灵魂?)
好吧,事实证明我们可以很容易地采取这种限制:
data Term = T (Term -> Term)
T f ! x = f x
i = T $ \ x -> x
k = T $ \ x -> T $ \ y -> x
s = T $ \ f -> T $ \ g -> T $ \ x -> (f ! x) ! (g ! x)
Run Code Online (Sandbox Code Playgroud)
这非常有效,并且允许构造和执行任意lambda表达式.例如,我们可以轻松地构建一个函数来转换Int成一个教会数字:
zero = k ! i
succ = s ! (s ! (k ! s) ! k)
encode 0 = zero
encode n = succ ! (encode $ n-1)
Run Code Online (Sandbox Code Playgroud)
再次,这完美地工作.
现在写一个解码函数.
...是的,祝你好运!麻烦的是,我们可以创建任意的lambda术语,但我们无法以任何方式检查它们.所以我们需要添加一些方法来做到这一点.
到目前为止,我提出的最好的想法是这样的:
data Term x = F (Term x -> Term x) | R (Term x -> x)
F f ! x = f x
R f ! x = R $ \ _ -> f x
out :: Term x -> x
out (R f) = f (error "mu")
out (F _) = (error "nu")
i = F $ \ x -> x
k = F $ \ x -> F $ \ y -> x
s = F $ \ f -> F $ \ g -> F $ \ x -> (f ! x) ! (g ! x)
Run Code Online (Sandbox Code Playgroud)
我现在可以做点什么了
decode :: Term Int -> Int
decode ti = out $ ti ! R (\ tx -> 1 + out tx) ! R (\ tx -> 0)
Run Code Online (Sandbox Code Playgroud)
这适用于Church Bools和Church数字.
当我开始尝试做任何高阶事时,事情开始变得非常糟糕.抛弃所有类型信息来实现无类型的 lambda演算,我现在正在努力说服类型检查器让我做我想做的事情.
这有效:
something = F $ \ x -> F $ \ n -> F $ \ s -> s ! x
nothing = F $ \ n -> F $ \ s -> n
encode :: Maybe x -> Term x
encode (Nothing) = nothing
encode (Just x) = something ! x
Run Code Online (Sandbox Code Playgroud)
这不是:
decode :: Term x -> Maybe (Term x)
decode tmx = out $ tmx ! R (\ tx -> Nothing) ! R (\ tx -> Just tx)
Run Code Online (Sandbox Code Playgroud)
我已经尝试了十几个微小的变化; 没有一种类型检查.并不是我不明白它为什么会失败,而是我无法弄清楚它取得成功的方法.(特别是,R Just显然是不合格的.)
这几乎就像我想要一个功能forall x y. Term x -> Term y.因为,对于纯粹的无类型术语,这应该始终是可能的.这是唯一涉及R无效的条款.但我无法弄清楚如何在Haskell类型系统中表达这一点.
(例如,尝试更改Fto 的类型forall x. Term x -> Term x.现在定义k为ill-typed,因为内部F $ \ y -> x实际上不能返回任何类型,而只是[now fixed]类型x.)
任何比我聪明的人都有更好的主意吗?
好的,我找到了一个解决方案:
上面的代码Term x由 的结果类型参数化R。与其这样做(并吓坏类型检查器),不如构造一些Value可以表示您想要返回的每种结果类型的类型。现在我们有
data Term = F (Term -> Term) | R (Term -> Value)
Run Code Online (Sandbox Code Playgroud)
将所有可能的结果类型折叠成一个单一的不透明Value类型后,我们就可以开始工作了。
具体来说,我选择的类型是
data Value = V Int [Term]
Run Code Online (Sandbox Code Playgroud)
所以 aValue是一个Int代表 ADT 值的构造函数,后跟一个代表该构造函数Term的每个字段。有了这个定义,我们终于可以做
decode :: Term -> Maybe Term
decode tmx =
case tmx ! R (\ _ -> V 0 []) ! R (\ tx -> V 1 [tx]) of
V 0 [] -> Nothing
V 1 [tx] -> Just tx
_ -> error "not a Maybe"
Run Code Online (Sandbox Code Playgroud)
同样,您可以像这样对列表进行编码和解码:
null = F $ \ n -> F $ \ c -> n
cons = F $ \ x -> n $ \ xs -> F $ \ n -> F $ \ c -> c ! x ! xs
encode :: [Term] -> Term
encode ( []) = null
encode (x:xs) = cons ! x ! encode xs
decode :: Term -> [Term]
decode txs =
case out $ txs ! R (\ txs -> V 0 []) ! F (\ tx -> R $ \ txs -> V 1 [tx, txs]) of
V 0 [] -> []
V 1 [tx, txs] -> tx : decode txs
_ -> error "not a list"
Run Code Online (Sandbox Code Playgroud)
当然,您必须猜测您需要应用哪个解码函数。但那是适合您的无类型 lambda 演算!