{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE UndecidableInstances #-}
module Control.Lift
( liftAll
, traverseAll
, traverseAll_
, sequenceAll
, sequenceAll_
, fmapAll
, foldMapAll
, foldrAll
, foldlAll
, foldlAll'
, concatAll
, module Data.Functor.Compose
) where
import Data.Foldable (foldl', sequence_, traverse_)
import Data.Functor.Compose (Compose(..))
import Data.Coerce (Coercible, coerce)
liftAll :: forall s f g d n.
( CountArgs f ~ n
, Applicative g
, EmbedDepth () s ~ d
, ComposeUntil d s ~ g ()
, Applyable n d g f
, Coercible s (g ())
)
=> f -> App n d g f
liftAll = apply @n @d . pure @g
traverseAll :: forall s a b d f g res sa.
( EmbedDepth () s ~ d
, ComposeUntil d s ~ g ()
, FlattenUntil d (g b) ~ res
, FlattenUntil d (g a) ~ sa
, Applicative f
, Traversable g
, Coercible res (g b)
, Coercible sa (g a)
)
=> (a -> f b) -> sa -> f res
traverseAll f = fmap coerce . traverse @g f . coerce
traverseAll_ :: forall s a b sa d f g.
( EmbedDepth () s ~ d
, ComposeUntil d s ~ g ()
, ComposeUntil d sa ~ g a
, Foldable g
, Applicative f
, Coercible sa (g a)
)
=> (a -> f b) -> sa -> f ()
traverseAll_ f = traverse_ @g f . coerce @sa @(g a)
sequenceAll :: forall s a d f g res sfa.
( EmbedDepth () s ~ d
, ComposeUntil d s ~ g ()
, FlattenUntil d (g (f a)) ~ sfa
, FlattenUntil d (g a) ~ res
, Applicative f
, Traversable g
, Coercible sfa (g (f a))
, Coercible res (g a)
)
=> sfa -> f res
sequenceAll = traverseAll @s @(f a) id
sequenceAll_ :: forall s a d f g sfa.
( EmbedDepth () s ~ d
, ComposeUntil d s ~ g ()
, ComposeUntil d sfa ~ g (f a)
, Applicative f
, Foldable g
, Coercible sfa (g (f a))
)
=> sfa -> f ()
sequenceAll_ = traverseAll_ @s id
fmapAll :: forall s sa a b d f res.
( EmbedDepth () s ~ d
, FlattenUntil d (f b) ~ res
, FlattenUntil d (f a) ~ sa
, ComposeUntil d s ~ f ()
, Functor f
, Coercible sa (f a)
, Coercible res (f b)
)
=> (a -> b) -> sa -> res
fmapAll f = coerce . fmap @f f . coerce
foldMapAll :: forall s sa a m d f.
( EmbedDepth () s ~ d
, ComposeUntil d sa ~ f a
, Foldable f
, Monoid m
, Coercible sa (f a)
)
=> (a -> m) -> sa -> m
foldMapAll f = foldMap @f f . coerce
foldrAll :: forall s sa a b d f res.
( EmbedDepth () s ~ d
, ComposeUntil d sa ~ f a
, Foldable f
, Coercible sa (f a)
)
=> (a -> b -> b) -> b -> sa -> b
foldrAll f b = foldr @f f b . coerce
foldlAll :: forall s sa a b d f res.
( EmbedDepth () s ~ d
, ComposeUntil d sa ~ f a
, Foldable f
, Coercible sa (f a)
)
=> (b -> a -> b) -> b -> sa -> b
foldlAll f b = foldl @f f b . coerce
foldlAll' :: forall s sa a b d f res.
( EmbedDepth () s ~ d
, ComposeUntil d sa ~ f a
, Foldable f
, Coercible sa (f a)
)
=> (b -> a -> b) -> b -> sa -> b
foldlAll' f b = foldl' @f f b . coerce
concatAll :: forall s sa a b d f res.
( EmbedDepth [()] s ~ d
, ComposeUntil d sa ~ f [a]
, Foldable f
, Coercible sa (f [a])
)
=> sa -> [a]
concatAll = concat @f . coerce
class (CountArgs f ~ n) => Applyable n d g f where
apply :: g f -> App n d g f
instance ( CountArgs f ~ Z
, Coercible (FlattenUntil d (g f)) (g f)
) => Applyable Z d g f where
apply = coerce
{-# INLINE apply #-}
instance ( Applyable n d g b
, FlattenUntil d (g a) ~ s
, ComposeUntil d s ~ g a
, Applicative g
, Coercible s (g a)
) => Applyable (S n) d g (a -> b) where
apply gf = apply @n @d @g @b . (gf <*>) . coerce
{-# INLINE apply #-}
data Nat = Z | S Nat
type family CountArgs f :: Nat where
CountArgs (a -> b) = S (CountArgs b)
CountArgs a = Z
type family EmbedDepth a s :: Nat where
EmbedDepth a a = Z
EmbedDepth a (s b) = S (EmbedDepth a b)
type family App (n :: Nat) (d :: Nat) g x where
App (S n) d g (a -> b) = FlattenUntil d (g a) -> App n d g b
App Z d g a = FlattenUntil d (g a)
type family Embed f g where
Embed f (g a) = Compose f g a
Embed f a = f a
type family ComposeUntil n f where
ComposeUntil Z a = a
ComposeUntil (S Z) (f a) = f a
ComposeUntil (S n) (f b) = Embed f (ComposeUntil n b)
type family FlattenUntil n f where
FlattenUntil Z a = a
FlattenUntil (S Z) (f a) = f a
FlattenUntil (S n) (Compose f g a) = f (FlattenUntil n (g a))