[Template-haskell] Polymorphism + Quasiquoting + Untyped AST =
problems
Alfonso Acosta
alfonso.acosta at gmail.com
Wed Feb 20 02:22:18 EST 2008
Hi,
Let me show you why I reached that conclusion through a simple example.
Imagine that, for some reason, we need to implement a DSL which is
required to use vectors. Furthermore, we would like to make
transformations/sanity checks at compile time.
To keep things simple, the vector is internally represented as a list:
newtype Vec a = MkVec [a] -- Note that MkVec would be hidden to the end user.
Using Template Haskell, we can easily create a constructor function
which fulfils all the requirements.
vector :: Lift a => [a] -> QExp
vector xs = do sanityCheck xs
[| MkVec xs |]
where sanityCheck = undefined -- not specified
Using "vector" is simple:
$(vector [1,2,3,4,5])
OK, fair enough. However, pattern matching is lost and it would be
nicer to be able to to build vector literals using a syntax different
to lists. For example, using less-than and more-than symbols to
enclose the vector elements:
<1,2,3,4,5>
We would also like to do some pattern matching:
<> -- empty vector
x <xs> -- head and tail of the vector
Using a quasiquoter all the above is is possible. In the case of Int
vectors, supposing name our quasiquoter v we could do things like.
[$v|<1,2,3,4,5,6>|]
head :: Vector Int -> Int
f v = case v of
[$v|<>|] -> error "empty"
[$v|x<xs>|] -> x
Looks nice, but we lose polymorphism! It is imposible to make v work
with any instance of Read! Here is a possible implementation:
-- parse a list enclosed with lower-than and greater-than characters
parseLTGT :: Read a => String -> [a]
parseLTGT = undefined -- code ommited
v = QuasiQuoter vExp vPat
-- In the case of Ints it is simple
vExp :: String -> Q Exp
vExp str = do let xs = (readLTGT str) :: [Int]
sanityCheck xs
[| MkVec xs |]
Unfortunately, we cannot implement vExpr in the general case. Removing
the explicit signature of readLTGT would lead to
ambiguous-type-variable errors.
Maybe things would be different if TH's AST wasn't untyped (i.e. vExpr
:: String -> Q (Exp a)) I'm not sure if it is feasible, though.
I would love to be proven wrong and read about a workaround/solution.
Any suggestions?
Cheers,
Fons
More information about the template-haskell
mailing list