Haskell:ConstraintKinds 和 TypeSynonymInstances 之间的交互
Haskell: interaction between ConstraintKinds, and TypeSynonymInstances
在使用 ConstraintKinds 和 TypeSynonymInstances 时尝试使用 GHC 8.6.1 编译小型 Haskell 文件时出现意外错误。
我想制作一个 class 以 class 作为参数,并且我想在编写实例时使用别名。这是代码:
{-# LANGUAGE ConstraintKinds, KindSignatures, TypeSynonymInstances #-}
module TypeAlias where
import Data.Kind
class Foo a
class Bar a
class Baz (c :: * -> Constraint)
instance Baz Foo -- compiles
instance Baz Bar -- compiles
type FooBar a = (Foo a, Bar a) -- compiles
instance Baz FooBar -- fails!
-- TypeAlias.hs:17:10-19: error:
-- • The type synonym ‘FooBar’ should have 1 argument, but has been given none
-- • In the instance declaration for ‘Baz FooBar’
-- |
-- 17 | instance Baz FooBar
-- | ^^^^^^^^^^
这个错误令人惊讶,因为据我所知,FooBar
具有预期的类型,即 * -> Constraint
,但编译器说应该为其提供一个参数。
是否可以像我在这里尝试的那样在实例声明中使用约束别名?如果是这样,我如何理解看似矛盾的错误消息?
(我知道我可以简单地将 FooBar
声明为 class 而不是别名,但我真的不想这样做,因为我也想要一个实例,那时我必须拉进来UndecidableInstances
。)
原来,Ed Kmett 在一年前回答了我的问题。我不能用类型别名来做到这一点,但使用 UndecidableInstances
对于这种特殊情况应该是良性的:
https://www.reddit.com/r/haskell/comments/5zjwym/when_is_undecidableinstances_okay_to_use/
以下是 Kmett 可能建议修正上述示例的方法:
{-# LANGUAGE ConstraintKinds, FlexibleInstances,
KindSignatures, UndecidableInstances #-}
module NotTypeAlias where
import Data.Kind
class Foo a
class Bar a
class Baz (c :: * -> Constraint)
instance Baz Foo -- compiles
instance Baz Bar -- compiles
class (Foo a, Bar a) => FooBar a
instance (Foo a, Bar a) => FooBar a -- compiles
instance Baz FooBar -- compiles
Kmett 认为,如果我们提供的 FooBar
实例是范围内的 sole 实例,则类型检查器不会陷入无限循环我们使用 UndecidableInstances
。我很满意他的话。
在使用 ConstraintKinds 和 TypeSynonymInstances 时尝试使用 GHC 8.6.1 编译小型 Haskell 文件时出现意外错误。
我想制作一个 class 以 class 作为参数,并且我想在编写实例时使用别名。这是代码:
{-# LANGUAGE ConstraintKinds, KindSignatures, TypeSynonymInstances #-}
module TypeAlias where
import Data.Kind
class Foo a
class Bar a
class Baz (c :: * -> Constraint)
instance Baz Foo -- compiles
instance Baz Bar -- compiles
type FooBar a = (Foo a, Bar a) -- compiles
instance Baz FooBar -- fails!
-- TypeAlias.hs:17:10-19: error:
-- • The type synonym ‘FooBar’ should have 1 argument, but has been given none
-- • In the instance declaration for ‘Baz FooBar’
-- |
-- 17 | instance Baz FooBar
-- | ^^^^^^^^^^
这个错误令人惊讶,因为据我所知,FooBar
具有预期的类型,即 * -> Constraint
,但编译器说应该为其提供一个参数。
是否可以像我在这里尝试的那样在实例声明中使用约束别名?如果是这样,我如何理解看似矛盾的错误消息?
(我知道我可以简单地将 FooBar
声明为 class 而不是别名,但我真的不想这样做,因为我也想要一个实例,那时我必须拉进来UndecidableInstances
。)
原来,Ed Kmett 在一年前回答了我的问题。我不能用类型别名来做到这一点,但使用 UndecidableInstances
对于这种特殊情况应该是良性的:
https://www.reddit.com/r/haskell/comments/5zjwym/when_is_undecidableinstances_okay_to_use/
以下是 Kmett 可能建议修正上述示例的方法:
{-# LANGUAGE ConstraintKinds, FlexibleInstances,
KindSignatures, UndecidableInstances #-}
module NotTypeAlias where
import Data.Kind
class Foo a
class Bar a
class Baz (c :: * -> Constraint)
instance Baz Foo -- compiles
instance Baz Bar -- compiles
class (Foo a, Bar a) => FooBar a
instance (Foo a, Bar a) => FooBar a -- compiles
instance Baz FooBar -- compiles
Kmett 认为,如果我们提供的 FooBar
实例是范围内的 sole 实例,则类型检查器不会陷入无限循环我们使用 UndecidableInstances
。我很满意他的话。