packages feed

gambler-0.4.0.0: source/Fold/ShortcutNonempty/Type.hs

module Fold.ShortcutNonempty.Type
  (
    ShortcutNonemptyFold (..),
    Will (..), Vitality (..),
  )
  where

import Control.Applicative (Applicative, liftA2, pure, (<*>))
import Data.Functor (Functor, fmap)
import Data.Monoid (Monoid, mempty)
import Data.Semigroup (Semigroup, (<>))
import Strict (Will (..), Vitality (..))
import Data.Void (absurd)

import qualified Strict

{- | Processes at least one input of type @a@, has the ability to halt
     midway through the stream, and results in a value of type @b@ -}
data ShortcutNonemptyFold a b = forall x y. ShortcutNonemptyFold
    { initial :: a -> Vitality x y
    , step :: y -> a -> Vitality x y
    , extract :: Vitality x y -> b
    }

instance Functor (ShortcutNonemptyFold a) where
    fmap f ShortcutNonemptyFold{ step, initial, extract } =
        ShortcutNonemptyFold{ initial, step, extract = \x -> f (extract x) }

instance Applicative (ShortcutNonemptyFold a) where
    pure b = ShortcutNonemptyFold
        { initial = \_ -> Dead ()
        , step = absurd
        , extract = \e -> case e of { Dead () -> b }
        }

    (<*>)
        ShortcutNonemptyFold{ initial = initialL, step = stepL, extract = extractL }
        ShortcutNonemptyFold{ initial = initialR, step = stepR, extract = extractR } =
          ShortcutNonemptyFold
            { initial = \a -> Strict.vitality2 (initialL a) (initialR a)
            , step = \(Strict.Tuple2 xL xR) a -> Strict.vitality2
                (Strict.unlessDead (\x -> stepL x a) xL)
                (Strict.unlessDead (\x -> stepR x a) xR)
            , extract = \e -> case e of { Dead x -> ex x; Alive _ x -> ex x }
            }
          where
            ex (Strict.Tuple2 xL xR) = (extractL xL) (extractR xR)

instance Semigroup b => Semigroup (ShortcutNonemptyFold a b) where
    (<>) = liftA2 (<>)

instance Monoid b => Monoid (ShortcutNonemptyFold a b) where
    mempty = pure mempty