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 dealing with two syntactic sugar constructs: a do-notation and a let block inside a do-notation. Things should become clear if we simply desugar your correct function implementation.
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
parseAtom = do
first <- letter <|> symbol
rest <- many (letter <|> digit <|> symbol)
let
atom = first : rest
in do
return $ case atom of
"#t" -> Bool True
"#f" -> Bool False
_ -> Atom atom
parseAtom =
(letter <|> symbol) >>= \first ->
many (letter <|> digit <|> symbol) >>= \rest ->
let
atom = first : rest
in return $ case atom of
"#t" -> Bool True
"#f" -> Bool False
_ -> Atom atom
It should also be noted that a simple let-expression inside a do-notation can be replaced with a bind-expression as you expected - all you need to do is just drop in a return. So let atom = first:rest can be translated to atom <- return $ first : rest.
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.
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