packages feed

moffy-0.1.0.0: src/Control/Moffy/Internal/Sig.hs

{-# LANGUAGE BlockArguments, LambdaCase, TupleSections #-}
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts, FlexibleInstances, UndecidableInstances #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs -fno-warn-orphans #-}

module Control.Moffy.Internal.Sig (
	-- * Adjust
	adjustSig,
	-- * Applicative
	app_, iapp_,
	-- * Parallel
	at_, break_, until_, indexBy_,
	-- * Copies
	spawn, parList_ ) where

import Prelude hiding (repeat)

import Control.Arrow (first, (>>>), (***))
import Control.Monad.Freer.Par (pattern Pure, pattern (:=<<))
import Control.Moffy.Internal.Sig.Type (
	Sig(..), ISig(..), isig,
	emit, emitAll, waitFor, repeat, res, ires, hold )
import Control.Moffy.Internal.React (
	Firstable, Adjustable, Updatable, adjust, par )
import Control.Moffy.Internal.React.Type (
	React, Rct(..), ThreadId, forkThreadId )
import Data.Type.Set ((:+:))
import Data.Type.Flip (Flip(..), (<$%>))
import Data.OneOrMore (Mergeable)

---------------------------------------------------------------------------

-- * FLIP APPLIICATIVE
--	+ INSTANCE APPLICATIVE
--	+ APP AND IAPP
-- * PARALLEL
--	+ AT
--	+ BREAK AND UNTIL
--	+ INDEX BY
-- * COPIES
--	+ SPAWN
--	+ PAR LIST
-- * BASIC COMBINATOR
--	+ ADJUST
--	+ PAIRS
--	+ PAUSE

---------------------------------------------------------------------------
-- FLIP APPLICATIVE
---------------------------------------------------------------------------

-- INSTANCE APPLICATIVE

instance ((es :+: es) ~ es, Mergeable es es es, Monoid r) =>
	Applicative (Flip (Sig s es) r) where
	pure = Flip . Sig . pure . unflip . pure
	mf <*> mx = Flip $ app_ forkThreadId (unflip mf) (unflip mx)

instance ((es :+: es) ~ es, Mergeable es es es, Semigroup r) =>
	Applicative (Flip (ISig s es) r) where
	pure = Flip . (:| hold)
	mf <*> mx = Flip $ iapp_ forkThreadId (unflip mf) (unflip mx)

-- APP AND IAPP

app_ :: ((es :+: es) ~ es, Mergeable es es es, Monoid r) =>
	React s es (ThreadId, ThreadId) ->
	Sig s es (a -> b) r -> Sig s es a r -> Sig s es b r
app_ ft mf mx = emitAll . maybe (pure mempty) (uncurry $ iapp_ ft) =<< waitFor (exposeBoth ft mf mx)

exposeBoth :: (
	Updatable (ISig s es a r) (ISig s es b r'),
	Updatable (ISig s es b r') (ISig s es a r), (es :+: es) ~ es, Mergeable es es es ) =>
	React s es (ThreadId, ThreadId) -> Sig s es a r -> Sig s es b r' ->
	React s es (Maybe (ISig s es a r, ISig s es b r'))
exposeBoth ft l (Sig r) = do
	(Sig l', r') <- res $ pause ft l r
	(Sig r'', l'') <- res $ pause ft (Sig r') l'
	pure $ (,) <$> ex l'' <*> ex r''
	where ex = \case Pure x -> Just x; _ -> Nothing

iapp_ :: ((es :+: es) ~ es, Mergeable es es es, Semigroup r) =>
	React s es (ThreadId, ThreadId) ->
	ISig s es (a -> b) r -> ISig s es a r -> ISig s es b r
iapp_ ft mf mx = (<$> (uncurry ($) <$%> ipairs ft mf mx)) \case
	(End x, End y) -> x <> y; (End x, _ :| _) -> x; (_ :| _, End y) -> y
	(_ :| _, _ :| _) -> error "never occur"

---------------------------------------------------------------------------
-- PARALLEL
---------------------------------------------------------------------------

-- AT

at_ :: Firstable es es' (ISig s (es :+: es') a r) r' =>
	React s (es :+: es') (ThreadId, ThreadId) ->
	Sig s es a r -> React s es' r' ->
	React s (es :+: es') (Either r (Maybe a, r'))
at_ ft (adjustSig -> Sig l) (adjust -> r) = par ft l r >>= \case
	(Pure l', r') -> (first Just <$>) <$> iat_ ft l' r'
	(_, Pure y) -> pure $ Right (Nothing, y)
	(_ :=<< _, _ :=<< _) -> error "never occur"

iat_ :: (Updatable (ISig s es a r) r', (es :+: es) ~ es, Mergeable es es es) =>
	React s es (ThreadId, ThreadId) ->
	ISig s es a r -> React s es r' -> React s es (Either r (a, r'))
iat_ ft l r = (<$> ires (ipause ft l r)) \case
	(End x, _) -> Left x; (h :| _, Pure y) -> Right (h, y)
	(_ :| _, _ :=<< _) -> error "never occur"

-- BREAK AND UNTIL

break_ :: Firstable es es' (ISig s (es :+: es') a r) r' =>
	React s (es :+: es') (ThreadId, ThreadId) ->
	Sig s es a r -> React s es' r' ->
	Sig s (es :+: es') a (Either r (Maybe a, r'))
break_ ft (adjustSig -> l) (adjust -> r) = (<$> pause ft l r)
	$ first unSig >>> \case
		(Pure (End x), _) -> Left x
		(_ :=<< Await _, Pure r') -> Right (Nothing, r')
		(Pure (h :| _), Pure r') -> Right (Just h, r')
		_ -> error "never occur"

until_ :: Firstable es es' (ISig s (es :+: es') a r) r' =>
	React s (es :+: es') (ThreadId, ThreadId) ->
	Sig s es a r -> React s es' r' ->
	Sig s (es :+: es') a (Either r (a, r'))
