defun-core-0.1: src/DeFun/Function.hs
{-# LANGUAGE Trustworthy #-}
-- | Defunctionalized function combinators,
-- from [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
-- and [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system) combinator calculi.
--
-- These may be useful for writing anonymous functions in point-free style,
-- as pointful style would require extra defunctionalization symbols
-- (see e.g. t'DeFun.List.Map2' for an example).
--
module DeFun.Function (
-- * Id, I
Id, IdSym,
id, idSym,
-- * Const, K
Const, ConstSym, ConstSym1,
const, constSym, constSym1,
-- * Flip, C
Flip, FlipSym, FlipSym1, FlipSym2,
flip, flipSym, flipSym1, flipSym2,
-- * Comp, B
Comp, CompSym, CompSym1, CompSym2,
comp, compSym, compSym1, compSym2,
-- * Ap, S
Ap, ApSym, ApSym1, ApSym2,
ap, apSym, apSym1, apSym2,
-- * Join, W
Join, JoinSym, JoinSym1,
join, joinSym, joinSym1,
) where
import DeFun.Core
-- $setup
-- >>> import Prelude (Bool (..))
-- >>> import Data.Singletons.Bool (SBool (..))
-- >>> import DeFun
-- | Identity function. Combinator @I@ in https://en.wikipedia.org/wiki/SKI_combinator_calculus.
type Id :: a -> a
type family Id x where
Id x = x
type IdSym :: a ~> a
data IdSym x
type instance App IdSym x = Id x
id :: a x -> a (Id x)
id x = x
idSym :: Lam a a IdSym
idSym = Lam id
--
-- | Constant function. Combinator @K@ in https://en.wikipedia.org/wiki/SKI_combinator_calculus and https://en.wikipedia.org/wiki/B,_C,_K,_W_system.
type Const :: a -> b -> a
type family Const x y where
Const x y = x
type ConstSym :: a ~> b ~> a
data ConstSym x
type instance App ConstSym x = ConstSym1 x
type ConstSym1 :: a -> b ~> a
data ConstSym1 x y
type instance App (ConstSym1 x) y = Const x y
const :: a x -> b y -> a x
const x _ = x
constSym :: Lam2 a b a ConstSym
constSym = Lam constSym1
constSym1 :: a x -> Lam b a (ConstSym1 x)
constSym1 x = Lam (const x)
-- | Function flip. Combinator @C@ in https://en.wikipedia.org/wiki/B,_C,_K,_W_system.
type Flip :: (a ~> b ~> c) -> b -> a -> c
type family Flip f b a where
Flip f b a = f @@ a @@ b
type FlipSym :: (a ~> b ~> c) ~> b ~> a ~> c
data FlipSym f
type instance App FlipSym f = FlipSym1 f
type FlipSym1 :: (a ~> b ~> c) -> b ~> a ~> c
data FlipSym1 f x
type instance App (FlipSym1 f) x = FlipSym2 f x
type FlipSym2 :: (a ~> b ~> c) -> b -> a ~> c
data FlipSym2 f b a
type instance App (FlipSym2 f b) a = Flip f b a
flip :: Lam2 a b c f -> b x -> a y -> c (Flip f x y)
flip f b a = f @@ a @@ b
flipSym :: Lam (a :~> b :~> c) (b :~> a :~> c) FlipSym
flipSym = Lam flipSym1
flipSym1 :: Lam2 a b c f -> Lam2 b a c (FlipSym1 f)
flipSym1 f = Lam (flipSym2 f)
flipSym2 :: Lam2 a b c f -> b x -> Lam a c (FlipSym2 f x)
flipSym2 f b = Lam (flip f b)
--
-- | Function composition. Combinator @B@ in https://en.wikipedia.org/wiki/B,_C,_K,_W_system.
type Comp :: (b ~> c) -> (a ~> b) -> a -> c
type family Comp f g x where
Comp f g x = f @@ (g @@ x)
type CompSym :: (b ~> c) ~> (a ~> b) ~> a ~> c
data CompSym f
type instance App CompSym f = CompSym1 f
type CompSym1 :: (b ~> c) -> (a ~> b) ~> a ~> c
data CompSym1 f g
type instance App (CompSym1 f) g = CompSym2 f g
type CompSym2 :: (b ~> c) -> (a ~> b) -> a ~> c
data CompSym2 f g x
type instance App (CompSym2 f g) x = Comp f g x
comp :: Lam b c f -> Lam a b g -> a x -> c (Comp f g x)
comp f g x = f @@ (g @@ x)
compSym :: Lam (b :~> c) (Lam a b :~> Lam a c) CompSym
compSym = Lam compSym1
compSym1 :: Lam b c f -> Lam (a :~> b) (a :~> c) (CompSym1 f)
compSym1 f = Lam (compSym2 f)
compSym2 :: Lam b c f -> Lam a b g -> Lam a c (CompSym2 f g)
compSym2 f g = Lam (comp f g)
-- | Combinator 'S' in https://en.wikipedia.org/wiki/SKI_combinator_calculus.
type Ap :: (a ~> b ~> c) -> (a ~> b) -> a -> c
type family Ap f g x where
Ap f g x = f @@ x @@ (g @@ x)
type ApSym :: (a ~> b ~> c) ~> (a ~> b) ~> a ~> c
data ApSym f
type instance App ApSym f = ApSym1 f
type ApSym1 :: (a ~> b ~> c) -> (a ~> b) ~> a ~> c
data ApSym1 f g
type instance App (ApSym1 f) g = ApSym2 f g
type ApSym2 :: (a ~> b ~> c) -> (a ~> b) -> a ~> c
data ApSym2 f g x
type instance App (ApSym2 f g) x = Ap f g x
ap :: Lam2 a b c f -> Lam a b g -> a x -> c (Ap f g x)
ap f g x = f @@ x @@ (g @@ x)
apSym :: Lam3 (a :~> b :~> c) (a :~> b) a c ApSym
apSym = Lam apSym1
apSym1 :: Lam2 a b c f -> Lam2 (a :~> b) a c (ApSym1 f)
apSym1 f = Lam (apSym2 f)
apSym2 :: Lam2 a b c f -> Lam a b g -> Lam a c (ApSym2 f g)
apSym2 f g = Lam (ap f g)
-- | Combinator 'W' in https://en.wikipedia.org/wiki/B,_C,_K,_W_system
type Join :: (a ~> a ~> b) -> a -> b
type family Join f x where
Join f x = f @@ x @@ x
type JoinSym :: (a ~> a ~> b) ~> a ~> b
data JoinSym f
type instance App JoinSym f = JoinSym1 f
type JoinSym1 :: (a ~> a ~> b) -> a ~> b
data JoinSym1 f x
type instance App (JoinSym1 f) x = Join f x
join :: Lam2 a a b f -> a x -> b (Join f x)
join f x = f @@ x @@ x
joinSym :: Lam2 (a :~> a :~> b) a b JoinSym
joinSym = Lam joinSym1
joinSym1 :: Lam2 a a b fun -> Lam a b (JoinSym1 fun)
joinSym1 f = Lam (join f)