具有类型类约束的类型同义词是否可行?

时间:2014-06-15 18:35:58

标签: haskell typeclass

随意更改标题,我只是没有足够的经验知道真正发生的事情。

所以,我基于this松散地编写了一个程序,并写了这个(就像它在原文中一样)

type Row a    = [a]
type Matrix a = [Row a]

没什么特别的。 但是,我发现自己编写了几个类似这样的函数:

Eq a => Row a -> ...

所以我想也许我可以将这个约束写入类型同义词定义中,因为在我看来它不应该那么复杂,对吧?如果编译器可以在函数中使用它,它应该作为类型同义词。这里没有部分申请,也没有任何或某种诡计(对我来说)。

所以我尝试了这个:

type Row a = Eq a => [a]

这不起作用,编译器建议启用RankNTypes。该选项使其编译,但函数仍然要求我将Eq a =>留在其类型声明中。顺便说一句,如果我像以前一样尝试使用类似type Matrix a = [Row a]的同义词,则会导致错误。

所以我的问题是:

  • 是否可以在其定义中使用带类型类约束的类型同义词?

    • 如果没有,为什么?
  • 这个问题背后的目标是否可以通过其他方式实现?

2 个答案:

答案 0 :(得分:3)

对类型变量的约束不能是任何Haskell类型签名的一部分。

这似乎有点荒谬的陈述:“那么(==) :: Eq a => a -> a -> a是什么?”

答案是a并不存在,就像定义x中实际上没有f x = x * log x一样。你确定在定义该函数时使用了x符号,但实际上它只是lambda抽象中使用的本地工具。绝对无法从外部访问此符号,实际上并不要求编译器甚至在机器代码中生成对应x的任何内容 - 它可能只是被优化掉了。 / p>

实际上,任何多态签名基本上都可以读作接受类型变量的lambda表达式;各种写作风格:

(==) :: forall a . Eq a => a -> a -> a
(==) :: ∀ a . Eq a => a -> a -> a
(==) :: Λa. {Eq a} -> a -> a -> a

这称为System F

请注意,此签名中并没有真正的“约束”,而是一个额外的参数Eq - 类字典。

答案 1 :(得分:1)

通常您希望避免在类型同义词中使用约束,除非它确实是必要的。例如,从Data.Set获取containers API。

Data.Set中的许多操作都要求集合的元素为Ord的实例,因为Set在内部实现为二叉树。 memberinsert都需要Ord

member :: Ord a => a -> Set a -> Bool
insert :: Ord a => a -> Set a -> Set a

然而Set的定义根本没有提到Ord

这是因为Set 上的某些操作不需要Ord个实例,例如sizenull

size :: Set a -> Int
null :: Set a -> Bool

如果类型类约束是Set定义的一部分,那么这些函数必须包含约束,即使它不是必需的。

所以是的,可以使用RankNTypes在类型同义词中设置约束,但它通常是不明智的。最好为需要它们的函数编写约束。