remote-monad-0.1.0.0: src/Control/Remote/Monad/Packet/Applicative.hs
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-|
Module: Control.Remote.Monad.Packet.Applicative
Copyright: (C) 2016, The University of Kansas
License: BSD-style (see the file LICENSE)
Maintainer: Andy Gill
Stability: Alpha
Portability: GHC
-}
module Control.Remote.Monad.Packet.Applicative
( -- * The remote applicative
ApplicativePacket(..)
-- * Utility
, superCommand
) where
import Control.Monad.Trans.Class
import Control.Monad.Trans.State.Strict
import qualified Control.Remote.Monad.Packet.Strong as Strong
import Control.Natural
-- | A Remote Applicative, that can encode both commands and procedures, bundled together.
data ApplicativePacket (c :: *) (p :: * -> *) (a :: *) where
Command :: ApplicativePacket c p b -> c -> ApplicativePacket c p b
Procedure :: ApplicativePacket c p (a -> b) -> p a -> ApplicativePacket c p b
Pure :: a -> ApplicativePacket c p a
instance Functor (ApplicativePacket c p) where
fmap f (Command g c) = Command (fmap f g) c
fmap f (Procedure g p) = Procedure (fmap (f .) g) p
fmap f (Pure a) = Pure (f a)
instance Applicative (ApplicativePacket c p) where
pure a = Pure a
(Pure f) <*> m = fmap f m
(Command g c) <*> (Pure a) = Command (fmap (\ f -> f a) g) c
(Procedure g p) <*> (Pure a) = Procedure (fmap (\ f a1 -> f a1 a) g) p
m <*> (Command g2 c2) = Command (m <*> g2) c2
m <*> (Procedure g2 p2) = Procedure (fmap (.) m <*> g2) p2
-- | This simulates a 'ApplicativePacket', to see if it only contains commands, and if so,
-- returns the static result. The commands still need executed. The term super-command
-- is a play on Hughes' super-combinator terminology.
superCommand :: ApplicativePacket c p a -> Maybe a
superCommand (Pure a) = Just a
superCommand (Command g _) = superCommand g
superCommand (Procedure _ _) = Nothing