Reputation: 407
I'm trying to build a parser for a simplistic DSL.
I'm running into trouble with the following function:
procP :: ((a->Bool) -> [a] -> Bool) -> String -> Comperator -> ([String] -> Bool)
procP q v c =
case c of
NumE -> q ((==) . unMay . readDouble $ v) . mapMaybe readDouble
NumNE -> q ((/=) . unMay . readDouble $ v) . mapMaybe readDouble
NumLTE -> q ((<=) . unMay . readDouble $ v) . mapMaybe readDouble
NumLT -> q ((<) . unMay . readDouble $ v) . mapMaybe readDouble
NumGTE -> q ((>=) . unMay . readDouble $ v) . mapMaybe readDouble
NumGT -> q ((>) . unMay . readDouble $ v) . mapMaybe readDouble
Exists -> q notBlanks
DatE -> q ((==) . unMay . p_date $ v ) . mapMaybe p_date
DatNE -> q ((/=) . unMay . p_date $ v ) . mapMaybe p_date
DatLTE -> q ((<=) . unMay . p_date $ v ) . mapMaybe p_date
DatLT -> q ((<) . unMay . p_date $ v ) . mapMaybe p_date
DatGTE -> q ((>=) . unMay . p_date $ v ) . mapMaybe p_date
DatGT -> q ((>) . unMay . p_date $ v ) . mapMaybe p_date
TxtE -> q (==v)
TxtME -> (q (==v)) . map (rTrim)
TxtNME -> (q (/=v)) . map (rTrim)
TxtNE -> q (/= v)
The breakdown here is as follows:
q
is some function that works like any
from prelude. There are a couple different variations, but the type signature should be more or less the same - given a predicate and a list, return a bool.
v
is a string input for purposes of comparison, it helps construct the predicate.
c
is a token type constructed by the parser that represents what type of comparison we should use in the predicate.
unMay
is a stupid hack function to "unwrap" a Just
value or error on Nothing
.
readDouble
and p_date
are functions that take a String
and return either a Maybe Day
or Maybe Double
, respectively.
The design intent here is that the we're using the Comparator
token to tell us what type to change the input String
s to internally, so that I can choose whether to compare against a value as a String
, Day
, or Double
, respectively.
Sort of like a super basic version of what Perl does with ==
vs eq
, but with less coercion and more nasty error messages.
The problem I'm having is that this doesn't type check, because the predicate getting passed to q
ends up presenting as type Double->Bool
instead of a->Bool
, and so I get an error about how a
is a rigid type variable.
The error more or less makes sense to me, but I'm having a lot of trouble thinking of a way to get around the problem.
Does anyone have any advice on how to re-structure this?
Upvotes: 1
Views: 126
Reputation: 152707
Turn on Rank2Types
(e.g. by putting {-# LANGUAGE Rank2Types #-}
at the top of your file) and write
-- vvvvvvvvv difference is here
procP :: (forall a. (a->Bool) -> [a] -> Bool) -> String -> Comperator -> ([String] -> Bool)
Upvotes: 4