module Clean.Arrow (
Arrow(..),
(>>>),(<<<),(>>^),(^>>),(|||),
Apply(..),app,
Kleisli(..)
) where
import Clean.Core hiding (flip)
import Clean.Classes
import Clean.Monad
import Clean.Traversable
import Clean.Lens
(>>>) = flip (.)
(<<<) = (.)
(^>>) = promap
(>>^) = (<&>)
infixr 4 >>>,<<<,^>>,>>^
class (Split k,Choice k) => Arrow k where
arr :: (a -> b) -> k a b
instance Arrow (->) where arr = id
class Arrow k => Apply k where
apply :: k (k a b,a) b
instance Apply (->) where apply (f,x) = f x
instance Arrow k => Cofunctor (Flip k a) where
comap f (Flip g) = Flip (arr f >>> g)
app f = arr (f,) >>> apply
a ||| b = (Left<$>a) <|> (Right<$>b)
instance (Monad f,Contravariant f,Monad g) => Monad (Compose f g) where
join = map getCompose >>> getCompose >>> map collect
>>> join >>> map join >>> Compose
kc = iso (Compose . runKleisli) (Kleisli . getCompose)
kc' = iso (Kleisli . getCompose) (Compose . runKleisli)
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
instance Unit m => Unit (Kleisli m a) where pure = Kleisli . const . pure
instance Functor f => Functor (Kleisli f a) where map f m = m ^. kc.lam (map f).kc'
instance Monad m => Applicative (Kleisli m a)
instance Monad m => Monad (Kleisli m a) where join m = m ^. kc.lam (join . map (^.kc)).kc'
instance Monad m => Category (Kleisli m) where
id = Kleisli pure
Kleisli f . Kleisli g = Kleisli (\a -> g a >>= f)
instance Monad m => Choice (Kleisli m) where
Kleisli f <|> Kleisli g = Kleisli (f <|> g)
instance Monad m => Split (Kleisli m) where
Kleisli f <#> Kleisli g = Kleisli (\(a,c) -> (,)<$>f a<*>g c)
instance Monad m => Apply (Kleisli m) where
apply = Kleisli (\(Kleisli f,a) -> f a)
instance Monad m => Arrow (Kleisli m) where
arr a = Kleisli (pure . a)