I want to access parsecs input stream directly which can be done using getParserState
. To read from the stream the uncons
method is provided. However I'm facing (as usual) a type related problem. so this is my parsing function:
myParser :: (Stream s m Char) => ParsecT s (ShiftedState u s) m String
myParser = do
s <- P.getParserState
let i = stateInput s
let x = uncons i
return ""
and I'm getting the following error.
Could not deduce (Stream s m0 Char)
arising from a use of ‘uncons’
And the problem is simply that I do not quite know what exactly the error means. I think uncons
runs in the underlying monad, not in the ParsecT monad. But I don't know how to lift (?) it.
Basically I would like to know how I can use uncons
and read from the stream. Now please don't worry about wether one should do this... this is basically me understanding how monads work xD
Here’s what’s happening: uncons
needs to run in some sort of monad. You can see this by its type signature: uncons :: Stream s m t => s -> m (Maybe (t, s))
. But you’re just doing let x = uncons i
— so x
is a monadic computation which returns the result of uncons i
, but you haven’t specified which monad this monadic computation is running within. You happen to know that you ‘want’ uncons i
to run within your monad m
(which satisfies Stream s m Char
), but GHC doesn’t know this. So GHC makes the assumption that here, uncons i :: m0 (Maybe (t, s))
, where m0
is some arbitrary monad. Thus GHC produces the error you see, since uncons
requires the constraint Stream s m0 Char
to be satisfied in order to use it, yet that constraint isn’t necessarily satisfied for any random m0
.
How can this be solved? Well, you already know that this whole computation is of type ParsecT s (ShiftedState u s) m Char
, and m
satisfies the instance Stream s m Char
. And as it turns out, there is a function lift :: Monad m => m a -> ParsecT s u m a
which ‘lifts’ a monadic computation m a
to a Parsec computation ParsecT s u m a
. So you can just rewrite your function to:
myParser :: (Stream s m Char) => ParsecT s (ShiftedState u s) m String
myParser = do
s <- P.getParserState
let i = stateInput s
x <- lift (uncons i)
return ""
I haven’t tested it, but this should work if I haven’t made any mistakes.
(Another solution is to simply give x
a type signature:
let x :: m (Maybe (Char, s))
x = uncons i
This forces x
to have the type you want. Now GHC can look and see that m
and s
all satisfy the relevant constraint, so does not produce that error. But this requires the ScopedTypeVariables
language extension to compile, and is much less elegant than the previous solution.)