{-# LANGUAGE TemplateHaskell #-}
{-| Control.Concatenative brings concatenative combinators in the style of factor
    (see <http://docs.factorcode.org/content/article-dataflow-combinators.html>)
    to haskell in a variety of interfaces, allowing a terse, pointfree style. 
-}
module Control.Concatenative (
    -- * Postfix combinators
    
    -- | These concatenative combinators essentially apply multiple functions to
    --   one or more values before combining all the results using another
    --   function.
    --   Without concatenative combinators:
    --
    -- > \x-> (x+1) + (subtract 1 x)
    --
    --   With concatenative combinators:
    --
    -- > bi (+1) (subtract 1) (+)
    
    bi, tri, biSp, triSp, biAp, triAp, ifte,
    biM, triM, biSpM, triSpM, biApM, triApM,
    biM_, triM_, biApM_, triApM_,
    
    -- * Postfix arrows
    
    -- | The arrow functions '&&.' and '**.' are equivalent to 'bi' and 'biSp'.
    -- Combining here must be done seperately, through the '>>@' function.
    
    (>>@), dup, swap, both,
    (>>.), (&&.), (**.), first, second,
    
    -- * Generalized Datatypes
    
    -- | The Concatenative datatype can be used to cleave, spread, or
    --   apply any number of functions and values. 
    --   Using the 'bi' combinator:
    --
    -- > bi (+1) (subtract 1) (+)
    --
    --   is equivalent to using the '&.' function:
    --
    -- > with ((+1) &. (subtract 1)) (+)
    --
    --   and may be generalized to any number of functions:
    --
    -- > with ((subtract 10) &. (+1) .&. (*50)) enumFromThenTo
    --
    --   '*.' similarly generalizes 'biSp', and 'cl' and 'sp' generalize
    --   their monadic variants. Generic application presents a problem for the
    --   type system, however, and the library resorts to template haskell:
    --
    -- > biAp (+1)
    --
    --   translates to
    --
    -- > $(apN 2) (+1)
    
    Concatenative(..),
    cat, (&.), (.&.), (*.), (.*.),
    catM, clM, cl, spM, sp,
    apN, apM, apM_
    ) where
import Control.Arrow
import Control.Monad
import Language.Haskell.TH

-- Function Interface

-- | Apply both arguments to a and combine the results
bi :: (a -> b) -> (a -> c) -> (b -> c -> d) -> a -> d
bi :: (a -> b) -> (a -> c) -> (b -> c -> d) -> a -> d
bi f :: a -> b
f g :: a -> c
g c :: b -> c -> d
c x :: a
x = b -> c -> d
c (a -> b
f a
x) (a -> c
g a
x)

-- | Apply each of three arguments to a and combine the results
tri :: (a -> b) -> (a -> c) -> (a -> d) -> (b -> c -> d -> e) -> a -> e
tri :: (a -> b) -> (a -> c) -> (a -> d) -> (b -> c -> d -> e) -> a -> e
tri f :: a -> b
f g :: a -> c
g h :: a -> d
h c :: b -> c -> d -> e
c x :: a
x = b -> c -> d -> e
c (a -> b
f a
x) (a -> c
g a
x) (a -> d
h a
x)

-- | Apply the first argument to a, the second to b, and combine the results
biSp :: (a -> c) -> (b -> d) -> (c -> d -> e) -> a -> b -> e
biSp :: (a -> c) -> (b -> d) -> (c -> d -> e) -> a -> b -> e
biSp f :: a -> c
f g :: b -> d
g c :: c -> d -> e
c x :: a
x y :: b
y = c -> d -> e
c (a -> c
f a
x) (b -> d
g b
y)

-- | Apply the first argument to a, the second to b, and the third to c, combining the results
triSp :: (a -> d) -> (b -> e) -> (c -> f) -> (d -> e -> f -> g) -> a -> b -> c -> g
triSp :: (a -> d)
-> (b -> e) -> (c -> f) -> (d -> e -> f -> g) -> a -> b -> c -> g
triSp f :: a -> d
f g :: b -> e
g h :: c -> f
h c :: d -> e -> f -> g
c x :: a
x y :: b
y z :: c
z = d -> e -> f -> g
c (a -> d
f a
x) (b -> e
g b
y) (c -> f
h c
z)

-- | Apply a function to two values and combine the results
biAp :: (t -> t1) -> (t1 -> t1 -> t2) -> t -> t -> t2
biAp :: (t -> t1) -> (t1 -> t1 -> t2) -> t -> t -> t2
biAp f :: t -> t1
f c :: t1 -> t1 -> t2
c x :: t
x y :: t
y = t1 -> t1 -> t2
c (t -> t1
f t
x) (t -> t1
f t
y)

-- | Apply a function to three values and combine the results
triAp :: (a -> b) -> (b -> b -> b -> c) -> a -> a -> a -> c
triAp :: (a -> b) -> (b -> b -> b -> c) -> a -> a -> a -> c
triAp f :: a -> b
f c :: b -> b -> b -> c
c x :: a
x y :: a
y z :: a
z = b -> b -> b -> c
c (a -> b
f a
x) (a -> b
f a
y) (a -> b
f a
z)

ifte :: (a -> Bool) -- ^ A predicate
     -> (a -> b)    -- ^ Applied if the predicate yields True
     -> (a -> b)    -- ^ Applied if the predicate yields False
     -> a -> b
ifte :: (a -> Bool) -> (a -> b) -> (a -> b) -> a -> b
ifte test :: a -> Bool
test ca :: a -> b
ca cb :: a -> b
cb x :: a
x =
    if a -> Bool
test a
x then a -> b
ca a
x else a -> b
cb a
x

-- Monad Utilities

-- | Like 'bi', but functions can return monadic values
biM :: Monad m => (a -> m b) -> (a -> m c) -> (b -> c -> m d) -> a -> m d
biM :: (a -> m b) -> (a -> m c) -> (b -> c -> m d) -> a -> m d
biM f :: a -> m b
f g :: a -> m c
g c :: b -> c -> m d
c a :: a
a = do
    b
x <- a -> m b
f a
a
    c
y <- a -> m c
g a
a
    b -> c -> m d
c b
x c
y

-- | Like 'biM', but throws away the end result
biM_ :: Monad m => (a -> m b) -> (a -> m c) -> a -> m ()
biM_ :: (a -> m b) -> (a -> m c) -> a -> m ()
biM_ f :: a -> m b
f g :: a -> m c
g a :: a
a = a -> m b
f a
a m b -> m c -> m c
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> a -> m c
g a
a m c -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- | Like 'tri', but functions can return monadic values
triM :: Monad m => (a -> m b) -> (a -> m c) -> (a -> m d) -> (b -> c -> d -> m e) -> a -> m e
triM :: (a -> m b)
-> (a -> m c) -> (a -> m d) -> (b -> c -> d -> m e) -> a -> m e
triM f :: a -> m b
f g :: a -> m c
g l :: a -> m d
l c :: b -> c -> d -> m e
c a :: a
a = do
    b
x <- a -> m b
f a
a
    c
y <- a -> m c
g a
a
    d
z <- a -> m d
l a
a
    b -> c -> d -> m e
c b
x c
y d
z

-- | Like 'triM', but throws away the end result
triM_ :: Monad m => (a -> m b) -> (a -> m c) -> (a -> m d) -> a -> m ()
triM_ :: (a -> m b) -> (a -> m c) -> (a -> m d) -> a -> m ()
triM_ f :: a -> m b
f g :: a -> m c
g l :: a -> m d
l a :: a
a = a -> m b
f a
a m b -> m c -> m c
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> a -> m c
g a
a m c -> m d -> m d
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> a -> m d
l a
a m d -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- | Like 'biSp', but functions can return monadic values
biSpM :: Monad m => (a -> m c) -> (b -> m d) -> (c -> d -> m e) -> a -> b -> m e
biSpM :: (a -> m c) -> (b -> m d) -> (c -> d -> m e) -> a -> b -> m e
biSpM f :: a -> m c
f g :: b -> m d
g c :: c -> d -> m e
c x :: a
x y :: b
y = do
    c
a <- a -> m c
f a
x
    d
b <- b -> m d
g b
y
    c -> d -> m e
c c
a d
b

-- | Like 'triSp', but functions can return monadic values
triSpM :: Monad m => (a -> m d) -> (b -> m e) -> (c -> m f) -> (d -> e -> f -> m g) -> a -> b -> c -> m g
triSpM :: (a -> m d)
-> (b -> m e)
-> (c -> m f)
-> (d -> e -> f -> m g)
-> a
-> b
-> c
-> m g
triSpM f :: a -> m d
f g :: b -> m e
g h :: c -> m f
h c :: d -> e -> f -> m g
c x :: a
x y :: b
y z :: c
z = do
    d
a <- a -> m d
f a
x
    e
b <- b -> m e
g b
y
    f
n <- c -> m f
h c
z
    d -> e -> f -> m g
c d
a e
b f
n

-- | Like 'biAp', but functions can return monadic values
biApM :: Monad m => (t -> m t1) -> (t1 -> t1 -> m t2) -> t -> t -> m t2
biApM :: (t -> m t1) -> (t1 -> t1 -> m t2) -> t -> t -> m t2
biApM f :: t -> m t1
f c :: t1 -> t1 -> m t2
c x :: t
x y :: t
y = do
    t1
a <- t -> m t1
f t
x
    t1
b <- t -> m t1
f t
y
    t1 -> t1 -> m t2
c t1
a t1
b

-- | Like 'biApM', but throws away the end result
biApM_ :: Monad m => (t -> m t1) -> t -> t -> m ()
biApM_ :: (t -> m t1) -> t -> t -> m ()
biApM_ f :: t -> m t1
f x :: t
x y :: t
y = t -> m t1
f t
x m t1 -> m t1 -> m t1
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> t -> m t1
f t
y m t1 -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- | Like 'triAp', but functions can return monadic values
triApM :: Monad m => (a -> m b) -> (b -> b -> b -> m c) -> a -> a -> a -> m c
triApM :: (a -> m b) -> (b -> b -> b -> m c) -> a -> a -> a -> m c
triApM f :: a -> m b
f c :: b -> b -> b -> m c
c x :: a
x y :: a
y z :: a
z = do
    b
a <- a -> m b
f a
x
    b
b <- a -> m b
f a
y
    b
n <- a -> m b
f a
z
    b -> b -> b -> m c
c b
a b
b b
n

-- | Like 'triApM', but throws away the end result
triApM_ :: Monad m => (a -> m b) -> a -> a -> a-> m ()
triApM_ :: (a -> m b) -> a -> a -> a -> m ()
triApM_ f :: a -> m b
f x :: a
x y :: a
y z :: a
z = a -> m b
f a
x m b -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> a -> m b
f a
y m b -> m b -> m b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> a -> m b
f a
z m b -> m () -> m ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- Arrow Interface

infixl 3 >>@
infixl 3 &&.
infixl 3 **.
infixl 4 >>.

-- |Left associative version of '&&&'
(&&.) :: Arrow a => a b c -> a b c' -> a b (c, c')
&&. :: a b c -> a b c' -> a b (c, c')
(&&.) = a b c -> a b c' -> a b (c, c')
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
(&&&)

