Suppose I just want to create my own parser which is exactly the same with the char
in Parsec, but when I run
import Text.Parsec
char1 c = char c
It gives me
? Non type-variable argument in the constraint: Stream s m Char
(Use FlexibleContexts to permit this)
? When checking the inferred type
char1 :: forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Cha
How can I solve it? Is there any other imports that I should include? Thanks
Parsec parsers have rather complicated types due to their flexibility. You can get around this in two ways:
Put {-# Language FlexibleContexts #-}
at the top of your source file. This pragma tells GHC to do some extra type inference.
(Recommended) Give char1 an explicit type.
char1 :: Char -> Parsec String () Char
char1 c = char c
This is recommended because you should always give any top-level declaration an explicit type. If you don't then all the compiler can tell you is that there is a type mismatch somewhere in your code (it will tell you where it found the contradiction, but that's not likely to be where the error is). With explicit type declarations the compiler can narrow it down.
In this case, Parsec defines the Parsec
type as
type Parsec s u = ParsecT s u Identity
You will recognise ParsecT
from your error message. ParsecT
is a monad transformer: it lets you have the parser do things in other monads (like IO) when it recognises the text. In this case we only want a parser, so we use the Identity
monad, which does nothing.
The s
parameter is the stream of inputs. In this case we will say that the parser is taking its input from a String
.
The u
parameter is a state. This allows you to do stuff like recording variable names in a symbol table as you encounter them. In this case we don't use a state so its just ()
.
If you were writing a real parser then you would generally define your own type synonym, something like
type FooParser a = Parsec Text FooState a
char1 :: Char -> FooParser Char
char1 = char