liftAN
Posted on December 29, 2018
Tags: Haskell
This function is now available on hackage.
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.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
module Apply where
data N = Z | S N
type family AppFunc f n a where
AppFunc f Z a = f a
AppFunc f (S n) (a -> b) = f a -> AppFunc f n b
type family CountArgs f where
CountArgs (_ -> b) = S (CountArgs b)
CountArgs _ = Z
class (CountArgs a ~ n) => Applyable a n where
apply :: Applicative f => f a -> AppFunc f (CountArgs a) a
instance (CountArgs a ~ Z) => Applyable a Z where
= id
apply {-# INLINE apply #-}
instance Applyable b n => Applyable (a -> b) (S n) where
= apply (f <*> x)
apply f x {-# INLINE apply #-}
-- | >>> lift (\x y z -> x ++ y ++ z) (Just "a") (Just "b") (Just "c")
-- Just "abc"
lift :: (Applyable a n, Applicative f) => (b -> a) -> (f b -> AppFunc f n a)
= apply (fmap f x)
lift f x {-# INLINE lift #-}