{-| 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 *$