I'm working through the Write Yourself a Scheme tutorial, and one code block made me wonder about the difference between bind and assignment:
parseAtom = do first <- letter <|> symbol
rest <- many (letter <|> digit <|> symbol)
let atom = first:rest
return $ case atom of
"#t" -> Bool True
"#f" -> Bool False
_ -> Atom atom
Why let atom =
instead of atom <-
? Thus, I tried:
parseAtom = do first <- letter <|> symbol
rest <- many (letter <|> digit <|> symbol)
atom <- first : rest
return $ case atom of
"#t" -> Bool True
"#f" -> Bool False
_ -> Atom atom
And I get the compile error:
Couldn't match expected type `[Char]'
against inferred type `Text.Parsec.Prim.ParsecT
String () Data.Functor.Identity.Identity Char'
In a stmt of a 'do' expression: atom <- first : rest
I can't figure precisely what this means, which is probably due to an imprecise understanding of do
or monads. (I've read Learn You a Haskell along with various other monad/do tutorials, and other SO questions note that indentation oftens causes issues here, but I think I'm indenting correctly)
You're inside the parser monad, so the right side of <-
needs to be a parser expression. However first : rest
is simply a list (a string, specifically), not a parser expression.
What v <- someParser
does is it applies the given parser to the input and then stores the matched text in v
. A string is not a parser and it can't be applied to the input and there would be no matched text to store in v
. So all that you could do is to store the string in v
, which you'd do by writing let v = someString
.