Copyright | (c) Donnacha Oisín Kidney 2018 |
---|---|
License | MIT |
Maintainer | mail@doisinkidney.com |
Portability | GHC |
Safe Haskell | Safe |
Language | Haskell2010 |
Control.Applicative.Lift.Internal
Description
There's a family of functions in Control.Applicative which follow the
pattern liftA2
, liftA3
, etc.
Using some tricks from Richard Eisenberg's thesis we can write them all at
once.
- Eisenberg, Richard A. "Dependent Types in Haskell: Theory and Practice." University of Pennsylvania, 2016. https://github.com/goldfirere/thesis/raw/master/built/thesis.pdf
Documentation
type family AppFunc f n a where ... Source #
returns the type of the function AppFunc
f n aa
"lifted" over n
arguments.
class CountArgs a ~ n => Applyable a n where Source #
The actual class which constructs the lifted function.
lift :: (Applyable b n, Applicative f) => (a -> b) -> f a -> AppFunc f n b Source #
Lift a function over applicative arguments. This function is an
arity-generic version of the functions liftA2
,
liftA3
, etc.
Type inference works best when the function being lifted is monomorphic:
>>>
lift (\x y z -> x ++ y ++ z) (Just "a") (Just "b") (Just "c")
Just "abc"
In these cases, GHC can see the number of arguments the function must
have, and so is able to pick the correct instance for Applyable
.
If the function is not monomorphic (for instance +
), you will need
to give a type signature:
>>>
lift ((+) :: Int -> Int -> Int) (Just 1) (Just 2)
Just 3
Alternatively, you can use type applications to monomorphise the function:
>>>
:set -XTypeApplications
>>>
lift ((+) @Int) (Just 1) (Just 2)
Just 3
Finally, everything is aggressively inlined, so there should be no
cost to using this function over manually writing
liftA3
etc.