---------------------------------------------------------------
-- Propagate Maybe to the top
--   980409 Patrik Jansson  
-- (Can be generalised to thread any monad, see Thread)
---------------------------------------------------------------
module Propagate(propagate,fprop,sumprop,prodprop,mapMaybe) where
import Base(cata,inn,pmap)

propagate  :: Regular d => d (Maybe a) -> Maybe (d a)
propagate  =  cata (mapMaybe inn . fprop)

-- Bifunctor f => ...
polytypic fprop :: f (Maybe a) (Maybe b) -> Maybe (f a b)
  = case f of
      g + h     ->  sumprop   . (fprop -+- fprop)
      g * h     ->  prodprop  . (fprop -*- fprop)
      Empty     ->  Just
      Par       ->  id
      Rec       ->  id
      d @ g     ->  propagate . (pmap fprop)
      Const t   ->  Just

sumprop  :: Either (Maybe a) (Maybe b) -> Maybe (Either a b)
sumprop  =  mapMaybe Left `either` mapMaybe Right

prodprop :: (Maybe a,Maybe b) -> Maybe (a,b)
prodprop p = case p of
               (Just x,Just y) ->  Just (x,y)
               _               ->  Nothing

---------------------------------------------------------------
--  Maybe functions

mapMaybe :: (a->b) -> Maybe a -> Maybe b
mapMaybe f = maybe Nothing (Just.f)