Here's an example from http://hackage.haskell.org/package/parsec-3.1.7/docs/Text-Parsec-Expr.html :
expr = buildExpressionParser table term
<?> "expression"
term = parens expr
<|> natural
<?> "simple expression"
table = [ [prefix "-" negate, prefix "+" id ]
, [postfix "++" (+1)]
, [binary "*" (*) AssocLeft, binary "/" (div) AssocLeft ]
, [binary "+" (+) AssocLeft, binary "-" (-) AssocLeft ]
]
binary name fun assoc = Infix (do{ reservedOp name; return fun }) assoc
prefix name fun = Prefix (do{ reservedOp name; return fun })
postfix name fun = Postfix (do{ reservedOp name; return fun })
Seems you need a few imports to get started:
import Text.Parsec
import Text.Parsec.Expr
import Text.Parsec.Token
And now it fails to typecheck on almost every line.
Does anyone know how to fix it?
Errors looking like this:
Couldn't match expected type ‘ParsecT s u m a0’
with actual type ‘String -> ParsecT s9 u9 m9 ()’
Relevant bindings include
name :: GenTokenParser s9 u9 m9 (bound at Eval2.hs:28:9)
postfix :: GenTokenParser s9 u9 m9 -> (a -> a) -> Operator s u m a
(bound at Eval2.hs:28:1)
Probable cause: ‘reservedOp’ is applied to too few arguments
In a stmt of a 'do' block: reservedOp name
In the first argument of ‘Postfix’, namely
‘(do { reservedOp name;
return fun })’
Makes me curious about the type of reservedOp
λ :t reservedOp
reservedOp
:: GenTokenParser s u m
-> String -> Text.Parsec.Prim.ParsecT s u m ()
So looking at the documentation here http://hackage.haskell.org/package/parsec-3.1.7/docs/Text-Parsec-Token.html :
reservedOp :: String -> ParsecT s u m ()
Orly? So what's a GenTokenParser s u m
and how do I get one?
Check out this type. What could it possibly mean?
λ :t TokenParser
TokenParser
:: Text.Parsec.Prim.ParsecT s u m String
-> (String -> Text.Parsec.Prim.ParsecT s u m ())
-> Text.Parsec.Prim.ParsecT s u m String
-> (String -> Text.Parsec.Prim.ParsecT s u m ())
-> Text.Parsec.Prim.ParsecT s u m Char
-> Text.Parsec.Prim.ParsecT s u m String
-> Text.Parsec.Prim.ParsecT s u m Integer
-> Text.Parsec.Prim.ParsecT s u m Integer
-> Text.Parsec.Prim.ParsecT s u m Double
-> Text.Parsec.Prim.ParsecT s u m (Either Integer Double)
-> Text.Parsec.Prim.ParsecT s u m Integer
-> Text.Parsec.Prim.ParsecT s u m Integer
-> Text.Parsec.Prim.ParsecT s u m Integer
-> (String -> Text.Parsec.Prim.ParsecT s u m String)
-> (forall a.
Text.Parsec.Prim.ParsecT s u m a
-> Text.Parsec.Prim.ParsecT s u m a)
-> Text.Parsec.Prim.ParsecT s u m ()
-> (forall a.
Text.Parsec.Prim.ParsecT s u m a
-> Text.Parsec.Prim.ParsecT s u m a)
-> (forall a.
Text.Parsec.Prim.ParsecT s u m a
-> Text.Parsec.Prim.ParsecT s u m a)
-> (forall a.
Text.Parsec.Prim.ParsecT s u m a
-> Text.Parsec.Prim.ParsecT s u m a)
-> (forall a.
Text.Parsec.Prim.ParsecT s u m a
-> Text.Parsec.Prim.ParsecT s u m a)
-> (forall a.
Text.Parsec.Prim.ParsecT s u m a
-> Text.Parsec.Prim.ParsecT s u m a)
-> Text.Parsec.Prim.ParsecT s u m String
-> Text.Parsec.Prim.ParsecT s u m String
-> Text.Parsec.Prim.ParsecT s u m String
-> Text.Parsec.Prim.ParsecT s u m String
-> (forall a.
Text.Parsec.Prim.ParsecT s u m a
-> Text.Parsec.Prim.ParsecT s u m [a])
-> (forall a.
Text.Parsec.Prim.ParsecT s u m a
-> Text.Parsec.Prim.ParsecT s u m [a])
-> (forall a.
Text.Parsec.Prim.ParsecT s u m a
-> Text.Parsec.Prim.ParsecT s u m [a])
-> (forall a.
Text.Parsec.Prim.ParsecT s u m a
-> Text.Parsec.Prim.ParsecT s u m [a])
-> GenTokenParser s u m
Thanks @Christian Conkle and @bheklilr and this here http://hackage.haskell.org/package/parsec-3.1.7/docs/Text-Parsec-Token.html#v:makeTokenParser
Here's the 2014 version of the buildExpressionParser
example which should be in the Parsec docs instead of what's there.
import Text.Parsec
import Text.Parsec.Expr
import Text.Parsec.Token
import Text.Parsec.Language (javaStyle)
lexer = makeTokenParser javaStyle
expr = buildExpressionParser table term
<?> "expression"
term = parens lexer expr
<|> natural lexer
<?> "simple expression"
table = [ [prefix "-" negate, prefix "+" id ]
, [postfix "++" (+1)]
, [binary "*" (*) AssocLeft, binary "/" (div) AssocLeft ]
, [binary "+" (+) AssocLeft, binary "-" (-) AssocLeft ]
]
binary name fun assoc = Infix (do{ reservedOp lexer name; return fun }) assoc
prefix name fun = Prefix (do{ reservedOp lexer name; return fun })
postfix name fun = Postfix (do{ reservedOp lexer name; return fun })
The data constructor GenTokenParser
has all those parameters because it's the constructor for a type with a lot of fields.
The way to make a TokenParser
is indeed with makeTokenParser
. Its type says that it returns a GenTokenParser
; TokenParser
is just a restricted type synonym. TokenParser st
is exactly the same thing as GenTokenParser String st Identity
.
You can, as the docs suggest, pass it a premade language definition like haskellDef
. You could also manually construct a LanguageDef
, which isn't too complicated; ask if you want elaboration. The middle ground is to use record modification syntax to modify one of the premade definitions: makeTokenParser (haskellDef { commentStart = "<<", commentEnd = ">>" })
.
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