“自由”类型变量由类型同义词

时间:2016-03-25 20:57:02

标签: haskell types

给出一个班级

class MonadSignal m sigs | m -> sigs where ...

和一个班级

class CanSignal sigs sigs' where ...

我想定义一个像这样的类型同义词

type MonadSignal' sigs m = (MonadSignal m sigs', CanSignal sigs sigs')

此处sigs'类型同义词的头部中未提及MonadSignal'变量,但它仅用于连接第一个和第二个约束,并且由m唯一确定在头脑中提到了

通常情况下,我认为我可以在RHS上forall,但由于这只是一个Constraint同义词,因此该变量没有实际的正文。

可以在这做任何事吗? (除了将变量放在头部并在实际使用同义词时给出错误的印象,它是一个实际的“变量”)

3 个答案:

答案 0 :(得分:3)

这不是保守的改变,但一种解决方案是从功能依赖转换为类型系列。你可以建立一个相关的家庭

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
module TypeFamily where

class Monad m => MonadSignal m where
  type Sig m :: *
  make :: m sig

class CanSignal sigs sigs' where

type MonadSignal' sigs m = (MonadSignal m, CanSignal sigs (Sig m))

它可能不如为两者使用多参数类型那么漂亮,但它在表现力方面应该同样相同而且你不必担心这样做"传递闭包&#34 ;有点像。

答案 1 :(得分:2)

不幸的是,我相信如果你坚持做一个fundep,你必须给出错误的印象(如果你接受一个稍微不同的方法,请参阅这个答案的底部)。我简单地想过,也许你可以让MonadSignal'成为一个类,但你不能给它你想要的超类约束。你可以通过一种或多种Dict方法真正明确来弥补这一点,但那时你的生活将会很艰难。

虽然这不相关,但最好定义

class MonadSignal sigs m | m -> sigs

交换参数的顺序,这会让您获得更有用的部分应用程序,并使GeneralizedNewtypeDeriving适用于您的班级。

还有另一种使用类型系列的方法,基于类型系列方面的fundep的合法实现:

class (sigs ~ Sigs m) => MonadSignal sigs m where
  type Sigs m :: * -- Or appropriate kind
  ...

type MonadSignal' sigs m = (MonadSignal (Sigs m) m, CanSignal sigs (Sigs m))

答案 2 :(得分:1)

您可以使用类替换类型同义词:

class MonadSignal' sigs (m :: * -> *)
instance (MonadSignal m sigs', CanSignal sigs sigs') => MonadSignal' sigs m 

在类实例中,类型变量sigs'不会出现在类头中, 所以你必须使用{-# LANGUAGE UndecidableInstances #-}才能工作。虽然我不相信这个课程实际上可以导致不终止。