{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE OverloadedRecordDot #-}

module MonadicBang.Internal.Effect.Offer where

import Control.Algebra
import Control.Carrier.State.Strict
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as M

-- | Offers a number of things that can be yoinked, but only once

data Offer k v m a where
  Yoink :: k -> Offer k v m (Maybe v)

yoink :: Has (Offer k v) sig m => k -> m (Maybe v)
yoink :: forall k v (sig :: (* -> *) -> * -> *) (m :: * -> *).
Has (Offer k v) sig m =>
k -> m (Maybe v)
yoink = Offer k v m (Maybe v) -> m (Maybe v)
forall (eff :: (* -> *) -> * -> *) (sig :: (* -> *) -> * -> *)
       (m :: * -> *) a.
(Member eff sig, Algebra sig m) =>
eff m a -> m a
send (Offer k v m (Maybe v) -> m (Maybe v))
-> (k -> Offer k v m (Maybe v)) -> k -> m (Maybe v)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. k -> Offer k v m (Maybe v)
forall {k} k v (m :: k). k -> Offer k v m (Maybe v)
Yoink

newtype OfferC k v m a = OfferC {forall k v (m :: * -> *) a. OfferC k v m a -> StateC (Map k v) m a
getOfferState :: StateC (Map k v) m a}
  deriving newtype ((forall a b. (a -> b) -> OfferC k v m a -> OfferC k v m b)
-> (forall a b. a -> OfferC k v m b -> OfferC k v m a)
-> Functor (OfferC k v m)
forall a b. a -> OfferC k v m b -> OfferC k v m a
forall a b. (a -> b) -> OfferC k v m a -> OfferC k v m b
forall k v (m :: * -> *) a b.
Functor m =>
a -> OfferC k v m b -> OfferC k v m a
forall k v (m :: * -> *) a b.
Functor m =>
(a -> b) -> OfferC k v m a -> OfferC k v m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall k v (m :: * -> *) a b.
Functor m =>
(a -> b) -> OfferC k v m a -> OfferC k v m b
fmap :: forall a b. (a -> b) -> OfferC k v m a -> OfferC k v m b
$c<$ :: forall k v (m :: * -> *) a b.
Functor m =>
a -> OfferC k v m b -> OfferC k v m a
<$ :: forall a b. a -> OfferC k v m b -> OfferC k v m a
Functor, Functor (OfferC k v m)
Functor (OfferC k v m) =>
(forall a. a -> OfferC k v m a)
-> (forall a b.
    OfferC k v m (a -> b) -> OfferC k v m a -> OfferC k v m b)
-> (forall a b c.
    (a -> b -> c)
    -> OfferC k v m a -> OfferC k v m b -> OfferC k v m c)
-> (forall a b. OfferC k v m a -> OfferC k v m b -> OfferC k v m b)
-> (forall a b. OfferC k v m a -> OfferC k v m b -> OfferC k v m a)
-> Applicative (OfferC k v m)
forall a. a -> OfferC k v m a
forall a b. OfferC k v m a -> OfferC k v m b -> OfferC k v m a
forall a b. OfferC k v m a -> OfferC k v m b -> OfferC k v m b
forall a b.
OfferC k v m (a -> b) -> OfferC k v m a -> OfferC k v m b
forall a b c.
(a -> b -> c) -> OfferC k v m a -> OfferC k v m b -> OfferC k v m c
forall k v (m :: * -> *). Monad m => Functor (OfferC k v m)
forall k v (m :: * -> *) a. Monad m => a -> OfferC k v m a
forall k v (m :: * -> *) a b.
Monad m =>
OfferC k v m a -> OfferC k v m b -> OfferC k v m a
forall k v (m :: * -> *) a b.
Monad m =>
OfferC k v m a -> OfferC k v m b -> OfferC k v m b
forall k v (m :: * -> *) a b.
Monad m =>
OfferC k v m (a -> b) -> OfferC k v m a -> OfferC k v m b
forall k v (m :: * -> *) a b c.
Monad m =>
(a -> b -> c) -> OfferC k v m a -> OfferC k v m b -> OfferC k v m c
forall (f :: * -> *).
Functor f =>
(forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
$cpure :: forall k v (m :: * -> *) a. Monad m => a -> OfferC k v m a
pure :: forall a. a -> OfferC k v m a
$c<*> :: forall k v (m :: * -> *) a b.
Monad m =>
OfferC k v m (a -> b) -> OfferC k v m a -> OfferC k v m b
<*> :: forall a b.
OfferC k v m (a -> b) -> OfferC k v m a -> OfferC k v m b
$cliftA2 :: forall k v (m :: * -> *) a b c.
Monad m =>
(a -> b -> c) -> OfferC k v m a -> OfferC k v m b -> OfferC k v m c
liftA2 :: forall a b c.
(a -> b -> c) -> OfferC k v m a -> OfferC k v m b -> OfferC k v m c
$c*> :: forall k v (m :: * -> *) a b.
Monad m =>
OfferC k v m a -> OfferC k v m b -> OfferC k v m b
*> :: forall a b. OfferC k v m a -> OfferC k v m b -> OfferC k v m b
$c<* :: forall k v (m :: * -> *) a b.
Monad m =>
OfferC k v m a -> OfferC k v m b -> OfferC k v m a
<* :: forall a b. OfferC k v m a -> OfferC k v m b -> OfferC k v m a
Applicative, Applicative (OfferC k v m)
Applicative (OfferC k v m) =>
(forall a b.
 OfferC k v m a -> (a -> OfferC k v m b) -> OfferC k v m b)
-> (forall a b. OfferC k v m a -> OfferC k v m b -> OfferC k v m b)
-> (forall a. a -> OfferC k v m a)
-> Monad (OfferC k v m)
forall a. a -> OfferC k v m a
forall a b. OfferC k v m a -> OfferC k v m b -> OfferC k v m b
forall a b.
OfferC k v m a -> (a -> OfferC k v m b) -> OfferC k v m b
forall k v (m :: * -> *). Monad m => Applicative (OfferC k v m)
forall k v (m :: * -> *) a. Monad m => a -> OfferC k v m a
forall k v (m :: * -> *) a b.
Monad m =>
OfferC k v m a -> OfferC k v m b -> OfferC k v m b
forall k v (m :: * -> *) a b.
Monad m =>
OfferC k v m a -> (a -> OfferC k v m b) -> OfferC k v m b
forall (m :: * -> *).
Applicative m =>
(forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
$c>>= :: forall k v (m :: * -> *) a b.
Monad m =>
OfferC k v m a -> (a -> OfferC k v m b) -> OfferC k v m b
>>= :: forall a b.
OfferC k v m a -> (a -> OfferC k v m b) -> OfferC k v m b
$c>> :: forall k v (m :: * -> *) a b.
Monad m =>
OfferC k v m a -> OfferC k v m b -> OfferC k v m b
>> :: forall a b. OfferC k v m a -> OfferC k v m b -> OfferC k v m b
$creturn :: forall k v (m :: * -> *) a. Monad m => a -> OfferC k v m a
return :: forall a. a -> OfferC k v m a
Monad)

-- Returns the result of the computation, along with the remaining offers

runOffer :: Map k v -> OfferC k v m a -> m (Map k v, a)
runOffer :: forall k v (m :: * -> *) a.
Map k v -> OfferC k v m a -> m (Map k v, a)
runOffer Map k v
o (OfferC StateC (Map k v) m a
s) = Map k v -> StateC (Map k v) m a -> m (Map k v, a)
forall s (m :: * -> *) a. s -> StateC s m a -> m (s, a)
runState Map k v
o StateC (Map k v) m a
s

instance (Algebra sig m, Ord k) => Algebra (Offer k v :+: sig) (OfferC k v m) where
  alg :: forall (ctx :: * -> *) (n :: * -> *) a.
Functor ctx =>
Handler ctx n (OfferC k v m)
-> (:+:) (Offer k v) sig n a -> ctx () -> OfferC k v m (ctx a)
alg Handler ctx n (OfferC k v m)
hdl (:+:) (Offer k v) sig n a
sig ctx ()
ctx = case (:+:) (Offer k v) sig n a
sig of
    L (Yoink k
k) -> StateC (Map k v) m (ctx a) -> OfferC k v m (ctx a)
forall k v (m :: * -> *) a. StateC (Map k v) m a -> OfferC k v m a
OfferC do
      (Maybe v
mv, Map k v
remaining) <- (k -> v -> Maybe v) -> k -> Map k v -> (Maybe v, Map k v)
forall k a.
Ord k =>
(k -> a -> Maybe a) -> k -> Map k a -> (Maybe a, Map k a)
M.updateLookupWithKey (\k
_ v
_ -> Maybe v
forall a. Maybe a
Nothing) k
k (Map k v -> (Maybe v, Map k v))
-> StateC (Map k v) m (Map k v)
-> StateC (Map k v) m (Maybe v, Map k v)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StateC (Map k v) m (Map k v)
forall s (sig :: (* -> *) -> * -> *) (m :: * -> *).
Has (State s) sig m =>
m s
get
      Map k v -> StateC (Map k v) m ()
forall s (sig :: (* -> *) -> * -> *) (m :: * -> *).
Has (State s) sig m =>
s -> m ()
put Map k v
remaining
      ctx a -> StateC (Map k v) m (ctx a)
forall a. a -> StateC (Map k v) m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
Maybe v
mv a -> ctx () -> ctx a
forall a b. a -> ctx b -> ctx a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ ctx ()
ctx)
    R sig n a
other -> StateC (Map k v) m (ctx a) -> OfferC k v m (ctx a)
forall k v (m :: * -> *) a. StateC (Map k v) m a -> OfferC k v m a
OfferC (Handler ctx n (StateC (Map k v) m)
-> (:+:) (State (Map k v)) sig n a
-> ctx ()
-> StateC (Map k v) m (ctx a)
forall (ctx :: * -> *) (n :: * -> *) a.
Functor ctx =>
Handler ctx n (StateC (Map k v) m)
-> (:+:) (State (Map k v)) sig n a
-> ctx ()
-> StateC (Map k v) m (ctx a)
forall (sig :: (* -> *) -> * -> *) (m :: * -> *) (ctx :: * -> *)
       (n :: * -> *) a.
(Algebra sig m, Functor ctx) =>
Handler ctx n m -> sig n a -> ctx () -> m (ctx a)
alg ((.getOfferState) (OfferC k v m (ctx x) -> StateC (Map k v) m (ctx x))
-> (ctx (n x) -> OfferC k v m (ctx x))
-> ctx (n x)
-> StateC (Map k v) m (ctx x)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ctx (n x) -> OfferC k v m (ctx x)
Handler ctx n (OfferC k v m)
hdl) (sig n a -> (:+:) (State (Map k v)) sig n a
forall (f :: (* -> *) -> * -> *) (g :: (* -> *) -> * -> *)
       (m :: * -> *) k.
g m k -> (:+:) f g m k
R sig n a
other) ctx ()
ctx)
  {-# INLINE alg #-}