-- |Left associative version of '***'
(**.) :: Arrow a => a b c -> a b' c' -> a (b,b') (c,c')
**. :: a b c -> a b' c' -> a (b, b') (c, c')
(**.) = a b c -> a b' c' -> a (b, b') (c, c')
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
(***)

-- |Left associative version of '>>>'
(>>.) :: Arrow a => a b c -> a c d -> a b d
>>. :: a b c -> a c d -> a b d
(>>.) = a b c -> a c d -> a b d
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
(>>>)

-- | Combine with a binary function
(>>@) :: Arrow a => a b (x,y) -> (x -> y -> z) -> a b z
a :: a b (x, y)
a >>@ :: a b (x, y) -> (x -> y -> z) -> a b z
>>@ f :: x -> y -> z
f = a b (x, y)
a a b (x, y) -> a (x, y) z -> a b z
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> ((x, y) -> z) -> a (x, y) z
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr (\(x :: x
x,y :: y
y) -> x -> y -> z
f x
x y
y)

-- | Arrow version of 'biAp'
both :: Arrow a => a b c -> a (b,b) (c,c)
both :: a b c -> a (b, b) (c, c)
both a :: a b c
a = a b c -> a (b, b) (c, b)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first a b c
a a (b, b) (c, b) -> a (c, b) (c, c) -> a (b, b) (c, c)
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> a b c -> a (c, b) (c, c)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second a b c
a

