对于类型Door
和Hallway
:
data DoorState :: Type where
Opened :: DoorState
Closed :: DoorState
Locked :: DoorState
deriving (Bounded, Enum, Eq, Ord, Show)
data Door :: DoorState -> Type where
Door :: {material :: String} -> Door s
deriving (Show)
data Hallway :: [DoorState] -> Type where
Origin :: Hallway '[]
Section :: Door ds -> Hallway dsl -> Hallway (ds : dsl)
此appendHallway
的定义有效:
appendHallway :: forall (ds :: DoorState) (dsl :: [DoorState]). Door ds -> Hallway dsl -> Hallway (ds : dsl)
appendHallway d rest = Section d rest
在appendHallway
部分中明确指出ds
和dsl
之间的关系的forall
的定义不起作用:
appendHallway :: forall t (ds :: t) (dsl :: [t]). (t ~ DoorState) => Door ds -> Hallway dsl -> Hallway (ds : dsl)
appendHallway d rest = Section d rest
返回的错误如下:
error:
• Expected kind ‘DoorState’, but ‘ds’ has kind ‘t’
• In the first argument of ‘Door’, namely ‘ds’
In the type signature:
appendHallway :: forall t (ds :: t) (dsl :: [t]).
(t ~ DoorState) => Door ds -> Hallway dsl -> Hallway (ds : dsl)
|
351 | appendHallway :: forall t (ds :: t) (dsl :: [t]). (t ~ DoorState) => Door ds -> Hallway dsl -> Hallway (ds : dsl)
| ^^
上面的示例可能有些人为,但是在某些情况下,指示较高种类的类型变量之间的关系将是有帮助的,甚至是必要的。此错误是对GHC当前版本的限制吗?还是在GHC的将来版本中,上述错误也是荒谬的?是否有另一种方式可以表达GHC会接受的ds
和dsl
之间的关系?
答案 0 :(得分:2)
Haskell具有用于计算,类型和种类的独立命名空间。当你写
forall (ds :: t). ...
变量t
是种类级别的变量,但是在您编写时
t ~ DoorState => ...
变量t
是类型级别的变量t
,这是一个完全不相关的变量。确实,所有类型平等仅在类型级别上。据我所知,在目前的GHC Haskell中根本没有任何形式可以将种类相等表示为约束。
答案 1 :(得分:2)
您写的东西确实是胡说八道。 =>
的LHS的约束仅在值级别上存在,就像->
的LHS的约束仅在值级别上一样。更具体地说(尽管这是一个微弱的内存),a ~ b
的一个实例在其中包含基本类型为a ~# b
的实例(以相同的方式data Showable = forall s. Show s => Showable s
持有一种类型的对象) Type
)。您实际上需要完成a ~# b
的所有工作,但需要解开a ~ b
的包装才能完成。但是,您无法以一种无法谈论a ~ b
中的DoorState
的方式谈论类型中的值级别参数DoorState -> Door _can'tTalkAboutTheDoorState
。
您可以做的是这个。定义
type family Cast (x :: (a :: Type)) :: (b :: Type) where
Cast x = x
-- this seems strange, but realize the equation is actually
-- Cast @a @a (x :: a) = (x :: a)
-- Cast-ing some type from one kind to another only goes through
-- when they're actually the same kind
-- can make a, b, or both explicit instead of implicit
然后
appendHallway :: forall t (ds :: t) (dsl :: [t]).
(t ~ DoorState) =>
Door (Cast ds) ->
Hallway (Cast dsl) ->
Hallway (Cast ds : Cast dsl)
appendHallway d rest = Section d rest
只要知道t ~ DoorState
,类型族应用程序Cast @t @DoorState ds
和Cast @[t] @[DoorState] dsl
就会分别减少为ds
和dsl
。