module Flite.Descend where

import Control.Monad
import Flite.Identity
import Flite.Writer

class Descend a where
  descendM :: Monad m => (a -> m a) -> a -> m a

descend :: Descend a => (a -> a) -> a -> a
descend f a = runIdentity (descendM (return . f) a)

extract :: Descend a => (a -> [b]) -> a -> [b]
extract f = fst . runWriter . descendM (\a -> writeMany (f a) >> return a)

universe :: Descend a => a -> [a]
universe a = a : extract universe a