【问题标题】:Is it possible to define Omega combinator (λx.xx) in modern Haskell?是否可以在现代 Haskell 中定义 Omega 组合子(λx.xx)?
【发布时间】:2015-11-05 13:37:41
【问题描述】:

堆栈!是否可以在现代 Haskell 中定义 Omega 组合子(λx.xx)?我想,Haskell98 的类型系统旨在使这样的事情变得不可能,但是现代扩展呢?

【问题讨论】:

    标签: haskell lambda-calculus


    【解决方案1】:

    您不能直接在 Haskell 中表示 omega。很少有类型系统可以代表自我应用程序,而 Haskell 的类型系统不是其中之一。但是您可以对无类型的 lambda 演算进行编码并模拟 omega 和 self 应用程序,如下所示:

    data Scott = Scott { apply :: Scott -> Scott }
    
    omega = Scott $ \x -> apply x x
    

    现在您可以说apply omega omega 并获得非终止计算。如果你想在 GHCi 中尝试一下,你可能需要下面的 Show 实例

    instance Show Scott where
      show (Scott _) = "Scott"
    

    【讨论】:

    • 这种递归类型会触发GHC inliner bug,它会阻止优化器在编译时终止。可能需要一些NOINLINE pragma。 (仅使用 GHCi 很容易将编译时的非终止与运行时混淆)。
    • @chi,GHCi 没有内联任何东西。
    【解决方案2】:

    不,但有点。这里要欣赏的是,Haskell 在newtype 声明中支持无限制递归。根据 Haskell 的语义,newtype 是定义的类型与其实现类型之间的同构。所以例如这个定义:

    newtype Identity a = Identity { runIdentity :: a }
    

    ...断言Identity aa 类型是同构的。根据定义,构造函数Identity :: a -> Identity a 和观察者runIdentity :: Identity a -> a 是相反的。

    所以从 svenningsson 的答案中借用 Scott 类型名称,定义如下:

    newtype Scott = Scott { apply :: Scott -> Scott }
    

    ...断言Scott 类型与Scott -> Scott 同构。因此,虽然您不能将 Scott 直接应用于自身,但您可以使用同构来获取其 Scott -> Scott 对应项并将其应用于原始对象:

    omega :: Scott -> Scott
    omega x = apply x x
    

    或者稍微有趣一点:

    omega' :: (Scott -> Scott) -> Scott
    omega' f = f (Scott f)
    

    ...这是一个固定点组合器类型!这个技巧可以适应在 Haskell 中编写 Y 组合器的一个版本:

    module Fix where
    
    newtype Scott a = Scott { apply :: Scott a -> a }
    
    -- | This version of 'fix' is fundamentally the Y combinator, but using the
    -- 'Scott' type to get around Haskell's prohibition on self-application (see
    -- the expression @apply x x@, which is @x@ applied to itself).  Example:
    --
    -- >>> take 15 $ fix ([1..10]++)
    -- [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5]
    fix :: (a -> a) -> a
    fix f = (\x -> f (apply x x)) (Scott (\x -> f (apply x x)))
    

    【讨论】:

      【解决方案3】:

      嗯,你可以定义:

      {-# LANGUAGE Rank2Types #-}
      
      omega :: (forall a . a) -> b
      omega x = x x
      

      然而这几乎没有用,因为唯一可以作为参数传递的值是undefined,所以你根本不能将它用作组合子。甚至omega omega 也无法进行类型检查。

      要注意的是,为了让 x x 进行类型检查,您必须输入 x 类型为 T = t -> s 并且 tT 统一(这样您就可以将 x 传递给本身)。但这基本上意味着t 必须是类型变量,并且参数必须是完全多态的,从而使函数无用。

      【讨论】:

      • 使用此类型签名omega :: (forall a. a -> f a) -> f (a -> f a),您可以定义purePure :: Applicative f => f (a -> f a); purePure = omega pure
      猜你喜欢
      • 2020-03-24
      • 1970-01-01
      • 1970-01-01
      • 2015-07-30
      • 2011-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-20
      相关资源
      最近更新 更多