packages feed

heftia-effects-0.4.0.0: src/Control/Monad/Hefty/ShiftReset.hs

-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.

module Control.Monad.Hefty.ShiftReset where

import Control.Monad.Hefty (
    Eff,
    interpretH,
    interpretHBy,
    interpretRecHWith,
    raiseH,
    runEff,
    type (~>),
 )
import Data.Effect.Key (KeyH (KeyH))
import Data.Effect.ShiftReset (
    Reset (Reset),
    Shift,
    Shift' (Shift),
    Shift_,
    Shift_' (Shift_'),
 )

type ShiftFix ans eh ef = Shift ans (ShiftBase ans eh ef)

newtype ShiftBase ans eh ef a
    = ShiftBase {unShiftBase :: Eff (Shift ans (ShiftBase ans eh ef) ': eh) ef a}
    deriving newtype (Functor, Applicative, Monad)

evalShift :: Eff '[ShiftFix ans '[] ef] ef ans -> Eff '[] ef ans
evalShift = runShift pure

runShift :: (a -> Eff '[] ef ans) -> Eff '[ShiftFix ans '[] ef] ef a -> Eff '[] ef ans
runShift f =
    interpretHBy f \e k ->
        evalShift $ case e of
            KeyH (Shift g) -> unShiftBase $ g (ShiftBase . raiseH . k) ShiftBase

withShift :: Eff '[ShiftFix ans '[] '[Eff eh ef]] '[Eff eh ef] ans -> Eff eh ef ans
withShift = runEff . evalShift

runShift_ :: forall r ef. Eff (Shift_ (Eff r ef) ': r) ef ~> Eff r ef
runShift_ = interpretRecHWith \(KeyH (Shift_' f)) k -> f k id

runReset :: forall r ef. Eff (Reset ': r) ef ~> Eff r ef
runReset = interpretH \(Reset a) -> a