module Control.Isomorphism.Partial.Prim
( Iso ()
, inverse
, apply
, unapply
, IsoFunctor ((<$>))
, ignore
, (***)
, (|||)
, associate
, commute
, unit
, element
, subset
, iterate
, distribute
) where
import Prelude ()
import Control.Monad (liftM2, (>=>), fmap, mplus)
import Control.Category (Category (id, (.)))
import Data.Bool (Bool, otherwise)
import Data.Either (Either (Left, Right))
import Data.Eq (Eq ((==)))
import Data.Maybe (Maybe (Just, Nothing))
import Control.Isomorphism.Partial.Unsafe (Iso (Iso))
inverse :: Iso alpha beta -> Iso beta alpha
inverse (Iso f g) = Iso g f
apply :: Iso alpha beta -> alpha -> Maybe beta
apply (Iso f g) = f
unapply :: Iso alpha beta -> beta -> Maybe alpha
unapply = apply . inverse
instance Category Iso where
g . f = Iso (apply f >=> apply g)
(unapply g >=> unapply f)
id = Iso Just Just
infix 5 <$>
class IsoFunctor f where
(<$>) :: Iso alpha beta -> (f alpha -> f beta)
ignore :: alpha -> Iso alpha ()
ignore x = Iso f g where
f _ = Just ()
g () = Just x
(***) :: Iso alpha beta -> Iso gamma delta -> Iso (alpha, gamma) (beta, delta)
i *** j = Iso f g where
f (a, b) = liftM2 (,) (apply i a) (apply j b)
g (c, d) = liftM2 (,) (unapply i c) (unapply j d)
(|||) :: Iso alpha gamma -> Iso beta gamma -> Iso (Either alpha beta) gamma
i ||| j = Iso f g where
f (Left x) = apply i x
f (Right x) = apply j x
g y = (Left `fmap` unapply i y) `mplus` (Right `fmap` unapply j y)
associate :: Iso (alpha, (beta, gamma)) ((alpha, beta), gamma)
associate = Iso f g where
f (a, (b, c)) = Just ((a, b), c)
g ((a, b), c) = Just (a, (b, c))
commute :: Iso (alpha, beta) (beta, alpha)
commute = Iso f f where
f (a, b) = Just (b, a)
unit :: Iso alpha (alpha, ())
unit = Iso f g where
f a = Just (a, ())
g (a, ()) = Just a
distribute :: Iso (alpha, Either beta gamma) (Either (alpha, beta) (alpha, gamma))
distribute = Iso f g where
f (a, Left b) = Just (Left (a, b))
f (a, Right c) = Just (Right (a, c))
g (Left (a, b)) = Just (a, Left b)
g (Right (a, b)) = Just (a, Right b)
element :: Eq alpha => alpha -> Iso () alpha
element x = Iso
(\a -> Just x)
(\b -> if x == b then Just () else Nothing)
subset :: (alpha -> Bool) -> Iso alpha alpha
subset p = Iso f f where
f x | p x = Just x | otherwise = Nothing
iterate :: Iso alpha alpha -> Iso alpha alpha
iterate step = Iso f g where
f = Just . driver (apply step)
g = Just . driver (unapply step)
driver :: (alpha -> Maybe alpha) -> (alpha -> alpha)
driver step state
= case step state of
Just state' -> driver step state'
Nothing -> state