实例签名:对方法的约束
使用InstanceSignatures,我可以为实例 decl 中的方法签名。
实例声明中的类型签名必须比类声明中的类型签名更多(或相同),使用实例类型实例化。
我可以从这个答案中看到sig 的类型部分不能更具体;但是为什么不能添加额外的约束呢?毕竟,您可以对实例 decl 施加约束,这将使实例比“使用实例类型实例化的类声明”更具体。
Addit:(响应前几条评论。)为了解释“您可以对实例 decl 进行约束……更具体的OVERLAPPABLE实例”:这里的实例头声称它提供addNat了所有类型a, b, c。但它没有:它只提供 if ais of the form SNat a'、cis of the formSNat c'等。我在问为什么我不能在方法级别同样限制类型?
例如[改编自 Hughes 1999](更现实地说,这可能是 BST/玫瑰树等):
data AscList a = AscList [a] -- ascending list
instance Functor AscList where -- constructor class
fmap f (AscList xs) = AscList $ sort $ fmap f xs
-- :: Ord b => (a -> b) -> AscList a -> AscList b -- inferred
没有实例签名 GHC 会抱怨no instance for (Ord b)。带有签名的 GHC 抱怨来自is more polymorphic than给定类的实例化 sig 。
这个(优秀的)答案解释了实例字典中的机制。我可以看到字典中该方法的条目具有从类 decl 中方法(如果有)的约束数设置的类型。没有空间为该方法放置额外的字典/参数。
这似乎只是实施没有预见到需要。是否有更深层次/更基于理论的反对理由?
(顺便说一句,我对 Hughes 的方法并不那么信服:那会同时需要Ord a => WFT(AscList a)和Ord b => WFT(AscList b)。但是没有必要要求传入(AscList a)是上升的。其他构造函数类AscList可能在Ord任何地方都不需要约束。)
回答
如果您允许向不在类方法中的实例方法添加约束,则使用类型类的多态函数在您专门化它时可能不再进行类型检查。
例如,考虑AscList上面的实例,以及以下用法Functor:
data T f = T (f (IO ())) -- f applied to a non-Ord
example :: Functor f => T f -> T f
example (T t) = T (fmap (x -> x >> print 33) t)
- 类型
example表示您可以f使用任何函子实例化,例如f = AscList. - 但这毫无意义,因为它会尝试对
AscList (IO ()).
当我们example在这里专门研究时,唯一能判断出问题的方法是阅读它的定义,找出 offmap的用法是否仍然有效,这与模块化背道而驰。类型签名中的类型类约束不会也不应该记录如何使用它们的方法。相反,这意味着实例不能向它们的方法实现添加约束。