{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeOperators #-}

module Data.Invertible.Strong where

import Prelude hiding ((.), id, fst, snd, curry)
import qualified Prelude as P
import Data.Invertible.Bijection
-- import Data.Invertible.Function
import Data.Invertible.Profunctor
import Data.Invertible.Tuple

-- | Generalizing 'Star' of a strong 'Functor'
--
-- /Note:/ Every 'Functor' in Haskell is strong with respect to @(,)@.
--
-- This describes profunctor strength with respect to the product structure
-- of Hask.
--
-- <http://www-kb.is.s.u-tokyo.ac.jp/~asada/papers/arrStrMnd.pdf>
class IsoProfunctor p => IsoStrong p where
  first' :: p a b -> p (a, c) (b, c)
  first' = dimap swap swap P.. second'

  second' :: p a b -> p (c, a) (c, b)
  second' = dimap swap swap P.. first'

instance IsoStrong (Bijection (->)) where
  first' (ab :<->: ba) = (\ ~(a, c) -> (ab a, c)) :<->: (\ ~(b, c) -> (ba b, c))
  {-# INLINE first' #-}
  second' (ab :<->: ba) = (\ ~(c, a) -> (c, ab a)) :<->: (\ ~(c, b) -> (c, ba b))
  {-# INLINE second' #-}