module Data.Profunctor where

import Prelude hiding ((.), id)

import Control.Arrow (Kleisli (..))
import Control.Category
import Control.Monad

class Profunctor p where
    dimap :: (a -> b) -> (c -> d) -> p b c -> p a d
    dimap f g = lmap f . rmap g

    lmap :: (a -> b) -> p b c -> p a c
    lmap f = dimap f id

    rmap :: (b -> c) -> p a b -> p a c
    rmap g = dimap id g

instance Profunctor (->) where
    dimap f g a = g . a . f

instance Monad m => Profunctor (Kleisli m) where
    dimap f g (Kleisli a) = Kleisli (fmap g . a . f)