module Data.BranchingStream
  ( Strf(..)
  , hdf
  , tlf
  , genStrf
  , strfToList
  ) where

import Control.Comonad
  

{-|
An H-branching stream. The specific functor chosen for /H/ determines
its behavior:

* @Strf 'Id'@ is an infinite stream

* @Strf Maybe@ is a non-empty stream

* @Strf []@ is a rose tree
-}
data Strf h c = Consf c (h (Strf h c))

hdf :: Strf h c -> c
hdf (Consf x _) = x

tlf :: Strf h c -> h (Strf h c)
tlf (Consf _ xs) = xs

genStrf :: Functor h
        => (a -> c) -> (a -> h a) -> a -> Strf h c
genStrf g1 g2 z = Consf (g1 z) (fmap (genStrf g1 g2) (g2 z))

instance Functor h => Functor (Strf h) where
  fmap g = genStrf (g . hdf) tlf

instance Functor h => Comonad (Strf h) where
  extract   = hdf
  duplicate = genStrf id tlf

strfToList :: Strf Maybe a -> [a]
strfToList (Consf x xs) = x : maybe [] strfToList xs