{-| Map the arguments and return value of functions. 

General use:

  - @f $* g1 $$ g2 … $$ gn *$ h = \\x1 … xn -> h (f (g1 x1) (g2 x2) … (gn xn))@

Examples:

  - @on f g = f $* g $$ g *$ id@
  - @comparing f = compare $* f $$ f *$ id@
  - @f . g = f $* g *$ id@

Related work:

  - <http://conal.net/blog/posts/semantic-editor-combinators Semantic Editor Combinators> 
    (Conal Elliott, 2008\/11\/24). Introduces composable editors for 
    function arguments and return values.
  - <http://matt.immute.net/content/pointless-fun Pointless Fun> (Matt 
    Hellige, 2008\/12\/03). Derives a similar operator named @~>@. This
    operator composes an editor which can then be applied to the subject
    to edit. This better agrees with Conal's concept of Semantic Editor 
    Combinators. In contrast, @$*@ includes the subject as part of the 
    editor, though you can write @($* g1 $$ g2 … $$ gn *$ h)@ for an 
    editor independent of the subject. Also, @~>@ is right-associative 
    whereas @$*@ and @$$@ are left-associative.
  - <http://hackage.haskell.org/package/TypeCompose-0.9.11/docs/Control-Compose.html TypeCompose version 0.9.11>
    (Conal Elliott, 2016\/01\/15). Package including an implementation of
    @~>@.
-}
module Data.Function.Meld
( ($*)
, ($$)
, (*$)
) where

import Prelude (flip)
import Control.Category (Category, (.), id)

-- | Map a function argument.
arg :: Category cat => cat a' a -> cat a b -> cat a' b
arg = flip (.)

-- | Map a function return value.
ret :: Category cat => cat b c -> cat a b -> cat a c
ret = (.)

-- | Begin melding.
--
-- @f $* g1 $$ g2 … $$ gn *$ h = \\x1 … xn -> h (f (g1 x1) (g2 x2) … (gn xn))@
($*) :: Category cat =>
           cat b c
        -> cat a b
        -> cat c d
        -> cat a d
($*) x f g = ret g (arg f x)
infixl 8 $*

-- | Continue melding.
--
-- @f $* g1 $$ g2 … $$ gn *$ h = \\x1 … xn -> h (f (g1 x1) (g2 x2) … (gn xn))@
($$) :: Category cat =>
           ((cat b c -> cat a d) -> e)
        -> cat a b 
        -> cat c d
        -> e
($$) f g h = f (ret h . arg g)
infixl 7 $$

-- | Finish melding.
--
-- @f $* g1 $$ g2 … $$ gn *$ h = \\x1 … xn -> h (f (g1 x1) (g2 x2) … (gn xn))@
(*$) :: Category cat => cat a b -> cat a b
(*$) = id
infixl 6 *$