在Haskell中有可能有健忘的类型同义词吗?

时间:2015-04-16 22:13:27

标签: haskell ghc existential-type type-synonyms

如果我有一个带有幻像参数的类型,我有时只关心它,比如这个:

data Foo p a b = Bar a b

是否有任何黑客方式来编写类型同义词BazBaz a b对于我遗忘的Foo p a b ptype Baz a b = Foo p a b

你无法做到:

type Baz a b = forall p.Foo p a b

虽然你可以做(​​有适当的扩展名):

Foo P1 a b

这似乎不是我想要的,因为我无法将Baz a b类型的值转换为data Baz' a b = forall p.Baz' (Foo p a b) 类型,并显示有关&#34的消息;刚性类型变量"。

您是否需要另一层构造器来实现此效果,如下所示?你能简单解释一下原因吗?

{{1}}

2 个答案:

答案 0 :(得分:10)

目前没有办法将此作为类型同义词。但是,如果您有GHC 7.10,则可以打开PartialTypeSignatures扩展名并改为编写Foo _ a b。使用-fno-warn-partial-type-signatures要求GHC不要以这种方式警告您所留下的每个漏洞。

答案 1 :(得分:6)

使用类型同义词无法可靠地完成此操作。您需要存在类型或rank-n类型。

问题在于Haskell允许类型同义词完全是可互替的。即,当您定义type Baz a b = Foo p a b时,在您拥有Foo p a b的每个上下文中,您将被允许使用Baz a b,反之亦然。例如,如果你有这种类型的函数:

f1 :: Foo Something a b -> Whatever Something b a

然后由于可替代性,它与此类型相同:

f1 :: Baz a b -> Whatever Something b a

就这样:

f1 :: Foo p a b -> Whatever Something b a

...然后你可以专注于此:

f1 :: Foo SomethingElse a b -> Whatever Something b a

那么,你能做什么?一种是定义存在的包装类型:

{-# LANGUAGE ExistentialTypes #-}

data Baz a b = forall p. Baz (Foo p a b)

做同样事情的另类方式:

{-# LANGUAGE GADTs #-}

data Baz a b where
     Baz :: Foo p a b -> Baz a b

你可以采取的第二种方式:rank-n类型和延续传递风格:

{-# LANGUAGE RankNTypes #-}

-- To consume one of these, you pass a "callback" function to `runBaz`,
-- which is not allowed to restrict the type variable `p`.
newtype Baz a b = Baz { runBaz :: forall p r. (Foo p a b -> r) -> r }

makeBaz :: Foo p a -> Baz a b
makeBaz foo = Baz ($foo)

你尝试过的第三种方式(我告诉过)并不能很好地工作:输入同义词+ impredicative类型(需要获得forall个同义词在许多情况下作为类型参数。)