{-# LANGUAGE MultiParamTypeClasses #-}
class Coerce a b where coerce :: a -> b
instance Coerce a a where coerce a = a
Run Code Online (Sandbox Code Playgroud)
现在,这不起作用:coerce 0 :: Int
但是如果实例被替换为this,则表达式有效:
instance a ~ b => Coerce a b where coerce x = x
Run Code Online (Sandbox Code Playgroud)
为什么?
Ben*_*Ben 10
我可以告诉你为什么第一个不起作用.
Coerce
可以为任何可能的类型对定义.coerce 0 :: Int
被解析为(coerce 0) :: Int
.所以你已经用类型注释修复了b
in coerce :: a -> b
,但不是a
.
数字文字是多态的,因此0
有类型Num a => a
.那不行; 没有实例匹配Coerce a Int
.有可能是Coerce Double Int
,Coerce Complex Int
等,所以明知b
是Int
不足以推断这0
是一个Int
.我们需要说coerce (0 :: Int) :: Int
修复两个类型参数.
我相信第二个可行,因为实例声明的约束不用于帮助解析类型类.instance a ~ b => Coerce a b
完全匹配就像你写的那样instance Coerce a b
.也就是说,这是最常见的实例(出于类型类解析的目的),它可以很好地匹配任何可能的调用coerce
(因此你不能写任何其他非重叠的实例).该a ~ b
约束仅被施加之后被选择的实例.
由于你有一个匹配任何东西的实例,所以选择一个实例没有问题coerce 0 :: Int
,即使我们仍然有同样的问题,不知道它是什么类型0
.但是在实例选择之后,我们现在有了额外的约束a ~ Int
,它允许将明确的类型分配给所有东西.