packages feed

spectacle-1.0.0: src/Control/Mealy.hs

{-# LANGUAGE TupleSections #-}

-- |
--
-- @since 1.0.0
module Control.Mealy
  ( -- * Mealy Machines
    Mealy,
    runMealy,

    -- ** Applicative Transformer
    MealyM (MealyM),
    runMealyM,
    arrM,
    refold,
  )
where

import Control.Applicative (liftA2)
import Data.Functor.Identity (Identity (runIdentity))

-- ---------------------------------------------------------------------------------------------------------------------

newtype MealyM m a b = MealyM
  {runMealyM :: a -> m (b, MealyM m a b)}
  deriving (Functor)

arrM :: Functor m => (a -> m b) -> MealyM m a b
arrM f = let k = MealyM (fmap (,k) . f) in k

refold :: Monad m => (a -> b -> MealyM m a c -> m (c, MealyM m a c)) -> MealyM m a b -> MealyM m a c
refold f (MealyM k) =
  MealyM \s -> do
    (x, k') <- k s
    f s x (refold f k')

type Mealy = MealyM Identity

runMealy :: Mealy a b -> a -> (b, Mealy a b)
runMealy (MealyM k) x = runIdentity (k x)

-- | @since 1.0.0
instance (Applicative m, Semigroup b) => Semigroup (MealyM m a b) where
  MealyM f <> MealyM g = MealyM \x -> liftA2 (<>) (f x) (g x)
  {-# INLINE (<>) #-}

-- | @since 1.0.0
instance (Applicative m, Monoid b) => Monoid (MealyM m a b) where
  mempty = MealyM \_ -> pure mempty
  {-# INLINE mempty #-}

-- | @since 1.0.0
instance Applicative m => Applicative (MealyM m a) where
  pure x = MealyM \_ -> pure (x, pure x)
  {-# INLINE pure #-}

  MealyM m <*> MealyM n = MealyM \x ->
    liftA2 (\(f, m') (c, n') -> (f c, m' <*> n')) (m x) (n x)
  {-# INLINE (<*>) #-}