{-# 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

为什么?

最佳答案

我可以告诉你为什么第一个不起作用。

可以为任何可能的类型对定义Coercecoerce 0 :: Int解析为(coerce 0) :: Int。因此,您已使用类型注释将b固定在coerce :: a -> b中,而不是a

数字文字是多态的,因此0的类型为Num a => a。那行不通;没有与Coerce a Int匹配的实例。可能有Coerce Double IntCoerce Complex Int等,因此仅知道bInt不足以推断0Int。我们需要说coerce (0 :: Int) :: Int来修复两个类型参数。

我相信第二个方法是有效的,因为实例声明的约束并未用于帮助解析类型类。 instance a ~ b => Coerce a b与您编写的instance Coerce a b完全匹配。 IE。这是最通用的实例(出于类型类解析的目的),它很好地匹配了对coerce的任何调用(因此您不能编写任何其他不重叠的实例)。 a ~ b约束仅在选择实例后才应用。

因为您有一个匹配任何实例的实例,所以即使我们仍然有一个不知道coerce 0 :: Int是什么类型的问题,也可以为0选择一个实例。但是,在实例选择之后,我们现在有了附加的约束a ~ Int,它允许将明确的类型分配给所有内容。

10-06 01:50