随意更改标题,我只是没有足够的经验知道真正发生的事情。
所以,我基于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]
的同义词,则会导致错误。
所以我的问题是:
是否可以在其定义中使用带类型类约束的类型同义词?
这个问题背后的目标是否可以通过其他方式实现?
答案 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
在内部实现为二叉树。 member
或insert
都需要Ord
member :: Ord a => a -> Set a -> Bool
insert :: Ord a => a -> Set a -> Set a
然而Set
的定义根本没有提到Ord
。
这是因为Set
上的某些操作不需要Ord
个实例,例如size
或null
。
size :: Set a -> Int
null :: Set a -> Bool
如果类型类约束是Set
定义的一部分,那么这些函数必须包含约束,即使它不是必需的。
所以是的,可以使用RankNTypes
在类型同义词中设置约束,但它通常是不明智的。最好为需要它们的函数编写约束。