packages feed

SciFlow-0.7.0: src/Control/Workflow/Language/TH/Internal.hs

{-# LANGUAGE TemplateHaskell #-}

module Control.Workflow.Language.TH.Internal (link) where

import Control.Arrow
import Data.List (foldr1)
import           Language.Haskell.TH

link :: [String]  -- a list of parents
     -> ExpQ      -- child
     -> ExpQ
link [] x = x
link [s] x = [| $(varE $ mkName s) >>> $x |]
link [s1,s2] x = [| linkA2 $(varE $ mkName s1) $(varE $ mkName s2) $x |]
link [s1,s2,s3] x = [| linkA3 $(varE $ mkName s1) $(varE $ mkName s2) 
    $(varE $ mkName s3) $x |]
link [s1,s2,s3,s4] x = [| linkA4 $(varE $ mkName s1) $(varE $ mkName s2) 
    $(varE $ mkName s3) $(varE $ mkName s4) $x |]
link [s1,s2,s3,s4,s5] x = [| linkA5 $(varE $ mkName s1) $(varE $ mkName s2) 
    $(varE $ mkName s3) $(varE $ mkName s4) $(varE $ mkName s5) $x |]
link xs x = linkAN (map mkName xs) x
{-# INLINE link #-}

linkA2 :: Arrow arr => arr a b1 -> arr a b2 -> arr (b1, b2) c -> arr a c
linkA2 a1 a2 f = (a1 &&& a2) >>> f
{-# INLINE linkA2 #-}

linkA3 :: Arrow arr => arr a b1 -> arr a b2 -> arr a b3
       -> arr (b1, b2, b3) c
       -> arr a c
linkA3 a1 a2 a3 f = (a1 &&& a2 &&& a3) >>>
    arr (\(b1,(b2,b3)) -> (b1,b2,b3)) >>> f
{-# INLINE linkA3 #-}

linkA4 :: Arrow arr => arr a b1 -> arr a b2 -> arr a b3 -> arr a b4
       -> arr (b1, b2, b3, b4) c
       -> arr a c
linkA4 a1 a2 a3 a4 f = (a1 &&& a2 &&& a3 &&& a4) >>>
    arr (\(b1,(b2,(b3,b4))) -> (b1,b2,b3,b4)) >>> f
{-# INLINE linkA4 #-}

linkA5 :: Arrow arr => arr a b1 -> arr a b2 -> arr a b3 -> arr a b4 -> arr a b5
       -> arr (b1, b2, b3, b4, b5) c
       -> arr a c
linkA5 a1 a2 a3 a4 a5 f = (a1 &&& a2 &&& a3 &&& a4 &&& a5) >>>
    arr (\(b1,(b2,(b3,(b4,b5)))) -> (b1,b2,b3,b4,b5)) >>> f
{-# INLINE linkA5 #-}

linkAN :: [Name]  -- ^ a list of Arrows
       -> ExpQ
       -> ExpQ
linkAN as f = [| $arr1 >>> arr $arr2 >>> $f |]
  where
    arr1 = return $ foldr1 g $ map VarE as
      where
        g x1 x2 = AppE (AppE (VarE '(&&&)) x1) x2
    arr2 = return $ LamE [tuple1] $ TupE $ map VarE vars
      where
        tuple1 = go $ map VarP vars
          where
            go [x] = x
            go (x:xs) = TupP [x, go xs]
            go _ = error "empty list"
        vars = map (\i -> mkName $ "x" ++ show i) ([1..n] :: [Int])
    n = length as
{-# INLINE linkAN #-}