【发布时间】:2015-09-29 15:18:47
【问题描述】:
我们偶尔会有人询问如何在 Haskell 中实现无类型 lambda 演算。 [当然,我现在无法找到这些问题中的任何一个,但我确定我已经看到了! >
做这样的事情很简单
i = \ x -> x
k = \ x y -> x
s = \ f g x -> (f x) (g x)
这非常有效。但是,一旦您尝试做类似的事情
s i i
类型检查器正确地抱怨无限类型。基本上,无类型 lambda 演算中的 everything 都是一个函数——这基本上意味着所有函数都有 infinite arity。但是 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)
这完美地工作,并允许构造和执行任意 lambda 表达式。例如,我们可以轻松地构建一个函数来将 Int 转换为 Church 数字:
zero = k ! i
succ = s ! (s ! (k ! s) ! k)
encode 0 = zero
encode n = succ ! (encode $ n-1)
再次,这非常有效。
现在写一个解码函数。
……是的,祝你好运!问题是,我们可以创建任意 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)
我现在可以做类似的事情
decode :: Term Int -> Int
decode ti = out $ ti ! R (\ tx -> 1 + out tx) ! R (\ tx -> 0)
这对教堂布尔和教堂数字非常有用。
当我开始尝试做任何高级别的事情时,事情开始变得非常糟糕。在丢弃所有类型信息以实现 untyped 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
这不是:
decode :: Term x -> Maybe (Term x)
decode tmx = out $ tmx ! R (\ tx -> Nothing) ! R (\ tx -> Just tx)
我已经尝试了十几种轻微的变化;他们都没有类型检查。不是我不明白它为什么会失败,而是我想不出任何方法让它成功。 (特别是,R Just 显然是错误的类型。)
这几乎就像我想要一个函数forall x y. Term x -> Term y。因为,对于 纯 无类型的术语,这应该始终是可能的。只有涉及R 的条款不起作用。但我不知道如何在 Haskell 类型系统中表达它。
(例如,尝试将F的类型更改为forall x. Term x -> Term x。现在k的定义是错误类型的,因为内部F $ \ y -> x实际上不能返回any类型,但只有x的[现已修复]类型。)
比我聪明的人有更好的主意吗?
【问题讨论】:
标签: haskell types lambda-calculus