两个变量的类实例

时间:2017-12-05 16:00:40

标签: haskell

我是Haskell的新手并创建了这个类

class Printable a where 
    toString :: a -> String

其中两个实例

instance Printable Bool where
    toString x | x == True = "true"
               | x == False  = "false" 

instance Printable () where
    toString x = "unit type"

它们工作得很好,现在我想创建一个带两个参数的实例,但是我遇到了麻烦。我到目前为止创造的是

instance (Printable a, Printable b) => Printable (a, b) where
    toString x | fst x == True = "(true,unit type)"

但现在我收到了错误

  

无法将预期类型'a'与实际类型'Bool'匹配

这是合理的,但当我用a替换Bool时,我也会收到错误消息。我怎样才能让它首先发挥作用,我是否可以限制ab的类型 - 例如,如果我希望a始终为Bool该怎么办?和b永远是()?

2 个答案:

答案 0 :(得分:8)

您编写了一个实例,其中您为元组(a, b)编写了该元组,如果项Printableab,则元组为Printable。但意味着abBool s或单位。

您可能认为 - 就像在许多语言中一样 - (==)运算符适用于任何两种类型,但在Haskell中(==)具有类型(==) :: Eq a => a -> a -> Bool,所以它是左边的函数右操作数具有相同的类型。因此,我们无法使用x == True,除非xBool

我们不需要这些警卫。我们需要做的是调用操作数的toString函数,所以:

instance (Printable a, Printable b) => Printable (a, b) where
    toString (x,y) = "(" ++ toString x ++ "," ++ toString y ++ ")"

我们也可以将[x] ++替换为x : ...,以便我们将其重写为:

instance (Printable a, Printable b) => Printable (a, b) where
    toString (x,y) = '(' :  toString x ++ ',' : toString y ++ ")"

编辑:如果您希望a始终为Bool,您可以写信:

instance Printable b => Printable (Bool, b) where
    toString (x,y) = '(' :  toString x ++ ',' : toString y ++ ")"

您当然可以添加警卫,模式匹配或其他方法来区分x == Truex == False,但我建议您不要这样做,因为这违反了DRY原则:< strong> D on R epeat Y 我们自己。

答案 1 :(得分:4)

仅仅因为aPrintable个实例并不意味着您可以假设a ~ Bool,所以x == True会失败。

但是,您应该使用模式匹配而不是相等,这样可以回避问题。

class Printable a where 
    toString :: a -> String

instance Printable Bool where
    toString True = "true"
    toString False = "false"

instance Printable () where
    toString () = "unit type"

然后,您的元组实例应该使用ab都是Printable的事实。您只需要在构造函数上进行模式匹配,而不是单个组件。

instance (Printable a, Printable b) => Printable (a, b) where
    toString (x, y)  = "(" ++ toString x ++ "," ++ toString y ++ ")"