dup :: Arrow a => a b (b,b)
dup :: a b (b, b)
dup = (b -> (b, b)) -> a b (b, b)
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr (\x :: b
x-> (b
x,b
x))

swap :: Arrow a => a (x,y) (y,x)
swap :: a (x, y) (y, x)
swap = ((x, y) -> (y, x)) -> a (x, y) (y, x)
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr (\(x :: x
x,y :: y
y) -> (y
y,x
x))

-- Datatypes

-- | Concatenative continuation
newtype Concatenative a b c d = Concatenative { Concatenative a b c d -> (b -> c) -> a -> d
with :: (b -> c) -> (a -> d) }

-- | Lifts a function into 'Concatenative'
cat :: (a -> b) -> Concatenative a b c c
cat :: (a -> b) -> Concatenative a b c c
cat f :: a -> b
f = ((b -> c) -> a -> c) -> Concatenative a b c c
forall a b c d. ((b -> c) -> a -> d) -> Concatenative a b c d
Concatenative ((b -> c) -> (a -> b) -> a -> c
forall b c a. (b -> c) -> (a -> b) -> a -> c
.a -> b
f)

-- | Construct a 'Concatenative' for cleaving
(.&.) :: Concatenative a b c d -> (a -> e) -> Concatenative a b (e -> c) d
(Concatenative l :: (b -> c) -> a -> d
l) .&. :: Concatenative a b c d -> (a -> e) -> Concatenative a b (e -> c) d
.&. f :: a -> e
f = ((b -> e -> c) -> a -> d) -> Concatenative a b (e -> c) d
forall a b c d. ((b -> c) -> a -> d) -> Concatenative a b c d
Concatenative (((b -> e -> c) -> a -> d) -> Concatenative a b (e -> c) d)
-> ((b -> e -> c) -> a -> d) -> Concatenative a b (e -> c) d
forall a b. (a -> b) -> a -> b
$ \c :: b -> e -> c
c a :: a
a-> (b -> c) -> a -> d
l ((b -> e -> c) -> e -> b -> c
forall a b c. (a -> b -> c) -> b -> a -> c
flip b -> e -> c
c (a -> e
f a
a)) a
a

