两个变量的类实例



我是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)"

但是现在我得到了错误

与实际类型的" bool"

无法匹配预期的类型" A"

这很合理,但是当我用Bool替换a时,我也会遇到错误。我如何首先使它起作用,并且可以限制ab的类型 - 例如,如果我希望a始终为Boolb始终为()?

怎么办?

您编写了一个实例,在其中为元组(a, b)编写该实例,元组为 Printable,以防项目 abPrintable。但这确实不是表示abBool s或单位。

您可能会认为 - 就像在许多语言中一样 - (==)操作员在任意两种类型上都可以使用,但是在Haskell (==)中具有类型(==) :: Eq a => a -> a -> Bool,因此它是一个函数,其中左和右操作数具有相同的型。因此,除非xBool

,我们不能使用x == True

我们不需要这些警卫。我们需要做的是呼叫操作数的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 ++ ")"

edit :如果您希望a始终是Bool,则可以写作:

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

您当然可以添加警卫,模式匹配或其他一些方法来区分x == Truex == False,但是我建议您不要这样做,因为这违反了干燥原则: d on't r epeat y 我们自己。

仅仅因为a具有Printable实例,并不意味着您可以假设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 ++ ")"

最新更新