我是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
时,我也会遇到错误。我如何首先使它起作用,并且可以限制a
和b
的类型 - 例如,如果我希望a
始终为Bool
和b
始终为()?
您编写了一个实例,在其中为元组(a, b)
编写该实例,元组为 Printable
,以防项目 a
和 b
是 Printable
。但这确实不是表示a
或b
是Bool
s或单位。
您可能会认为 - 就像在许多语言中一样 - (==)
操作员在任意两种类型上都可以使用,但是在Haskell (==)
中具有类型(==) :: Eq a => a -> a -> Bool
,因此它是一个函数,其中左和右操作数具有相同的型。因此,除非x
是Bool
。
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 == True
和x == 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"
您的元组实例应该利用a
和b
都是Printable
的事实。您只需要在构造函数上进行模式匹配,而不是各个组件。
instance (Printable a, Printable b) => Printable (a, b) where
toString (x, y) = "(" ++ toString x ++ "," ++ toString y ++ ")"