-- | Lift a function and add it to a 'Concatenative' for cleaving
(&.) :: (a -> b) -> (a -> e) -> Concatenative a b (e -> c) c
f :: a -> b
f &. :: (a -> b) -> (a -> e) -> Concatenative a b (e -> c) c
&. g :: a -> e
g = ((a -> b) -> Concatenative a b c c
forall a b c. (a -> b) -> Concatenative a b c c
cat a -> b
f) Concatenative a b c c -> (a -> e) -> Concatenative a b (e -> c) c
forall a b c d e.
Concatenative a b c d -> (a -> e) -> Concatenative a b (e -> c) d
.&. a -> e
g

-- | Construct a 'Concatenative' for spreading
(.*.) :: Concatenative a b c d -> (e -> f) -> Concatenative e b (f -> c) (a -> d)
(Concatenative l :: (b -> c) -> a -> d
l) .*. :: Concatenative a b c d
-> (e -> f) -> Concatenative e b (f -> c) (a -> d)
.*. f :: e -> f
f = ((b -> f -> c) -> e -> a -> d)
-> Concatenative e b (f -> c) (a -> d)
forall a b c d. ((b -> c) -> a -> d) -> Concatenative a b c d
Concatenative (((b -> f -> c) -> e -> a -> d)
 -> Concatenative e b (f -> c) (a -> d))
