I'm learning haskell, and I have a lot of difficulty with mentally parsing many haskell expressions I come across.
Of course, I expect that, with enough practice, mentally parsing haskell will become second-nature, but in the meantime, in order to make sense of what I come across, I'd like to find some automatic way to translate an arbitrary "standard haskell"1 expression into one in which all "ambiguous"2 sub-expressions have been eliminated by introducing the necessary parentheses.
For example, it would translate the expression
f g h i
...into
((f g) h) i
..., or
a -> b -> c -> d
...into
a -> (b -> (c -> d))
..., etc.
Preferably, this would be a tool I can access with my phone, since I do much of my reading on haskell away from a proper computer.
1Of course, no such tool could possibly work with custom operators of unknown fixity and associativity. By "standard haskell" I mean the stuff defined in the prelude and in the standard haskell library.
2I'm using "ambiguous" here as shorthand for "ambiguous in the absence of precedence rules". E.g. 2 + 3 * 5
is ambiguous unless there's some precedence rule that settles the question of which of the two operations will be performed first.
If you really want to go to the work of it, you could write a TemplateHaskell
function to do this for you - you essentially just walk the AST and add parens at will. I started doing that, but realized it will get pretty long and tedious pretty fast. I think it may be more convenient for the moment for you to only think about currying when it actually comes into play (with functions that are not fully applied).
However, there is a trick you can use for a subcase of your problem: parens around operators whose fixity and associativity you aren't familiar with. In GHCi, after booting up with the right flags, just wrap the expression you are interested in inspecting in $([| <expression> |])
. Then, you get to see a parenthesized version of your expression before the result of evaluating it.
$ ghci -ddump-splices -XTemplateHaskell
Prelude> $([| 1 + 2 ^ 3 * 4 |])
<interactive>:1:3-21: Splicing expression
[| 1 + 2 ^ 3 * 4 |] ======> (1 + ((2 ^ 3) * 4))
33
Prelude> $([| 1 <$ pure 4 >>= \x -> const mempty =<< [(+),(*)] <*> [1,2] <* [False] |])
<interactive>:2:3-77: Splicing expression
[| 1 <$ pure 4
>>=
(\ x_a6PT -> const mempty =<< [(+), (*)] <*> [1, 2] <* [False] |]
======>
((1 <$ (pure 4))
>>=
(\ x_a6PT
-> ((const mempty) =<< (([(+),(*)] <*> [1,2]) <* [False]))))
[]
Prelude>
However, this definitely won't fix the type signatures or function applications the way you want.
It's not exactly what you're asking for, but I've found using HLint to warn me about unnecessary parens when I'm writing Haskell to be a big help when I'm reading.
You may also find the chart on page 23 of Bernie Pope's "A tour of the Haskell Prelude" helpful. I've included a copy below.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With