I'm new to Haskell. This is my parser:
data Parser a = MkParser (String -> Maybe a)
This parses any string, gives the first character:
-- anyChar
anyChar :: Parser Char
anyChar = MkParser sf
where
sf "" = Nothing
sf (c:cs) = Just c
It works. Now, I am learning from a tutorial. It says I can convert an answer of a parser and run it through a function, like this (creating a new parser):
-- convert a parsers answer based on a function
convert :: (a -> b) -> Parser a -> Parser b
convert f (MkParser p1) = MkParser sf
where
sf inp = case p1 inp of
Nothing -> Nothing
Just x -> Just (f x)
This looks like it works! I realized here that I can access the input string in my parser functions. (Even though the definition of convert
doesn't take an input string. I want to recreate anyChar
so that it also uses the input string (Just so I can understand the syntax and what is going on). (I came from using Python and I'm a rookie at Haskell)
This is what I tried
-- apparently we can use "inp" to signifiy the input string
-- let's recreate anyChar to use input
anyCharInp :: Parser Char
anyCharInp = MkParser sf
where
case inp of
(c:cs) -> Just c
_ -> Nothing
But it's giving an indentation error. Any ideas?
You are close. Let's focus on this part:
anyCharInp :: Parser Char
anyCharInp = MkParser sf
This uses the sf
variable, but it does not define it in this line, so we need to define it below using where
.
where
case inp of
(c:cs) -> Just c
_ -> Nothing
Here we do not find a definition for sf
. Note that after where
the compiler expects definitions, not expressions, and will produce an error if it does not find them. Let's fix that:
anyCharInp :: Parser Char
anyCharInp = MkParser sf
where
sf inp = case inp of
(c:cs) -> Just c
_ -> Nothing
Now sf
is defined. Also not how sf
is a function taking inp
as argument. This is needed, since we need inp
to be defined before we can use case inp of ...
.
A few alternatives are possible. Here's one that avoids the case of
:
anyCharInp :: Parser Char
anyCharInp = MkParser sf
where
sf (c:cs) = Just c
sf _ = Nothing
(This turns out to be very similar to the one you posted, though.)
Here's another, using a lambda expression to avoid where
.
anyCharInp :: Parser Char
anyCharInp = MkParser (\inp ->
case inp of
(c:cs) -> Just c
_ -> Nothing
)
More alternatives exist, but these are the most common ones, I believe.