-> ((b -> f -> c) -> e -> a -> d)
-> Concatenative e b (f -> c) (a -> d)
forall a b. (a -> b) -> a -> b
$ \c :: b -> f -> c
c e :: e
e-> (b -> c) -> a -> d
l ((b -> f -> c) -> f -> b -> c
forall a b c. (a -> b -> c) -> b -> a -> c
flip b -> f -> c
c (e -> f
f e
e))

-- | Lift a function and add it to a 'Concatenative' for spreading
(*.) :: (t -> b) -> (a -> b1) -> Concatenative a b (b1 -> c) (t -> c)
f :: t -> b
f *. :: (t -> b) -> (a -> b1) -> Concatenative a b (b1 -> c) (t -> c)
*. g :: a -> b1
g = ((t -> b) -> Concatenative t b c c
forall a b c. (a -> b) -> Concatenative a b c c
cat t -> b
f) Concatenative t b c c
-> (a -> b1) -> Concatenative a b (b1 -> c) (t -> c)
forall a b c d e f.
Concatenative a b c d
-> (e -> f) -> Concatenative e b (f -> c) (a -> d)
.*. a -> b1
g

-- | Lift a monadic function to a 'Concatenative'
catM :: Monad m => (a -> m b) -> Concatenative a b (m c) (m c)
catM :: (a -> m b) -> Concatenative a b (m c) (m c)
catM f :: a -> m b
f = ((b -> m c) -> a -> m c) -> Concatenative a b (m c) (m c)
forall a b c d. ((b -> c) -> a -> d) -> Concatenative a b c d
Concatenative (((b -> m c) -> a -> m c) -> Concatenative a b (m c) (m c))
-> ((b -> m c) -> a -> m c) -> Concatenative a b (m c) (m c)
forall a b. (a -> b) -> a -> b
$ \c :: b -> m c
c a :: a
a-> a -> m b
f a
a m b -> (b -> m c) -> m c
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= b -> m c
c

-- | Construct a 'Concatenative' for spreading monadic functions
clM :: Monad m => Concatenative a b c (m d) -> (a -> m e) -> Concatenative a b (e -> c) (m d)
(Concatenative l :: (b -> c) -> a -> m d
l) `clM ` f :: a -> m e
f = ((b -> e -> c) -> a -> m d) -> Concatenative a b (e -> c) (m d)
forall a b c d. ((b -> c) -> a -> d) -> Concatenative a b c d
Concatenative (((b -> e -> c) -> a -> m d) -> Concatenative a b (e -> c) (m d))
-> ((b -> e -> c) -> a -> m d) -> Concatenative a b (e -> c) (m d)
forall a b. (a -> b) -> a -> b
$ \c :: b -> e -> c
c a :: a
a-> a -> m e
f a
a m e -> (e -> m d) -> m d
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (\x :: e
x-> (b -> c) -> a -> m d
l ((b -> e -> c) -> e -> b -> c
forall a b c. (a -> b -> c) -> b -> a -> c
flip b -> e -> c
c e
x) a
a)

