[Haskell-cafe] Template Haskell very wordy w/r/t Decs and Types

Simon Peyton-Jones simonpj at microsoft.com
Thu May 28 03:04:44 EDT 2009


You already have splicing for top level decls. Splicing for local decls is a whole different ball game because it brings new *binders* into scope.  For example

f = ...g...
g = let $(foo) in ...f...

Is the 'f' inside 'g' the same 'f' as the one bound at top level?  Not necessarily, because $(foo) might bind f.  So I can't even do dependency analysis to figure out whether f and g are mutually recursive!   It gets harder if $(foo) mentions 'f'; and if the definition of 'f' has a declaration splice too.

So splicing local decls introduces a new raft of questions whose answers are not obvious, and that might require some substantial structural rearrangement of GHC.  In particular to the "rename and then typecheck" strategy.   It's very similar to reason that we don't allow splices in patterns.

Bottom line: my nose tells me this is a swamp and I'm steering clear of it for now.

Simon

From: Matt Morrow [mailto:moonpatio at gmail.com]
Sent: 28 May 2009 00:08
To: Simon Peyton-Jones
Cc: Ross Mellgren; Haskell Cafe; GHC users
Subject: Re: [Haskell-cafe] Template Haskell very wordy w/r/t Decs and Types

Spectacular!

How difficult would it be to implement splicing in decls? I'm interested in having a go at it, and it seems like a perfect time since I can cheat off the fresh diff. In particular I'd love to be able to do stuff like this (without the current vicious hackery i'm using) (and granted, where i'm splicing is somewhat willy-nilly, but some approximation of this):

-----------------------------------------------------------------------------

{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
module DecTest where
import HsDec
import Data.List
import DecTestBoot
import Language.Haskell.TH.Lib
import Language.Haskell.TH.Syntax
import Language.Haskell.Meta.Utils

bootQ :: Q [Dec]
bootQ = bootQFunct
          primQStruct

primQStruct = (''[]
              ,(conT ''[] `appT`)
              ,[|[]|]
              ,[|null|]
              ,[|undefined|]
              ,[|union|]
              ,[|undefined|]
              ,[|undefined|])

bootQFunct
  (primN      :: Name
  ,primQ      :: TypeQ
              -> TypeQ  -- exists q. forall a. a -> q a
  ,emptyQ     :: ExpQ   -- Q a
  ,isEmptyQ   :: ExpQ   -- q a -> Bool
  ,insertQ    :: ExpQ   -- Int -> a -> q a -> q a
  ,mergeQ     :: ExpQ   -- q a -> q a -> q a
  ,findMinQ   :: ExpQ   -- q a -> Maybe (Int, a)
  ,deleteMinQ :: ExpQ)  -- q a -> q a

  = do  n <- newName "a"
        let primT = varT primN
            a = varT n

        [$dec|
          data BootQ $(a)
            = Nil
            | Node {-# UNPACK #-} !Int $(a) ($(primT) (BootQ $(a)))
            deriving(Eq,Ord)

          empty     :: BootQ $(a)
          isEmpty   :: BootQ $(a) -> Bool
          insert    :: Int -> $(a) -> BootQ $(a) -> BootQ $(a)
          merge     :: BootQ $(a) -> BootQ $(a) -> BootQ $(a)
          findMin   :: BootQ $(a) -> Maybe (Int, $(a))
          deleteMin :: BootQ $(a) -> BootQ $(a)

          empty = Nil
          isEmpty Nil = True
          isEmpty   _ = False
          findMin  Nil = Nothing
          findMin (Node n x _) = Just (n, x)
          insert n x q = merge (Node n x $(emptyQ)) q
          merge (Node n1 x1 q1)
                (Node n2 x2 q2)
            | n1 <= n2  = Node n1 x1 ($(insertQ) n2 (Node n2 x2 q2) q1)
            | otherwise = Node n2 x2 ($(insertQ) n1 (Node n1 x1 q1) q2)
          merge Nil q  = q
          merge q  Nil = q
          deleteMin  Nil = Nil
          deleteMin (Node _ _ q)
            = case $(findMinQ) q of
                Nothing -> Nil
                Just (_, Node m y q1)
                  -> let q2 = $(deleteMinQ) q
                      in Node m y ($(mergeQ) q1 q2)
            |]


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20090528/4d96f78f/attachment.html


More information about the Haskell-Cafe mailing list