    module Medium.Controlled where

    -- import qualified Medium
    -- import qualified Medium.Temporal as Temporal

    class C medium where
       control :: (control -> medium control a -> medium control a)

       {- Do actions on each (virtual) constructor, don't recourse. -}
       switchBinary ::
          (a -> b) ->
          (medium control a -> medium control a -> b) ->
          (medium control a -> medium control a -> b) ->
          (control -> medium control a -> b) ->
          (b -> medium control a -> b)
       switchList ::
          (a -> b) ->
          ([medium control a] -> b) ->
          ([medium control a] -> b) ->
          (control -> medium control a -> b) ->
          medium control a -> b

    {-
    {- A variant of fmap that does not only allow manipulation of primitives
       but also of the compositions.
       Though the structure must be preserved. -}
    mapList :: (Medium.Temporal.C b, Medium.C medium) =>
       (a->b) -> ([medium b]->[medium b]) -> ([medium b]->[medium b]) -> medium a -> medium b
    mapList f g h = foldList (prim . f) (serial . g) (parallel . h)

    mapListFlat :: (Medium.Temporal.C b, Medium.C medium) =>
       (a -> b) -> ([medium a] -> [medium b]) -> ([medium a] -> [medium b]) -> medium a -> medium b
    mapListFlat f g h = switchList (prim . f) (serial . g) (parallel . h)
    -}

    {- This is even more general than mapList -}
    foldList :: C medium =>
       (a->b) -> ([b]->b) -> ([b]->b) -> (c->b->b) -> medium c a -> b
    foldList f g h k =
       let recourse    = foldList f g h k
           recurseAll = map recourse
       in  switchList f (g . recurseAll) (h . recurseAll) (\c -> k c . recourse)

    foldBin :: C medium =>
       (a->b) -> (b->b->b) -> (b->b->b) -> (c->b->b) -> b -> medium c a -> b
    foldBin f g h k z =
       let recourse = foldBin f g h k z
           recurseAll op x y = recourse x `op` recourse y
       in  switchBinary f (recurseAll g) (recurseAll h) (\c -> k c . recourse) z