【问题标题】:Is it possible to have forgetful type synonyms in Haskell?在 Haskell 中是否有可能有健忘类型的同义词?
【发布时间】:2015-04-16 22:13:26
【问题描述】:

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

data Foo p a b = Bar a b

是否有任何破解方法可以编写类型同义词 Baz 使得 Baz a bFoo p a b 对于我忘记的一些 p

你不能这样做:

type 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)

【问题讨论】:

标签: haskell ghc existential-type type-synonyms


【解决方案1】:

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

【讨论】:

  • 在很多情况下,您可以通过发明新的类型变量来做到这一点。好主意,部分类型签名可能会覆盖另一个,并且可以让您不必编造唯一的名称,谢谢。
【解决方案2】:

使用类型同义词并不能真正可靠地做到这一点。您需要存在类型或 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)

第三种方法,你已经尝试过并且(我被告知)效果不太好:类型同义词 + 谓词类型(在许多情况下需要 forall 同义词作为类型参数出现)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多