From alfonso.acosta at gmail.com Wed Feb 20 02:22:18 2008 From: alfonso.acosta at gmail.com (Alfonso Acosta) Date: Wed Feb 20 02:20:34 2008 Subject: [Template-haskell] Polymorphism + Quasiquoting + Untyped AST = problems Message-ID: <6a7c66fc0802192322q252ccb1fyacf8f57b0b69deb6@mail.gmail.com> 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 -- 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|] -> 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 From alfonso.acosta at gmail.com Wed Feb 20 02:25:01 2008 From: alfonso.acosta at gmail.com (Alfonso Acosta) Date: Wed Feb 20 02:23:15 2008 Subject: [Template-haskell] Re: Polymorphism + Quasiquoting + Untyped AST = problems In-Reply-To: <6a7c66fc0802192322q252ccb1fyacf8f57b0b69deb6@mail.gmail.com> References: <6a7c66fc0802192322q252ccb1fyacf8f57b0b69deb6@mail.gmail.com> Message-ID: <6a7c66fc0802192325u78a922c5n69c393b10b96e501@mail.gmail.com> On Wed, Feb 20, 2008 at 8:22 AM, Alfonso Acosta wrote: > 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 meant vExp :: String -> Q (Exp (Vec a)) Sorry for the typo From alfonso.acosta at gmail.com Wed Feb 20 03:41:16 2008 From: alfonso.acosta at gmail.com (Alfonso Acosta) Date: Wed Feb 20 03:39:29 2008 Subject: [Template-haskell] Re: Polymorphism + Quasiquoting + Untyped AST = problems In-Reply-To: <20080220081217.GE4611@eecs.harvard.edu> References: <6a7c66fc0802192322q252ccb1fyacf8f57b0b69deb6@mail.gmail.com> <20080220081217.GE4611@eecs.harvard.edu> Message-ID: <6a7c66fc0802200041w6923b705y3f8f689ebd281bf6@mail.gmail.com> On Wed, Feb 20, 2008 at 9:12 AM, Geoffrey Mainland wrote: > On Wed, Feb 20, 2008 at 08:22:18AM +0100, Alfonso Acosta wrote: > > Hi, > > > > Let me show you why I reached that conclusion through a simple example. > > I can't help but feel I've missed some context :) Well, I'm probably bad at providing simplified examples ;). The real purpose of using quasiquoters is to help implementing fixed sized vectors (numerically parameterized lists using type-level numerals). See http://www.haskell.org/pipermail/haskell-cafe/2008-February/039801.html for details. > > Using "vector" is simple: > > > > $(vector [1,2,3,4,5]) > > Well, not so simple actually, as you'll get an "ambiguous type variable" > error unless you add a type signature. For instance: > > $(vector [1::Int,2,3,4,5]) True, I forgot to include the signature. However, even if a signature is required, vector can still be used to build vectors of any type, whereas that is not the case when using quasiquoters. > The real problem is that you can't splice in a polymorphic > variable. Witness: > > v = QuasiQuoter (fst . vExp) vPat > > vExp :: Read a => String -> (Q Exp, a) > vExp str = do let xs = (parseLTGT str) :: [a] > sanityCheck xs > ([| MkVec xs |], undefined) > Yes, I know. I thought it would maybe be possible if TH had a typed AST.