Я спрашивал об этом раньше, но, похоже, я сформулировал этот вопрос слишком узко. Поэтому давайте посмотрим, смогу ли я объяснить, что я на самом деле после.
Предположим, что у меня есть некоторый тип, который поддерживает несколько двоичных операторов, каждый из которых имеет различный приоритет и ассоциативность. Как написать экземпляр Show
, который правильно скопирует подвыражения?
Я знаю, что я здесь плотный, но я ошибаюсь каждый раз, когда я пытаюсь это сделать. Должна быть какая-то механическая процедура, за которой вы можете следовать, чтобы сделать это правильно, но я не могу ее найти. Может ли кто-нибудь пройти меня через пример?
Я знаю, что это, в конечном счете, сводится к завершению всего в showParen
и показу суб-выражений с использованием showsPrec
с правильным магическим числом, и я могу заставить его почти работать, но он никогда не работает правильно при любых обстоятельствах.
Изменить: Рассмотрим следующий код
data Expr =
Const Int |
Expr :+: Expr |
Expr :-: Expr |
Expr :*: Expr |
Expr :/: Expr
infixl 6 :+:
infixl 6 :-:
infixl 7 :*:
infixl 7 :/:
instance Show Expr where
showsPrec p e0 =
case e0 of
Const n -> shows n
x :+: y -> showParen (p > 6) $ (showsPrec 6 x) . (" :+: " ++) . (showsPrec 6 y)
x :-: y -> showParen (p > 6) $ (showsPrec 6 x) . (" :-: " ++) . (showsPrec 6 y)
x :*: y -> showParen (p > 7) $ (showsPrec 7 x) . (" :*: " ++) . (showsPrec 7 y)
x :/: y -> showParen (p > 7) $ (showsPrec 7 x) . (" :/: " ++) . (showsPrec 7 y)
Это работает почти правильно:
*Main> Const 1 :+: Const 2 :*: Const 3 :+: Const 4
1 :+: 2 :*: 3 :+: 4
*Main> (Const 1 :+: Const 2) :*: (Const 3 :+: Const 4)
(1 :+: 2) :*: (3 :+: 4)
Но не совсем:
*Main> Const 1 :+: Const 2 :-: Const 3 :-: Const 4
1 :+: 2 :-: 3 :-: 4
*Main> Const 1 :+: Const 2 :-: (Const 3 :-: Const 4)
1 :+: 2 :-: 3 :-: 4
Итак, похоже, что приоритет в порядке, но ассоциативность увязывается.