我必须定义一个类型类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
如果有一种方法与我的想法相似,或者我应该单独为每种数字类型定义它?
答案 0 :(得分:10)
这可能对家庭作业没有帮助,但你实际上可以写出这样的声明。您只需启用-XFlexibleInstances
即可。至少在GHC中,您可以通过在文件顶部放置一个编译指示来完成此操作:
{-# LANGUAGE FlexibleInstances #-}
如果你仔细查看你得到的错误信息,它会说"如果要禁用它,请使用-XFlexibleInstances。"。
在这种特殊情况下,您还需要启用UndecidableInstances
和OverlappingInstances
:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
您需要FlexibleInstances
,因为标准Haskell不允许任何形式的实例,其中类型变量在头部中出现多次。这完全没问题 - 我是最常用的扩展之一(根据this question)。
您需要UndecidableInstances
,因为您的实例声明可能会导致类型检查器永远循环。我认为使用UndecidableInstances
可以通过限制尝试减少实例时检查的深度来防止这种情况。这通常 - 包括在这种情况下 - 很好,但理论上可以使特定程序通过类型检查实现依赖。不过,它应该适用于你的情况。
正如hammar指出的那样,你需要启用OverlappingInstances
,因为" context"在检查它们是否重叠时,实例是忽略。在这种情况下,上下文是Num a
位。所以实例 - 用于检查它是否重叠 - 被读作instance Truthy a...
并与所有内容重叠。启用OverlappingInstances
后,您只需要有一个最具体的实例即可使用。