{-# LANGUAGE MultiParamTypeClasses #-}
class Coerce a b where coerce :: a -> b
instance Coerce a a where coerce a = a
现在,这将不起作用:
coerce 0 :: Int
但是,如果用该实例替换实例,则该表达式有效:instance a ~ b => Coerce a b where coerce x = x
为什么?
最佳答案
我可以告诉你为什么第一个不起作用。
可以为任何可能的类型对定义Coerce
。 coerce 0 :: Int
解析为(coerce 0) :: Int
。因此,您已使用类型注释将b
固定在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
完全匹配。 IE。这是最通用的实例(出于类型类解析的目的),它很好地匹配了对coerce
的任何调用(因此您不能编写任何其他不重叠的实例)。 a ~ b
约束仅在选择实例后才应用。
因为您有一个匹配任何实例的实例,所以即使我们仍然有一个不知道coerce 0 :: Int
是什么类型的问题,也可以为0
选择一个实例。但是,在实例选择之后,我们现在有了附加的约束a ~ Int
,它允许将明确的类型分配给所有内容。