{-| Module : Control.Arrow.Needle.TH Description : Template Haskell for needle Copyright : (c) 2014 Josh Kirklin License : MIT Maintainer : jjvk2@cam.ac.uk This module combines the parsing from "Control.Arrow.Needle.Parse" with Template Haskell. -} {-# LANGUAGE TemplateHaskell, TupleSections #-} module Control.Arrow.Needle.TH ( nd , ndFile ) where import Prelude as Pre import Control.Arrow.Needle.Parse import Control.Arrow import Data.Maybe import Control.Applicative import Language.Haskell.TH import Language.Haskell.TH.Quote import Language.Haskell.Meta import Data.Either import Data.Text as T import Data.Map.Strict as M -- | The inline needle quasi-quoter. -- -- > {-# LANGUAGE QuasiQuotes #-} -- > -- > exampleArrow :: Num c => (a,b,c) -> (a,a,b,c,c) -- > exampleArrow = [nd| -- > }===========> -- > \========> -- > }===========> -- > }==={negate}> -- > \========> -- > |] nd :: QuasiQuoter nd = QuasiQuoter { quoteExp = \str -> case (parseNeedle str) of Left e -> error . presentNeedleError $ e Right n -> arrowQ n , quotePat = error "Needles cannot be patterns." , quoteDec = error "Needles cannot be declarations." , quoteType = error "Needles cannot be types." } -- | Load a needle from a file. -- -- > {-# LANGUAGE TemplateHaskell #-} -- > -- > exampleArrow :: Float -> Float -- > exampleArrow = $(ndFile "example.nd") ndFile :: FilePath -> ExpQ ndFile fp = do str <- runIO $ readFile fp case (parseNeedle str) of Left e -> error . presentNeedleError $ e Right n -> arrowQ n -- | Convert NeedleArrow to ExpQ arrowQ :: NeedleArrow -> ExpQ arrowQ arrow = do let is = inputs arrow iNameMap <- M.fromList <$> mapM (\(a,b) -> ((a,b),) <$> newName ("_" ++ show a ++ "_" ++ show b)) is let iNames = Pre.map snd $ M.toList iNameMap iName (Input a b) = iNameMap ! (a,b) f i@(Input a b) = return $ AppE (VarE $ mkName "arr") $ LamE [TupP $ Pre.map VarP iNames] (VarE (iName i)) f (Through ma t) = do let ea = either error id $ parseExp . T.unpack $ t b <- case ma of Nothing -> return $ AppE (VarE $ mkName "arr") $ LamE [TupP $ Pre.map VarP iNames] (ConE $ mkName "()") Just a -> f a return $ InfixE (Just b) (VarE $ mkName ">>>") (Just ea) f (Join as) = do aNames <- mapM (\n -> newName ("_" ++ show n)) [0..(Pre.length as - 1)] let tupleArrows [c] = f c tupleArrows (c:cs) = [| $(f c) &&& $(tupleArrows cs) |] tupleNames [n] = VarP n tupleNames (n:ns) = TupP [VarP n, tupleNames ns] b <- tupleArrows as return $ InfixE (Just b) (VarE $ mkName ">>>") $ Just $ AppE (VarE $ mkName "arr") $ LamE [tupleNames aNames] (TupE $ Pre.map VarE aNames) f arrow inputs :: NeedleArrow -> [(Int, Int)] inputs (Input a b) = [(a,b)] inputs (Through ma _) = maybe [] inputs ma inputs (Join as) = as >>= inputs