我愚弄了一个来自Learn You a Haskell的例子,我不确定会出现什么问题。这是最初的例子,它模仿真实/虚假的语义:
class YesNo a where
yesno :: a -> Bool
一个直截了当的例子是:
instance YesNo Int where
yesno 0 = False
yesno _ = True
然后是:
instance YesNo (Maybe a) where
yesno (Just _) = True
yesno Nothing = False
这有一定的意义,但我发现yesno (Just False) == True
有点违反直觉的概念,所以我试着像这样修改它:
instance YesNo (Maybe a) where
yesno (Just b) = yesno b
yesno Nothing = False
因此,在Maybe实例包含值的情况下,我们得到该值本身的真实性。但是,这失败了错误No instance for (YesNo a) arising from a use of
yesno'`。我做错了什么?
答案 0 :(得分:3)
您需要告诉编译器类型a
必须有YesNo
个实例:
instance YesNo a => YesNo (Maybe a) where
yesno (Just a) = yesno a
yesno Nothing = False
测试:
> yesno (Just False)
False
答案 1 :(得分:0)
您可以为YesNo
创建Maybe a
的实例,仅当a
也是YesNo
的实例时才有效:
instance (YesNo a) => YesNo (Maybe a) where
yesno (Just b) = yesno b
yesno Nothing = False
对于每种类型(YesNo a) =>
,a
表示",a
是YesNo
"的实例。整个实例声明的内容类似于,#34;对于每种类型a
,a
是YesNo
的实例,Maybe a
也是YesNo
的实例{1}}其中......
答案 2 :(得分:0)
这样就是,其中Maybe实例包含我们得到的值......
在Haskell中无法做得很好。不应该读取类型类实例“我现在将此数据类型从非实例集传输到实例集”,而是“我现在描述如何将此类型用作该类的实例”。实际上并没有不是一个类的实例的概念,只是没有找到一个实例。
因此,如果您想根据Maybe
中包含的值做出决定,您可能应该按照Cirdec和Mikhail Glushenkov所建议的那样做:instance YesNo a => YesNo (Maybe a)
。当然这意味着,例如Maybe ()
将不成为YesNo
个实例。您可以为所有类型或其他类型获得相同的行为,但对于特定类型的集合,也会获得完全相同的行为。但是,根据类中是否存在类型,您无法获得不同的行为。
实际上有一种方法可以实现这一点,但它有点不受欢迎:
{-# LANGUAGE OverlappingInstances #-}
instance YesNo (Maybe a) where
yesno (Just _) = True
yesno Nothing = False
newtype YesNo_ a = YesNo_ a
instance YesNo a => YesNo (Maybe (YesNo_ a)) where
yesno (Just (YesNo_ a)) = yesno a
yesno Nothing = False
这不仅麻烦,还需要稍微不安全的OverlappingInstances
扩展名。