until_ ft (adjustSig -> l) (adjust -> r) = pause ft l r >>= \(Sig l', r') ->
	(<$> waitFor l') \case
		End x -> Left x
		h :| _ -> case r' of
			Pure y -> Right (h, y); _ -> error "never occur"

-- INDEX BY

indexBy_ ::
	Firstable es es' (ISig s (es :+: es') a r) (ISig s (es :+: es') b r') =>
	React s (es :+: es') (ThreadId, ThreadId) ->
	Sig s es a r -> Sig s es' b r' ->
	Sig s (es :+: es') (a, b) (Either r (Maybe a, r'))
indexBy_ ft (adjustSig -> l) (adjustSig -> r) = indexByGen ft l r

indexByGen ::
	(Updatable (ISig s es a r) (ISig s es b r'), (es :+: es) ~ es, Mergeable es es es) =>
	React s es (ThreadId, ThreadId) ->
	Sig s es a r -> Sig s es b r' -> Sig s es (a, b) (Either r (Maybe a, r'))
indexByGen ft l (Sig r) = waitFor (res $ pause ft l r) >>= \case
	(Sig (Pure l'), r') -> (first Just <$>) <$> iindexBy ft l' (Sig r')
	(l', Pure (_ :| r')) -> indexByGen ft l' r'
	(_, Pure (End y)) -> pure $ Right (Nothing, y)
	_ -> error "never occur"

iindexBy :: (Updatable (ISig s es a r) (ISig s es b r'), (es :+: es) ~ es, Mergeable es es es) =>
	React s es (ThreadId, ThreadId) ->
	ISig s es a r -> Sig s es b r' -> Sig s es (a, b) (Either r (a, r'))
iindexBy ft l (Sig r) = waitFor (ires $ ipause ft l r) >>= \case
	(End x, _) -> pure $ Left x
	(l'@(hl :| _), Pure (x :| r')) -> emit (hl, x) >> iindexBy ft l' r'
	(hl :| _, Pure (End y)) -> pure $ Right (hl, y)
	_ -> error "never occur"

