module TupleTH(
htuple,
mapTuple, mapTuple', filterTuple, filterTuple', reindexTuple, reverseTuple, rotateTuple,
zipTuple, catTuples,uncatTuple,
zipTupleWith, zipTupleWith',
safeTupleFromList, tupleFromList, constTuple,
proj, elemTuple, tupleToList, sumTuple,
foldrTuple, foldrTuple',
foldr1Tuple, foldr1Tuple',
foldlTuple, foldlTuple',
foldl1Tuple, foldl1Tuple',
andTuple, orTuple,
anyTuple, anyTuple',
allTuple, allTuple',
sequenceTuple, sequenceATuple
) where
import Language.Haskell.TH
import Data.Maybe
import Data.Functor
import Data.List()
import Control.Monad
import Control.Applicative
htuple :: Int -> TypeQ -> TypeQ
htuple n t = foldl appT (tupleT n) (replicate n t)
withxs :: Int -> (PatQ -> [ExpQ] -> Q b) -> Q b
withxs = withNames "x"
withys :: Int -> (PatQ -> [ExpQ] -> Q b) -> Q b
withys = withNames "y"
newNames :: String -> Int -> Q [Name]
newNames stem n = sequence [newName (stem++show i) | i <- [ 1::Int .. n ]]
withNames :: String -> Int -> (PatQ -> [ExpQ] -> Q b) -> Q b
withNames stem n body = do
names <- newNames stem n
body (tupP (fmap varP names)) (fmap varE names)
withNames2 :: String-> String-> Int-> (PatQ -> [ExpQ] -> PatQ -> [ExpQ] -> Q b)-> Q b
withNames2 stem1 stem2 n body =
withNames stem1 n (\xsp xes -> withNames stem2 n (body xsp xes))
appE2 :: ExpQ -> ExpQ -> ExpQ -> ExpQ
appE2 f x y = f `appE` x `appE` y
liftExpFun :: String -> (ExpQ -> ExpQ) -> Q Exp
liftExpFun argNameStem f = do
argName <- newName argNameStem
lam1E (varP argName) (f (varE argName))
zipTuple :: Int -> Q Exp
zipTuple n = zipTupleWith' n (conE (tupleDataName n))
zipTupleWith :: Int -> ExpQ
zipTupleWith n = liftExpFun "f" (zipTupleWith' n)
zipTupleWith' :: Int -> ExpQ -> ExpQ
zipTupleWith' n f =
withNames2 "x" "y" n
(\xsp xes ysp yes ->
lamE [xsp,ysp] (tupE (zipWith (appE2 f) xes yes)))
proj :: Int
-> Int
-> ExpQ
proj n i = do
x <- newName "x"
lam1E (tupP (replicate i wildP ++ [ varP x ] ++ replicate (ni1) wildP)) (varE x)
foldrTuple :: Int -> ExpQ
foldrTuple n = liftExpFun "c" (foldrTuple' n)
foldrTuple' :: Int -> ExpQ -> ExpQ
foldrTuple' n c = do
z <- newName "z"
withxs n (\xsp xes -> lamE [varP z, xsp] (foldr (appE2 c) (varE z) xes))
foldr1Tuple :: Int -> ExpQ
foldr1Tuple n = liftExpFun "c" (foldr1Tuple' n)
foldr1Tuple' :: Int -> ExpQ -> Q Exp
foldr1Tuple' n c = withxs n (\xsp xes -> lam1E xsp (foldr1 (appE2 c) xes))
foldlTuple :: Int -> ExpQ
foldlTuple n = liftExpFun "c" (foldlTuple' n)
foldlTuple' :: Int -> ExpQ -> ExpQ
foldlTuple' n c = do
z <- newName "z"
withxs n (\xsp xes -> lamE [varP z, xsp] (foldl (appE2 c) (varE z) xes))
foldl1Tuple :: Int -> ExpQ
foldl1Tuple n = liftExpFun "c" (foldl1Tuple' n)
foldl1Tuple' :: Int -> ExpQ -> Q Exp
foldl1Tuple' n c = withxs n (\xsp xes -> lam1E xsp (foldl1 (appE2 c) xes))
filterTuple :: Int -> ExpQ
filterTuple n = liftExpFun "p" (filterTuple' n)
filterTuple' :: Int -> ExpQ -> ExpQ
filterTuple' n p = withxs n (\xsp xes -> lamE [xsp] (go xes))
where
go [] = [| [] |]
go [x] = [| if $(p) $(x) then [$(x)] else [] |]
go (x:xs) = [| (if $(p) $(x) then ($(x) :) else id) $(go xs) |]
mapTuple :: Int -> ExpQ
mapTuple n = liftExpFun "f" (mapTuple' n)
mapTuple' :: Int -> ExpQ -> Q Exp
mapTuple' n f = withxs n (\xsp xes ->
lamE [xsp] (tupE [f `appE` x | x <- xes ]))
smatch :: PatQ -> ExpQ -> MatchQ
smatch p e = match p (normalB e) []
safeTupleFromList :: Int -> Q Exp
safeTupleFromList n = do
xns <- newNames "x" n
let xps = varP <$> xns
xes = varE <$> xns
xs <- newName "xs"
lam1E (varP xs) (caseE (varE xs)
[ smatch (listP xps) (conE 'Just `appE` (tupE xes))
, smatch wildP (conE 'Nothing)
])
tupleFromList :: Int -> Q Exp
tupleFromList n = [| \xs0 -> fromMaybe (error (msg ++ show (length xs0))) ( $(safeTupleFromList n) xs0 ) |]
where
msg = "tupleFromList "++show n++" called on a list of length "
orTuple :: Int -> Q Exp
orTuple 0 = [| False |]
orTuple n = foldl1Tuple' n [| (||) |]
andTuple :: Int -> Q Exp
andTuple 0 = [| True |]
andTuple n = foldl1Tuple' n [| (&&) |]
anyTuple :: Int -> Q Exp
anyTuple n = liftExpFun "p" (anyTuple' n)
allTuple :: Int -> Q Exp
allTuple n = liftExpFun "p" (allTuple' n)
anyTuple' :: Int -> Q Exp -> Q Exp
anyTuple' n p = [| $(orTuple n) . $(mapTuple' n p) |]
allTuple' :: Int -> Q Exp -> Q Exp
allTuple' n p = [| $(andTuple n) . $(mapTuple' n p) |]
elemTuple :: Int -> Q Exp
elemTuple n = do
z <- newName "z"
lam1E (varP z) (anyTuple' n [| (== $(varE z)) |])
tupleToList :: Int -> Q Exp
tupleToList n = [| $(foldrTuple' n (conE '(:))) [] |]
catTuples :: Int -> Int -> Q Exp
catTuples n m = withxs n (\xsp xes -> withys m (\ysp yes ->
lamE [xsp,ysp] (tupE (xes ++ yes))))
uncatTuple :: Int -> Int -> Q Exp
uncatTuple n m = withxs (n+m) (\xsp xes ->
lam1E xsp (tupE [tupE (take n xes), tupE (drop n xes) ]))
reindexTuple :: Int -> [Int] -> Q Exp
reindexTuple n is = withxs n (\xsp xes ->
lam1E xsp (tupE (fmap (xes !!) is)))
reverseTuple :: Int -> Q Exp
reverseTuple n = reindexTuple n (reverse [0..n1])
rotateTuple :: Int -> Int -> Q Exp
rotateTuple n k = reindexTuple n (fmap (`mod` n) [nk, nk+1 .. 2*nk1])
sumTuple :: Int -> Q Exp
sumTuple 0 = litE (integerL 0)
sumTuple n = foldl1Tuple' n (varE '(+))
constTuple :: Int -> Q Exp
constTuple n = reindexTuple 1 (replicate n 0)
sequenceTuple :: Int -> Q Exp
sequenceTuple 0 = [| return () |]
sequenceTuple 1 = [| id :: Monad m => m a -> m a |]
sequenceTuple n =
withxs n (\xsp xes ->
lam1E xsp (foldl (\x y -> [| $(x) `ap` $(y) |])
[| $(conE $ tupleDataName n) `liftM` $(head xes) |]
(tail xes)))
sequenceATuple :: Int -> Q Exp
sequenceATuple 0 = [| pure () |]
sequenceATuple 1 = [| id :: Applicative f => f a -> f a |]
sequenceATuple n =
withxs n (\xsp xes ->
lam1E xsp (foldl (\x y -> [| $(x) <*> $(y) |])
[| $(conE $ tupleDataName n) <$> $(head xes) |]
(tail xes)))