堆栈!是否有可能在现代Haskell中定义Omega组合器(λx.xx)?我想,Haskell98的类型系统旨在使这样的事情变得不可能,但现代扩展呢?
答案 0 :(得分:8)
你不能直接在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"
答案 1 :(得分:6)
不,但有点儿。这里需要注意的是Haskell在newtype
声明中支持不受限制的递归。通过Haskell的语义,newtype
是被定义的类型与其实现类型之间的同构。例如,这个定义:
newtype Identity a = Identity { runIdentity :: a }
...断言类型Identity a
和a
是同构的。根据定义,构造函数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)))
答案 2 :(得分:5)
嗯,你可以定义:
{-# LANGUAGE Rank2Types #-}
omega :: (forall a . a) -> b
omega x = x x
然而这几乎没用,因为唯一可以作为参数传递的值是undefined
,所以你根本不能将它用作组合器。即使omega omega
无法输入检查。
问题在于,x x
要进行类型检查,您必须键入x
类型T = t -> s
,其中t
与{{1}结合使用(以便您可以将T
传递给自己)。但这基本上意味着x
必须是一个类型变量,并且参数必须是完全多态的,这使得函数无用。
答案 3 :(得分:0)
那么,
omega :: a -> a
omega x = unsafeCoerce x x
甚至
omega :: a -> IO a
omega x = do
putStrLn "Why are you doing this to me?"
unsafeCoerce x x
main = omega omega
无限期打印"你为什么这样对我?"。