{-# LANGUAGE FunctionalDependencies, RankNTypes, TypeOperators #-}

{-|
Module      : Control.ParDual.Class
Description : Definition of the 'ParDual' class and its functions.
Copyright   : (c) Gabriel Volpe, 2020
License     : Apache-2.0
Maintainer  : volpegabriel@gmail.com
Stability   : experimental

You can find here functions such as 'parMap2', 'parTraverse', 'parBitraverse', etc.
-}
module Control.ParDual.Class where

import           Control.Applicative            ( ZipList(..) )
import           Control.Concurrent.Async       ( Concurrently(..) )
import           Data.Bitraversable             ( Bitraversable
                                                , bitraverse
                                                )
import           Data.Functor                   ( void )
import           Data.Validation                ( Validation
                                                , toEither
                                                , fromEither
                                                )

{- | The ParDual class abstracts over 'Monad's that have a dual
'Applicative' instance that acts in a different useful way.

E.g., the duality between 'Either' and 'Validation'. As well
as the duality between 'IO' and 'Concurrently'.

It can also be seen as an isomorphism defined at the class level.
-}
class (Monad m, Applicative f) => ParDual f m | m -> f, f -> m where
  {- | A natural transformation from 'm' to 'f'
  -}
  parallel :: forall a . m a -> f a

  {- | A natural transformation from 'f' to 'm'
  -}
  sequential :: forall a . f a -> m a

  {- |
  It is the analogue to using '<$>' and '<*>' for the dual
  'Applicative' of the current 'Monad', as defined by the
  relationship defined by the 'ParDual' instance.
  -}
  parMap2 :: m a0 -> m a1 -> (a0 -> a1 -> a) -> m a
  parMap2 ma0 :: m a0
ma0 ma1 :: m a1
ma1 f :: a0 -> a1 -> a
f = f a -> m a
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => f a -> m a
sequential (f a -> m a) -> f a -> m a
forall a b. (a -> b) -> a -> b
$ a0 -> a1 -> a
f
    (a0 -> a1 -> a) -> f a0 -> f (a1 -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m a0 -> f a0
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a0
ma0
    f (a1 -> a) -> f a1 -> f a
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a1 -> f a1
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a1
ma1

  {- |
  It is the analogue to using '<$>' and '<*>' for the dual
  'Applicative' of the current 'Monad', as defined by the
  relationship defined by the 'ParDual' instance.
  -}
  parMap3 :: m a0 -> m a1 -> m a2 -> (a0 -> a1 -> a2 -> a) -> m a
  parMap3 ma0 :: m a0
ma0 ma1 :: m a1
ma1 ma2 :: m a2
ma2 f :: a0 -> a1 -> a2 -> a
f = f a -> m a
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => f a -> m a
sequential (f a -> m a) -> f a -> m a
forall a b. (a -> b) -> a -> b
$ a0 -> a1 -> a2 -> a
f
    (a0 -> a1 -> a2 -> a) -> f a0 -> f (a1 -> a2 -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m a0 -> f a0
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a0
ma0
    f (a1 -> a2 -> a) -> f a1 -> f (a2 -> a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a1 -> f a1
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a1
ma1
    f (a2 -> a) -> f a2 -> f a
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a2 -> f a2
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a2
ma2

  {- |
  It is the analogue to using '<$>' and '<*>' for the dual
  'Applicative' of the current 'Monad', as defined by the
  relationship defined by the 'ParDual' instance.
  -}
  parMap4 :: m a0 -> m a1 -> m a2 -> m a3 -> (a0 -> a1 -> a2 -> a3 -> a) -> m a
  parMap4 ma0 :: m a0
ma0 ma1 :: m a1
ma1 ma2 :: m a2
ma2 ma3 :: m a3
ma3 f :: a0 -> a1 -> a2 -> a3 -> a
f = f a -> m a
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => f a -> m a
sequential (f a -> m a) -> f a -> m a
forall a b. (a -> b) -> a -> b
$ a0 -> a1 -> a2 -> a3 -> a
f
    (a0 -> a1 -> a2 -> a3 -> a) -> f a0 -> f (a1 -> a2 -> a3 -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m a0 -> f a0
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a0
ma0
    f (a1 -> a2 -> a3 -> a) -> f a1 -> f (a2 -> a3 -> a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a1 -> f a1
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a1
ma1
    f (a2 -> a3 -> a) -> f a2 -> f (a3 -> a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a2 -> f a2
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a2
ma2
    f (a3 -> a) -> f a3 -> f a
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a3 -> f a3
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a3
ma3

  {- |
  It is the analogue to using '<$>' and '<*>' for the dual
  'Applicative' of the current 'Monad', as defined by the
  relationship defined by the 'ParDual' instance.
  -}
  parMap5 :: m a0 -> m a1 -> m a2 -> m a3 -> m a4 -> (a0 -> a1 -> a2 -> a3 -> a4 -> a) -> m a
  parMap5 ma0 :: m a0
ma0 ma1 :: m a1
ma1 ma2 :: m a2
ma2 ma3 :: m a3
ma3 ma4 :: m a4
ma4 f :: a0 -> a1 -> a2 -> a3 -> a4 -> a
f = f a -> m a
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => f a -> m a
sequential (f a -> m a) -> f a -> m a
forall a b. (a -> b) -> a -> b
$ a0 -> a1 -> a2 -> a3 -> a4 -> a
f
    (a0 -> a1 -> a2 -> a3 -> a4 -> a)
-> f a0 -> f (a1 -> a2 -> a3 -> a4 -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m a0 -> f a0
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a0
ma0
    f (a1 -> a2 -> a3 -> a4 -> a) -> f a1 -> f (a2 -> a3 -> a4 -> a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a1 -> f a1
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a1
ma1
    f (a2 -> a3 -> a4 -> a) -> f a2 -> f (a3 -> a4 -> a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a2 -> f a2
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a2
ma2
    f (a3 -> a4 -> a) -> f a3 -> f (a4 -> a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a3 -> f a3
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a3
ma3
    f (a4 -> a) -> f a4 -> f a
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a4 -> f a4
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a4
ma4

  {- |
  It is the analogue to using '<$>' and '<*>' for the dual
  'Applicative' of the current 'Monad', as defined by the
  relationship defined by the 'ParDual' instance.
  -}
  parMap6 :: m a0 -> m a1 -> m a2 -> m a3 -> m a4 -> m a5 -> (a0 -> a1 -> a2 -> a3 -> a4 -> a5 -> a) -> m a
  parMap6 ma0 :: m a0
ma0 ma1 :: m a1
ma1 ma2 :: m a2
ma2 ma3 :: m a3
ma3 ma4 :: m a4
ma4 ma5 :: m a5
ma5 f :: a0 -> a1 -> a2 -> a3 -> a4 -> a5 -> a
f = f a -> m a
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => f a -> m a
sequential (f a -> m a) -> f a -> m a
forall a b. (a -> b) -> a -> b
$ a0 -> a1 -> a2 -> a3 -> a4 -> a5 -> a
f
    (a0 -> a1 -> a2 -> a3 -> a4 -> a5 -> a)
-> f a0 -> f (a1 -> a2 -> a3 -> a4 -> a5 -> a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m a0 -> f a0
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a0
ma0
    f (a1 -> a2 -> a3 -> a4 -> a5 -> a)
-> f a1 -> f (a2 -> a3 -> a4 -> a5 -> a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a1 -> f a1
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a1
ma1
    f (a2 -> a3 -> a4 -> a5 -> a) -> f a2 -> f (a3 -> a4 -> a5 -> a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a2 -> f a2
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a2
ma2
    f (a3 -> a4 -> a5 -> a) -> f a3 -> f (a4 -> a5 -> a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a3 -> f a3
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a3
ma3
    f (a4 -> a5 -> a) -> f a4 -> f (a5 -> a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a4 -> f a4
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a4
ma4
    f (a5 -> a) -> f a5 -> f a
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> m a5 -> f a5
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel m a5
ma5

  {- |
  Same as 'traverse', except it uses the dual 'Applicative' of
  the current 'Monad', as defined by the 'ParDual' relationship.
  -}
  parTraverse :: Traversable t => (a -> m b) -> t a -> m (t b)
  parTraverse f :: a -> m b
f ta :: t a
ta =
    let g :: a -> f b
g a :: a
a = m b -> f b
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel (a -> m b
f a
a)
        res :: f (t b)
res = t (f b) -> f (t b)
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
sequenceA (t (f b) -> f (t b)) -> t (f b) -> f (t b)
forall a b. (a -> b) -> a -> b
$ (a -> f b) -> t a -> t (f b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> f b
forall (f :: * -> *). ParDual f m => a -> f b
g t a
ta
    in  f (t b) -> m (t b)
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => f a -> m a
sequential f (t b)
res

  {- |
  Same as 'Data.Foldable.traverse_', except it uses the dual 'Applicative' of
  the current 'Monad', as defined by the 'ParDual' relationship.
  -}
  parTraverse_ :: Traversable t => (a -> m b) -> t a -> m ()
  parTraverse_ f :: a -> m b
f = m (t b) -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m (t b) -> m ()) -> (t a -> m (t b)) -> t a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> m b) -> t a -> m (t b)
forall (f :: * -> *) (m :: * -> *) (t :: * -> *) a b.
(ParDual f m, Traversable t) =>
(a -> m b) -> t a -> m (t b)
parTraverse a -> m b
f

  {- |
  Same as 'sequence', except it uses the dual 'Applicative' of
  the current 'Monad', as defined by the 'ParDual' relationship.
  -}
  parSequence :: Traversable t => t (m a) -> m (t a)
  parSequence = (m a -> m a) -> t (m a) -> m (t a)
forall (f :: * -> *) (m :: * -> *) (t :: * -> *) a b.
(ParDual f m, Traversable t) =>
(a -> m b) -> t a -> m (t b)
parTraverse m a -> m a
forall a. a -> a
id

  {- |
  Same as 'sequence_', except it uses the dual 'Applicative' of
  the current 'Monad', as defined by the 'ParDual' relationship.
  -}
  parSequence_ :: Traversable t => t (m a) -> m ()
  parSequence_ = m (t a) -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m (t a) -> m ()) -> (t (m a) -> m (t a)) -> t (m a) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t (m a) -> m (t a)
forall (f :: * -> *) (m :: * -> *) (t :: * -> *) a.
(ParDual f m, Traversable t) =>
t (m a) -> m (t a)
parSequence

  {- |
  Same as '*>', except it uses the dual 'Applicative' of
  the current 'Monad', as defined by the 'ParDual' relationship.
  -}
  parProductR :: m a -> m b -> m b
  parProductR ma :: m a
ma mb :: m b
mb = m a -> m b -> (a -> b -> b) -> m b
forall (f :: * -> *) (m :: * -> *) a0 a1 a.
ParDual f m =>
m a0 -> m a1 -> (a0 -> a1 -> a) -> m a
parMap2 m a
ma m b
mb (\_ b :: b
b -> b
b)

  {- |
  Same as '<*', except it uses the dual 'Applicative' of
  the current 'Monad', as defined by the 'ParDual' relationship.
  -}
  parProductL :: m a -> m b -> m a
  parProductL ma :: m a
ma mb :: m b
mb = m a -> m b -> (a -> b -> a) -> m a
forall (f :: * -> *) (m :: * -> *) a0 a1 a.
ParDual f m =>
m a0 -> m a1 -> (a0 -> a1 -> a) -> m a
parMap2 m a
ma m b
mb a -> b -> a
forall a b. a -> b -> a
const

  {- |
  Same as 'bitraverse', except it uses the dual 'Applicative' of
  the current 'Monad', as defined by the 'ParDual' relationship.
  -}
  parBitraverse :: Bitraversable t => (a -> m c) -> (b -> m d) -> t a b -> m (t c d)
  parBitraverse ma :: a -> m c
ma mb :: b -> m d
mb tab :: t a b
tab =
    let fa :: a -> f c
fa  = (\a :: a
a -> m c -> f c
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel (a -> m c
ma a
a))
        fb :: b -> f d
fb  = (\b :: b
b -> m d -> f d
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => m a -> f a
parallel (b -> m d
mb b
b))
        res :: f (t c d)
res = (a -> f c) -> (b -> f d) -> t a b -> f (t c d)
forall (t :: * -> * -> *) (f :: * -> *) a c b d.
(Bitraversable t, Applicative f) =>
(a -> f c) -> (b -> f d) -> t a b -> f (t c d)
bitraverse a -> f c
fa b -> f d
fb t a b
tab
    in  f (t c d) -> m (t c d)
forall (f :: * -> *) (m :: * -> *) a. ParDual f m => f a -> m a
sequential f (t c d)
res

  {- |
  Same as 'Data.Traversable.bisequence', except it uses the dual 'Applicative' of
  the current 'Monad', as defined by the 'ParDual' relationship.
  -}
  parBisequence :: Bitraversable t => t (m a) (m b) -> m (t a b)
  parBisequence = (m a -> m a) -> (m b -> m b) -> t (m a) (m b) -> m (t a b)
forall (f :: * -> *) (m :: * -> *) (t :: * -> * -> *) a c b d.
(ParDual f m, Bitraversable t) =>
(a -> m c) -> (b -> m d) -> t a b -> m (t c d)
parBitraverse m a -> m a
forall a. a -> a
id m b -> m b
forall a. a -> a
id

--------------------- Instances ----------------------------

instance Semigroup e => ParDual (Validation e) (Either e) where
  parallel :: Either e a -> Validation e a
parallel   = Either e a -> Validation e a
forall err a. Either err a -> Validation err a
fromEither
  sequential :: Validation e a -> Either e a
sequential = Validation e a -> Either e a
forall err a. Validation err a -> Either err a
toEither

instance ParDual Concurrently IO where
  parallel :: IO a -> Concurrently a
parallel   = IO a -> Concurrently a
forall a. IO a -> Concurrently a
Concurrently
  sequential :: Concurrently a -> IO a
sequential = Concurrently a -> IO a
forall a. Concurrently a -> IO a
runConcurrently

instance ParDual ZipList [] where
  parallel :: [a] -> ZipList a
parallel   = [a] -> ZipList a
forall a. [a] -> ZipList a
ZipList
  sequential :: ZipList a -> [a]
sequential = ZipList a -> [a]
forall a. ZipList a -> [a]
getZipList