I have written a parser in Haskell, which parses formulas in the form of string inputs and produces a Haskell data
type defined by the BNF below.
formula ::= true
| false
| var
| formula & formula
| ∀ var . formula
| (formula)
var ::= letter { letter | digit }*
Now I would like to create an instance of Show
so that I can nicely print the formulas defined by my types (I don't want to use deriving (Show)
). My question is: How do I define my function so that it can tell when parentheses are necessary? I don't want too many, nor too little parentheses.
For example, given the formula ∀ X . (X & Y) & (∀ Y . Y) & false
which, when parsed, produces the data structure
And (And (Forall "X" (And (Var "X") (Var "Y"))) (Forall "Y" (Var "Y"))) False
we have
Too little parentheses: ∀ X . X & Y & ∀ Y . Y & false
Too much parentheses: (∀ X . (((X) & (Y)))) & (∀ Y . (Y)) & (false)
Just right: ∀ X . (X & Y) & (∀ Y . Y) & false
Is there a way to gauge how many parenthesis are necessary so that the semantics is never ambiguous? I appreciate any feedback.
showsPrec
, whichshows
something with a given operatorPrec
edence. – MahayanashowsPrec
? The documentation I'm finding on it is quite minimal. – Bicolor∀ X
has the lowest precedence, so that∀ X . A & B
means∀ X . (A & B)
, and not(∀ X . A) & B
. (Sometimes the other precedence is used, instead.) Haskell also makes\ x ->
to extend as to the right as possible. You have to choose the precedence. – Hatboxshow
function so that parentheses are printed minimally. – BicolorshowsPrec
already available. A quick google search reveals this SO question, which I think is very helpful. – MahayanashowPrec
, you have to choose a precedence for your symbols. Essentially, you do have to choose which one between∀ X . (A & B)
and(∀ X . A) & B
can/should be written without parentheses. You want the latter, so the first will have parentheses -- that's OK. You need to assign a "precedence level" for your operators, and implementshowPrec
to add parentheses when you are in a context with a too high (I think) precedence. – HatboxShow
.Show
is meant to output Haskell code, such that copy-pasting that code can (roughly) rebuild the original data. This should go into its own function. @chi's answer is still correct, and you can use all theShowS
stuff to implement your new function, but it should not be calledshow
. – Premillenarian