---------------------------------------------------------------------------
-- COPIES
---------------------------------------------------------------------------

-- SPAWN

spawn :: Sig s es a r -> Sig s es (ISig s es a r) r'
spawn = repeat . unSig

-- PAR 	LIST

parList_, parListGen :: ((es :+: es) ~ es, Mergeable es es es) =>
	React s es (ThreadId, ThreadId) ->
	Sig s es (ISig s es a r) r' -> Sig s es [a] ([r], r')
parList_ ft s = reverse <$%> parListGen ft s
parListGen ft (Sig r) = iparList ft =<< waitFor r

iparList :: ((es :+: es) ~ es, Mergeable es es es) =>
	React s es (ThreadId, ThreadId) ->
	ISig s es (ISig s es a r) r' -> Sig s es [a] ([r], r')
iparList ft = isig (pure . ([] ,)) $ go . ((: []) <$>) . ((: []) <$%>) where
	go s (Sig r) = emitAll (ipause ft s r) >>= \case
		(s', Pure (h :| t)) -> go (cons ft h s') t
		(s', Pure (End y)) -> (, y) <$> emitAll s'
		(End x, r') -> emit [] >> first (x ++) <$> parListGen ft (Sig r')
		(_ :| _, _ :=<< _) -> error "never occur"

cons :: ((es :+: es) ~ es, Mergeable es es es) =>
	React s es (ThreadId, ThreadId) ->
	ISig s es a r -> ISig s es [a] [r] -> ISig s es [a] [r]
cons ft h t = uncurry (:) <$%> ipairs ft h t >>= \(h', t') ->
	(:) <$> ((: []) <$%> h') <*> t'

---------------------------------------------------------------------------
-- BASIC COMBINATOR
---------------------------------------------------------------------------

-- ADJUST

adjustSig :: Adjustable es es' => Sig s es a r -> Sig s es' a r
adjustSig = Sig . (adjustISig <$>) . adjust . unSig

adjustISig :: Adjustable es es' => ISig s es a r -> ISig s es' a r
adjustISig = isig End $ (adjustSig >>>) . (:|)

-- PAIRS

ipairs :: (Updatable (ISig s es a r) (ISig s es b r'), Mergeable es es es, (es :+: es) ~ es) =>
	React s es (ThreadId, ThreadId) -> ISig s es a r -> ISig s es b r' ->
	ISig s es (a, b) (ISig s es a r, ISig s es b r')
ipairs _ l@(End _) r = pure (l, r)
ipairs _ l r@(End _) = pure (l, r)
ipairs ft (hl :| Sig tl) (hr :| Sig tr) = ((hl, hr) :|) . Sig
	$ uncurry (ipairs ft) . ((hl ?:|) *** (hr ?:|)) <$> par ft tl tr
	where (?:|) h = \case Pure i -> i; t -> h :| Sig t

-- PAUSE

pause :: (Updatable (ISig s es a r) r', (es :+: es) ~ es, Mergeable es es es) =>
	React s es (ThreadId, ThreadId) -> Sig s es a r -> React s es r' ->
	Sig s es a (Sig s es a r, React s es r')
pause ft (Sig l) r = waitFor (par ft l r) >>= \case
	(Pure l', r') -> first emitAll <$> emitAll (ipause ft l' r')
	(l', r'@(Pure _)) -> pure (Sig l', r')
	_ -> error "never occur"

ipause :: (Updatable (ISig s es a r) r', (es :+: es) ~ es, Mergeable es es es) =>
	React s es (ThreadId, ThreadId) -> ISig s es a r -> React s es r' ->
	ISig s es a (ISig s es a r, React s es r')
ipause _ l@(End _) r = pure (l, r)
ipause ft (h :| t) r = (h :|) $ (<$> pause ft t r) \case
	(Sig (Pure t'), r') -> (t', r')
	(t', r'@(Pure _)) -> (h :| t', r')
	_ -> error "never occur"