cleff-0.2.1.0: src/Cleff/Input.hs
{-# 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
-- | Apply a function to the result of 'input'.
inputs :: Input i :> es => (i -> i') -> Eff es i'
inputs f = f <$> input
-- * Interpretations
-- | Run an 'Input' effect by giving a constant input value.
runInputConst :: i -> Eff (Input i ': es) ~> Eff es
runInputConst x = interpret \case
Input -> pure x
{-# INLINE runInputConst #-}
-- | Run an 'Input' effect by going through a list of values.
inputToListState :: Eff (Input (Maybe i) ': es) ~> Eff (State [i] ': es)
inputToListState = reinterpret \case
Input -> state \case
[] -> (Nothing, [])
x : xs -> (Just x, xs)
{-# INLINE inputToListState #-}
-- | Run an 'Input' in terms of a 'Reader'.
--
-- @since 0.2.1.0
inputToReader :: Eff (Input i ': es) ~> Eff (Reader i ': es)
inputToReader = reinterpret \case
Input -> ask
{-# INLINE inputToReader #-}
-- | Run an 'Input' effect by performing a computation for each input request.
runInputEff :: Eff es i -> Eff (Input i ': es) ~> Eff es
runInputEff m = interpret \case
Input -> m
{-# INLINE runInputEff #-}
-- | 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 f = interpret \case
Input -> f <$> input
{-# INLINE mapInput #-}
-- | 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 f = interpret \case
Input -> f =<< input
{-# INLINE bindInput #-}