-- | Lift a monadic function and add it to a 'Concatenative' for cleaving
cl :: (Monad m) => (a -> m b) -> (a -> m e) -> Concatenative a b (e -> m d) (m d)
f :: a -> m b
f cl :: (a -> m b) -> (a -> m e) -> Concatenative a b (e -> m d) (m d)
`cl` g :: a -> m e
g = ((a -> m b) -> Concatenative a b (m d) (m d)
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> Concatenative a b (m c) (m c)
catM a -> m b
f) Concatenative a b (m d) (m d)
-> (a -> m e) -> Concatenative a b (e -> m d) (m d)
forall (m :: * -> *) a b c d e.
Monad m =>
Concatenative a b c (m d)
-> (a -> m e) -> Concatenative a b (e -> c) (m d)
`clM` a -> m e
g

-- | Construct a 'Concatenative' for spreading monadic functions
spM :: Monad m => Concatenative a b c (m d) -> (e -> m f) -> Concatenative e b (f -> c) (a -> m d)
(Concatenative l :: (b -> c) -> a -> m d
l) spM :: Concatenative a b c (m d)
-> (e -> m f) -> Concatenative e b (f -> c) (a -> m d)
`spM` f :: e -> m f
f = ((b -> f -> c) -> e -> a -> m d)
-> Concatenative e b (f -> c) (a -> m d)
forall a b c d. ((b -> c) -> a -> d) -> Concatenative a b c d
Concatenative (((b -> f -> c) -> e -> a -> m d)
 -> Concatenative e b (f -> c) (a -> m d))
-> ((b -> f -> c) -> e -> a -> m d)
-> Concatenative e b (f -> c) (a -> m d)
forall a b. (a -> b) -> a -> b
$ \c :: b -> f -> c
c e :: e
e a :: a
a-> e -> m f
f e
e m f -> (f -> m d) -> m d
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \x :: f
x-> (b -> c) -> a -> m d
l ((b -> f -> c) -> f -> b -> c
forall a b c. (a -> b -> c) -> b -> a -> c
flip b -> f -> c
c f
x) a
a 

-- | Lift a monadic function and add it to a 'Concatenative' for spreading
sp :: (Monad m) => (a -> m b) -> (e -> m f) -> Concatenative e b (f -> m d) (a -> m d)
f :: a -> m b
f sp :: (a -> m b) -> (e -> m f) -> Concatenative e b (f -> m d) (a -> m d)
`sp` g :: e -> m f
g = ((a -> m b) -> Concatenative a b (m d) (m d)
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> Concatenative a b (m c) (m c)
catM a -> m b
f) Concatenative a b (m d) (m d)
-> (e -> m f) -> Concatenative e b (f -> m d) (a -> m d)
forall (m :: * -> *) a b c d e f.
Monad m =>
Concatenative a b c (m d)
-> (e -> m f) -> Concatenative e b (f -> c) (a -> m d)
`spM` e -> m f
g

-- | Create a 'Concatenative' for applying a function n times
--
-- > biAp (+1)
--
--   translates to
--
-- > $(apN 2) (+1)
apN :: Int -> Q Exp
apN :: Int -> Q Exp
apN n :: Int
n = [| \f-> $(apN' n) f |] where
    apN' :: Int -> Q Exp
    apN' :: Int -> Q Exp
apN' n :: Int
n | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 1 = [| \f-> $(apN' (n-1)) f .*. f |]
           | Bool
otherwise = [| cat |]

-- | Create a 'Concatenative' for applying a monadic function n times
--
-- > biApM (+1)
--
--   translates to
--
-- > $(apM 2) (+1)
apM :: Int -> Q Exp
apM :: Int -> Q Exp
apM n :: Int
n = [| \f-> $(apM' n) f |] where
    apM' :: Int -> Q Exp
    apM' :: Int -> Q Exp
apM' n :: Int
n | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 1 = [| \f-> $(apM' (n-1)) f `spM` f |]
           | Bool
otherwise = [| catM |]

-- | Convenience synonym for 'replicateM_'
apM_ :: Monad m => Int -> m a -> m ()
apM_ :: Int -> m a -> m ()
apM_ = Int -> m a -> m ()
forall (m :: * -> *) a. Applicative m => Int -> m a -> m ()
replicateM_