Haskell - 类型类定义中的类约束

时间:2013-10-25 23:41:31

标签: haskell typeclass

我愚弄了一个来自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'`。我做错了什么?

3 个答案:

答案 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表示",aYesNo"的实例。整个实例声明的内容类似于,#34;对于每种类型aaYesNo的实例,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扩展名。

相关问题