{-# LANGUAGE AllowAmbiguousTypes #-}

-- | Stream algebra and coalgebra for token streams.
--
-- This module holds the neutral stream interface used by both parsers and
-- agents: 'Uncons' destructs a stream, 'Snoc' constructs one.  It knows nothing
-- about parse results, posts, or agents — only about streams @f@ of tokens
-- @s@.
module Circuit.Stream
  ( -- * Boundary result
    These (..),

    -- * Stream coalgebra
    Uncons (..),

    -- * Stream algebra (left construction dual)
    Cons (..),

    -- * Stream algebra (right construction dual)
    Snoc (..),
  )
where

import Data.These (These (..))

instance Uncons [a] a where
  uncons :: [a] -> These a [a]
uncons [] = [a] -> These a [a]
forall a b. b -> These a b
That []
  uncons [a
x] = a -> These a [a]
forall a b. a -> These a b
This a
x
  uncons (a
x : [a]
xs) = a -> [a] -> These a [a]
forall a b. a -> b -> These a b
These a
x [a]
xs
  nil :: [a]
nil = []

instance Cons [a] a where
  cons :: a -> [a] -> [a]
cons = (:)
  consNil :: [a]
consNil = []

instance Snoc [a] a where
  snoc :: [a] -> a -> [a]
snoc [a]
xs a
x = [a]
xs [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a
x]
  snocNil :: [a]
snocNil = []

-- | Stream coalgebra with explicit boundary.
--
-- @uncons [x] = This x@ announces the final element at extraction. The
-- 'nil' value is the stream-specific empty used to continue after a 'This'
-- result.
class Uncons f s where
  uncons :: f -> These s f
  nil :: f

-- | Stream algebra: construct a stream by prepending one token on the left.
--
-- This is the construction dual of 'Uncons'.  Together they let code move
-- back and forth between tokens and streams using the same coalgebra.
class Cons f s where
  -- | Prepend one token to the left of a stream.
  cons :: s -> f -> f

  -- | The empty stream.
  consNil :: f

-- | Stream algebra: construct a stream by appending one token on the right.
--
-- This is the right-handed dual of 'Uncons'.
class Snoc f s where
  -- | Append one token to the right of a stream.
  snoc :: f -> s -> f

  -- | The empty stream.
  snocNil :: f