我正在做一个练习,为Maybe
数据类型中的对象实现括号:
我想要实现的是这种括号:
-- MyJust 'a'
-- MyJust (MyJust 'a')
-- MyJust MyNothing
data MyMaybe a = MyNothing | MyJust a
instance Show a => Show (MyMaybe a) where
showsPrec _ MyNothing = showString "MyNothing"
showsPrec p (MyJust x) =
showParen(p>6)(showString "MyJust ".showsPrec 7 x)
我的代码可以工作,但有些地方我不理解。首先,MyJust
运算符的优先级是多少(它必须小于6,否则我会得到类似(MyJust (MyJust 'a'))
的东西?另一个问题是,例如,我如何将其更改为9,从而得到(MyJust (MyJust 'a'))
?我尝试了infixl 9 'MyJust'
,但它不起作用。我问这个问题是为了更好地理解haskell中的优先级。
我认为您混淆了Haskell运算符的实际优先级与showsPrec
使用的优先级跟踪方案,以确保可打印表示以正确的方式使用括号来匹配实际优先级。
在Haskell中,一个术语对另一个术语的"应用",无论是像sqrt 16
这样的函数应用程序,还是像Just 4
这样的构造函数应用程序,都始终有效地保持与10的固定优先级相关联(即,大于任何中缀运算符的优先级(,这一点不能改变。
为了编写一个能够正确反映构造函数优先级的Show
实例,您需要编写:
instance Show a => Show (MyMaybe a) where
showsPrec _ MyNothing = showString "MyNothing"
showsPrec d (MyJust x) = showParen (d > app_prec) $
showString "MyJust " . showsPrec (app_prec+1) x
where app_prec = 10
请注意,这遵循Show
类文档中给出的Leaf
模板。
如果您将app_prec
的值更改为其他值,那么如果您只显示MyMaybe
类型或嵌套的MyMaybe
类型,则情况看起来会很好,但如果您将其与其他类型组合,则会开始崩溃。例如,使用我对app_prec = 10
的定义,以下内容可以正确工作:
> MyJust (Just 10)
MyJust (Just 10)
但是,如果您将其更改为不正确的app_prec = 6
以匹配问题中的定义,则会产生损坏的输出:
> MyJust (Just 10)
MyJust Just 10