I am going through Write Yourself a Scheme in Haskell. Its a great tutorial, but I've run into a wall with one of the parsing exercises:
parseNumber :: Parser LispVal
parseNumber = liftM (Number . read) $ many1 digit
Rewrite parseNumber using:
I had no problems with do-notation:
parseNumber :: Parser LispVal
parseNumber = do x <- many1 digit
let y = read x
return $ Number y
For #2 I've tried a bunch of variations such as:
parseNumber :: Parser LispVal
parseNumber = (many1 digit) >>= (liftM (Number . read))
but I keep running into type errors. I have two questions.
I feel like I am missing a fundamental concept regarding types?
You're attempting a non-trivial transformation from do-notation to bind notation, I recommend doing it the "trivial" way, and then making it points-free.
Recall:
x <- m === m >>= \x -> let x = e === let x = e in
Then you have:
parseNumber = many1 digit >>= \x -> let y = read x in return (Number y)
(I've removed the $
to avoid precedence problems.)
We can then convert this into:
parseNumber = many1 digit >>= \x -> return (Number (read x)) = many1 digit >>= return . Number . read
Now, if you want to use liftM
, you need to stop using bind, since the lifted function expects a monadic value as its argument.
parseNumber = liftM (Number . read) (many1 digit)
In your case, bind has type:
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
(since you're using Parser
as the Monad)
You give bind two arguments: the first one, many1 digit
, should be ok (regarding the type); but the type of the second argument is the result type of liftM
, namely Parser a -> Parser b
and this does not fit the second argument's expected type (a -> Parser b)
!
Without having tested it: instead of using liftM (Number.read)
as second argument of bind, try using return . Number . read
- this should have the right type and gives probably what you want...
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