14

显然有点心不在焉,我写如下内容:

{-# LANGUAGE ConstraintKinds     #-}
{-# LANGUAGE TypeFamilies        #-}

class Foo f where
  type Bar f :: *
  retbar :: Bar f -> IO f

type Baz f = (Foo f, Eq f)

  -- WithBar :: * -> (*->Constraint) -> * -> Constraint
type WithBar b c f = (c f, Bar f ~ b)

instance Foo () where
  type Bar () = ()
  retbar = return

naim :: WithBar () Baz u => IO u  -- why can I do this?
naim = retbar ()

main = naim :: IO ()

只有在成功编译之后,我才意识到这实际上不应该Baz工作:被定义为带有一个参数的类型同义词,但在这里我使用它没有直接参数。Type synonym ‘Baz’ should have 1 argument, but has been given none当我尝试这样的事情时,通常 GHC 会对我吠叫。

现在,不要误会我的意思:我真的很希望能够写出它,并且很容易看出它在这个特定示例中是如何工作的(简单WithBar的内联会产生签名naim :: (Foo u, Bar u ~ ()) => IO u,这当然很好),但是我不明白为什么它在这里实际上是这样工作的。ghc-7.8.2允许这样做可能只是一个错误吗?

4

3 回答 3

9

您的文件在 GHC 7.8 中编译,但在 GHC 7.10 中出现错误:

类型同义词“Baz”应该有 1 个参数,但没有给出

在 'naim' 的类型签名中: naim :: WithBar () Baz u => IO u

添加-XLiberalTypeSynonyms修复错误。因此,这是 7.8 中的一个错误。

于 2015-04-05T22:55:29.423 回答
5

扩展应启用部分应用程序LiberalTypeSynonyms

基本上,这会推迟类型同义词的大多数一致性检查,直到它们被扩展,所以你的“内联”解释本质上是正确的想法。

但是,这里奇怪的是,您的模块中的扩展并未暗示此扩展。我刚刚测试过,部分应用程序通常不适用于 just ConstraintKinds,TypeFamiliesPolyKinds. (我添加了后者,因为扩展之前检查了种类,否则我的测试类型会被推断为错误的类型。)

不过,您的文件在 GHCi 7.8.3 中对我来说加载得很好。也许这某种错误,即使有一个扩展使其正确合法。

于 2015-04-05T22:37:24.780 回答
4

我不知道官方的规则是什么,但是这种事情在最左外类型同义词扩展策略的基础上工作似乎是合理的。唯一重要的是类型同义词可以在其他类型检查发生之前在单独的终止阶段处理。我不知道您是否打算使用部分应用的类型同义词 F 作为另一个类型同义词 G 的参数,只要 G 确保 F 接收其缺少的参数,但这肯定与类型同义词的想法一致是一种肤浅的方便。

于 2015-04-05T22:06:51.290 回答