如何为另一个类型类中的所有类型编写实例?

时间:2012-01-16 08:52:37

标签: haskell

我必须定义一个类型类Truthy,它包含一个方法true,将类型类的实例转换为Bool值。

我的类型类声明:

class Truthy a where
    true :: a -> Bool

接下来,我必须为各种类型定义此类的实例,包括列表和数字类型。我已经为列表和Int做了这个,但有没有办法一次为所有数字类型执行此操作?

基于我的Int声明:

instance Truthy Int where
    true = (/=) 0

我尝试添加类型类约束,但它不起作用:

instance (Num a) => (Truthy a) where
    true = (/=) 0::a

如果有一种方法与我的想法相似,或者我应该单独为每种数字类型定义它?

1 个答案:

答案 0 :(得分:10)

这可能对家庭作业没有帮助,但你实际上可以写出这样的声明。您只需启用-XFlexibleInstances即可。至少在GHC中,您可以通过在文件顶部放置一个编译指示来完成此操作:

{-# LANGUAGE FlexibleInstances #-}

如果你仔细查看你得到的错误信息,它会说"如果要禁用它,请使用-XFlexibleInstances。"。

在这种特殊情况下,您还需要启用UndecidableInstancesOverlappingInstances

 {-# LANGUAGE FlexibleInstances,  UndecidableInstances, OverlappingInstances #-}

您需要FlexibleInstances,因为标准Haskell不允许任何形式的实例,其中类型变量在头部中出现多次。这完全没问题 - 我是最常用的扩展之一(根据this question)。

您需要UndecidableInstances,因为您的实例声明可能会导致类型检查器永远循环。我认为使用UndecidableInstances可以通过限制尝试减少实例时检查的深度来防止这种情况。这通常 - 包括在这种情况下 - 很好,但理论上可以使特定程序通过类型检查实现依赖。不过,它应该适用于你的情况。

正如hammar指出的那样,你需要启用OverlappingInstances,因为" context"在检查它们是否重叠时,实例是忽略。在这种情况下,上下文是Num a位。所以实例 - 用于检查它是否重叠 - 被读作instance Truthy a...并与所有内容重叠。启用OverlappingInstances后,您只需要有一个最具体的实例即可使用。