variadic-function-0.1.0.0: src/Data/Function/Variadic.hs
module Data.Function.Variadic
( -- * Decomposition and creation of functions
Function (..),
ConstructFunction,
DeconstructFunction,
-- * Helper classes for argument constraints
EmptyConstraint,
type (&),
)
where
import Data.Kind (Type)
-- | Toolkit for creating and transforming functions with a variable number of arguments.
-- Its parameters are function, list of its arguments, its result, and `argC`
-- that constraints all arguments of the function.
class
(ConstructFunction args r ~ f, DeconstructFunction f ~ '(args, r)) =>
Function f args r argC
where
-- | Create a new function
--
-- === __Example usage__
--
-- >>> printf :: Function Show f args String => f
-- >>> printf = createFunction (Proxy :: Proxy Show) (\acc a -> acc <> show a) id ""
-- >>> printf "hello" () :: String
-- "hello()"
createFunction ::
-- | Required for unambiguous choice of Function instance
proxy argC ->
-- | Combine arguments with accumulator
(forall a. argC a => acc -> a -> acc) ->
-- | Make result of the function
(acc -> r) ->
-- | Accumulator
acc ->
f
-- | Create a function with the same arguments as given one but may have a different result.
transformFunction ::
-- | Required for unambiguous choice of the Function instance
proxy argC ->
-- | Combine arguments with accumulator
(forall a. argC a => acc -> a -> acc) ->
-- | Create result of the `f` function using accumulator and the result of the function to transform
(acc -> r0 -> r) ->
-- | Accumulator
acc ->
-- | The function to transform
ConstructFunction args r0 ->
-- | The new function
f
-- | Extract list of arguments and the result from the function.
type family DeconstructFunction (f :: Type) :: ([Type], Type) where
DeconstructFunction (a -> f) = MapFst ((:) a) (DeconstructFunction f)
DeconstructFunction x = '( '[], x)
type family MapFst (f :: k1 -> k1) (tuple :: (k1, k2)) where
MapFst f '(a, b) = '(f a, b)
-- | Given the types of function arguments and its result, make a type of a function.
type family ConstructFunction (args :: [Type]) (r :: Type) where
ConstructFunction '[] r = r
ConstructFunction (a : args) r = a -> ConstructFunction args r
instance
('( '[], r) ~ DeconstructFunction r) =>
Function r '[] r argC
where
createFunction _ _ fr r = fr r
transformFunction _ _ fr acc r = fr acc r
instance
(Function f args r argC, argC a) =>
Function (a -> f) (a : args) r argC
where
createFunction pArgC fa fr acc = createFunction pArgC fa fr . fa acc
transformFunction pArgC fa fr acc f = \a -> transformFunction pArgC fa fr (fa acc a) (f a)
-- | When the arguments are not constrained, use this as the argC parameter of `Function`.
class EmptyConstraint a
instance EmptyConstraint a
-- | Combine constraints. For example, @Function f args x (Show & Num)@.
class (f x, g x) => (&) f g (x :: k)
instance (f x, g x) => (&) f g x