Thank you, community.
I’ll use a minimal working example to frame my question:
module Main where
import Control.Applicative ((<|>))
import Text.Parsec (parse, many1, digit, string, oneOf, try, char, manyTill, anyToken, lookAhead, many, noneOf, between)
import Text.Parsec.String (Parser)
data Tree = Leaf String | Node [Tree]
instance Show Tree where
show :: Tree -> String
show (Leaf x) = x
show (Node xs) = "(" ++ concatMap show xs ++ ")"
brackets :: Parser Tree
brackets = Node <$> between
(char '(') (char ')')
(many (brackets <|> (Leaf <$> many1 (noneOf "()"))))
s = "(An example using (nested (parenthesis)))"
main :: IO ()
main = print (
parse brackets "" s
)
Supposedly, brackets
function is a Parser Tree
which parses brackets (even nested ones). The first step is hovering my mouse over brackets definition, and I see (at least) three pieces of information:
- Type signature
between :: forall s (m :: Type -> Type) t u open close a.
Stream s m t =>
ParsecT s u m open
-> ParsecT s u m close -> ParsecT s u m a -> ParsecT s u m a
- Comment explaining function behaviour
between open close p parses open
, followed by p
and close
. Returns the value returned by p
.
- Example
braces = between (symbol "{") (symbol "}")
(A tooltip definition displays in VSC Code, thanks to HLS language server, I think).
In order to improve my understanding, I could look at between
, parse
, <$>
function definitions.
So, my question is:
what’s a good and practical route to understand what’s happening, for example, in brackets
function ?
And a follow-up question is: in general, we speak about the importance of understanding types, but
are types enough to understand Haskell code, or we need comments to quickly reason without going to look at function definitions ?
I ask this because in that tooltip, function definitions are missing, so types seem to be more important than function definitions when reading Haskell code.
I’ll appreciate any thoughts from this community.