{-# LANGUAGE Trustworthy #-}
-- |
-- Copyright: (c) 2021 Xy Ren
-- License: BSD3
-- Maintainer: xy.r@outlook.com
-- Stability: experimental
-- Portability: non-portable (GHC only)
module Cleff.Input
  ( -- * Effect
    Input (..)
    -- * Operations
  , input
  , inputs
    -- * Interpretations
  , runInputConst
  , inputToListState
  , inputToReader
  , runInputEff
  , mapInput
  , bindInput
  ) where

import           Cleff
import           Cleff.Reader
import           Cleff.State

-- * Effect

-- | An effect that is capable of reading from some input source, such as an input stream.
data Input i :: Effect where
  Input :: Input i m i

-- * Operations

makeEffect_ ''Input

-- | Read an input value from an input source.
input :: Input i :> es => Eff es i

-- | Apply a function to the result of 'input'.
inputs :: Input i :> es => (i -> i') -> Eff es i'
inputs :: (i -> i') -> Eff es i'
inputs i -> i'
f = i -> i'
f (i -> i') -> Eff es i -> Eff es i'
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Eff es i
forall i (es :: [Effect]). (Input i :> es) => Eff es i
input

-- * Interpretations

-- | Run an 'Input' effect by giving a constant input value.
runInputConst :: i -> Eff (Input i : es) ~> Eff es
runInputConst :: i -> Eff (Input i : es) ~> Eff es
runInputConst i
x = Handler (Input i) es -> Eff (Input i : es) ~> Eff es
forall (e :: Effect) (es :: [Effect]).
Handler e es -> Eff (e : es) ~> Eff es
interpret \case
  Input i (Eff esSend) a
Input -> i -> Eff es i
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure i
x

-- | Run an 'Input' effect by going through a list of values.
inputToListState :: Eff (Input (Maybe i) : es) ~> Eff (State [i] : es)
inputToListState :: Eff (Input (Maybe i) : es) a -> Eff (State [i] : es) a
inputToListState = Handler (Input (Maybe i)) (State [i] : es)
-> Eff (Input (Maybe i) : es) ~> Eff (State [i] : es)
forall (e' :: Effect) (e :: Effect) (es :: [Effect]).
Handler e (e' : es) -> Eff (e : es) ~> Eff (e' : es)
reinterpret \case
  Input (Maybe i) (Eff esSend) a
Input -> ([i] -> (Maybe i, [i])) -> Eff (State [i] : es) (Maybe i)
forall s (es :: [Effect]) a.
(State s :> es) =>
(s -> (a, s)) -> Eff es a
state \case
    []     -> (Maybe i
forall a. Maybe a
Nothing, [])
    i
x : [i]
xs -> (i -> Maybe i
forall a. a -> Maybe a
Just i
x, [i]
xs)

-- | Run an 'Input' in terms of a 'Reader'.
--
-- @since 0.2.1.0
inputToReader :: Eff (Input i : es) ~> Eff (Reader i : es)
inputToReader :: Eff (Input i : es) a -> Eff (Reader i : es) a
inputToReader = Handler (Input i) (Reader i : es)
-> Eff (Input i : es) ~> Eff (Reader i : es)
forall (e' :: Effect) (e :: Effect) (es :: [Effect]).
Handler e (e' : es) -> Eff (e : es) ~> Eff (e' : es)
reinterpret \case
  Input i (Eff esSend) a
Input -> Eff (Reader i : es) a
forall r (es :: [Effect]). (Reader r :> es) => Eff es r
ask

-- | Run an 'Input' effect by performing a computation for each input request.
runInputEff :: Eff es i -> Eff (Input i : es) ~> Eff es
runInputEff :: Eff es i -> Eff (Input i : es) ~> Eff es
runInputEff Eff es i
m = Handler (Input i) es -> Eff (Input i : es) ~> Eff es
forall (e :: Effect) (es :: [Effect]).
Handler e es -> Eff (e : es) ~> Eff es
interpret \case
  Input i (Eff esSend) a
Input -> Eff es i
Eff es a
m

-- | Transform an 'Input' effect into another one already in the effect stack, by a pure function.
--
-- @since 0.2.1.0
mapInput :: Input i' :> es => (i' -> i) -> Eff (Input i : es) ~> Eff es
mapInput :: (i' -> i) -> Eff (Input i : es) ~> Eff es
mapInput i' -> i
f = Handler (Input i) es -> Eff (Input i : es) ~> Eff es
forall (e :: Effect) (es :: [Effect]).
Handler e es -> Eff (e : es) ~> Eff es
interpret \case
  Input i (Eff esSend) a
Input -> i' -> i
f (i' -> i) -> Eff es i' -> Eff es i
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Eff es i'
forall i (es :: [Effect]). (Input i :> es) => Eff es i
input

-- | Transform an 'Input' effect into another one already in the effect stack, by an effectful computation.
--
-- @since 0.2.1.0
bindInput :: Input i' :> es => (i' -> Eff es i) -> Eff (Input i : es) ~> Eff es
bindInput :: (i' -> Eff es i) -> Eff (Input i : es) ~> Eff es
bindInput i' -> Eff es i
f = Handler (Input i) es -> Eff (Input i : es) ~> Eff es
forall (e :: Effect) (es :: [Effect]).
Handler e es -> Eff (e : es) ~> Eff es
interpret \case
  Input i (Eff esSend) a
Input -> i' -> Eff es i
f (i' -> Eff es i) -> Eff es i' -> Eff es i
forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
=<< Eff es i'
forall i (es :: [Effect]). (Input i :> es) => Eff es i
input