【问题标题】:Adventures with the untyped lambda calculus无类型 lambda 演算的冒险
【发布时间】: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


    【解决方案1】:

    好的,我找到了一个解决方案:

    上面的代码有Term x,由R的结果类型参数化。与其这样做(并吓坏类型检查器),不如构造一些类型Value,它可以表示您想要返回的每种结果类型。现在我们有

    data Term = F (Term -> Term) | R (Term -> Value)
    

    将所有可能的结果类型折叠成一个不透明的Value 类型后,我们就可以开始工作了。

    具体来说,我选择的类型是

    data Value = V Int [Term]
    

    所以 Value 是一个 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"
    

    同样,您可以像这样对列表进行编码和解码:

    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"
    

    当然,您必须猜测您需要应用哪些解码功能。但这就是适合您的无类型 lambda 演算!

    【讨论】:

    • 我认为data Term = Lam (Term -> Term) | App Term Term | Var Int 会是一个更直接的解决方案。
    • @András Kovács,你的意思是Lam Term
    • @user3237465 不,我的意思是Term -> Term。我们可以像上面那样做一个similar answer,但IMO更清洁。
    • @András Kovács,啊,现在看。这很像来自the shortest beta-normalizerquote(其他作者将此函数称为readback)。
    【解决方案2】:

    这不是答案,但评论太严格了。

    R Just 是错误类型的,因为它的类型是递归的,但我们总是可以将这种类型级别的递归包装在一个数据类型中:

    data Fix2 g f = Fix2 { run :: g (f (Fix2 g f)) }
    

    Fix2 可以用Fix 和类型构造函数的组合来表示,但我不想让事情复杂化。

    那么我们可以将decode定义为

    decode :: Term (Fix2 Maybe Term) -> Maybe (Term (Fix2 Maybe Term))
    decode tmx = run $ out $ tmx ! R (Fix2 . const Nothing) ! R (Fix2 . Just)
    

    一些测试:

    isSomething :: Term (Fix2 Maybe Term) -> Bool
    isSomething = isJust . decode
    
    i = F id
    
    main = do
        print $ isSomething (something ! i) -- True
        print $ isSomething  nothing        -- False
    

    但显然Term (Fix2 Maybe Term)Term a 相差甚远。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-25
      • 2019-03-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多