{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module ApplyOver.Over
  ( Over (..)
  ) where

import ApplyOver.Gen (Gen (..))

class Over f g r where
  over :: f -> g -> (Maybe r, g)

-- TODO Idea: make Gen Applicative and feed it with f partials

-- TODO try to use f instead of (ap (a -> b))
-- and use type family to extract ap, a, b for Gen and (ap b) for Over
instance (Applicative ap, Gen g (ap a), Over (ap b) g r) => Over (ap (a -> b)) g r where
  over f g =
    let (a', g') = next g in
    case a' of
      Just a -> over (f <*> a) g'
      Nothing -> (Nothing, g')

-- TODO define with instance above and Identity?
-- instance (Gen g a, Over b g r) => Over (a -> b) g r where
--   over f g =
--     let (a', g') = next g in
--     case a' of
--       Just a -> over (f a) g'
--       Nothing -> (Nothing, g')

instance Over r g r where
  over r g = (Just r, g)
