是否可以使用类型类约束的类型同义词?
随意更改标题,我只是没有足够的经验知道真正发生了什么。
所以,我在这个基础上松散地编写了一个程序,并且写了这个程序(因为它是原始的)
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]
像以前一样type Matrix a = [Row a]
的类型同义词,则会导致错误。
所以我的问题是这样的:
在它的定义中是否有可能具有类型类型约束的类型同义词?
这个问题背后的目标是否可以通过其他方式实现?
类型变量上的约束不能成为任何Haskell类型签名的一部分。
这似乎有点荒谬的说法:“什么是(==) :: Eq a => a -> a -> a
然后?”
答案是a
实际上并不存在,在几乎相同的方式没有真正的x
定义中的fx = x * log x
。 你已经确定在定义该函数时使用了x
符号,但实际上它只是在lambda抽象中使用的本地工具。 从外部访问这个符号绝对没有办法,事实上,编译器甚至不需要在机器代码中生成与x
相对应的任何东西 - 它可能只是被优化掉了。
事实上,任何多态签名基本上都可以读为接受类型变量的lambda表达式; 各种写作风格:
(==) :: forall a . Eq a => a -> a -> a
(==) :: ∀ a . Eq a => a -> a -> a
(==) :: Λa. {Eq a} -> a -> a -> a
这被称为系统F.
请注意,是不是真的在此签名“约束”,而是一个额外的参数:该Eq
-class字典。
通常你想避免在你的类型同义词中有约束,除非它真的有必要。 例如,从containers
取得Data.Set
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
类型同义词中存在约束,但通常是不明智的。 最好为需要它们的函数编写约束。