Skip to content

Instantly share code, notes, and snippets.

@ekmett
Created December 6, 2012 08:11
Show Gist options
  • Save ekmett/4222679 to your computer and use it in GitHub Desktop.
Save ekmett/4222679 to your computer and use it in GitHub Desktop.
Composable Iso
{-# LANGUAGE GADTs #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
import Control.Applicative
import Control.Arrow
import Control.Category
import Prelude hiding ((.),id)
class Coalgebraic (k :: * -> * -> *) (x :: *) where
type A k x :: *
type B k x :: *
type family ArgOf (f_b :: *) :: *
type instance ArgOf (f b) = b
instance (Functor f, f_b ~ f b) => Coalgebraic (->) (a -> f_b) where
type A (->) (a -> f_b) = a
type B (->) (a -> f_b) = ArgOf f_b
class (Category k, Coalgebraic k x, Coalgebraic k y) => Isomorphic k x y where
iso :: (A k y -> A k x) -> (B k x -> B k y) -> k x y
isoid :: (A k x ~ A k y, B k x ~ B k y) => k x y
instance (Functor f, x ~ (a -> f b), y ~ (s -> f t)) => Isomorphic (->) x y where
iso sa bt afb s = bt <$> afb (sa s)
isoid = id
instance Coalgebraic Isoid (a,b) where
type A Isoid (a,b) = a
type B Isoid (a,b) = b
instance (x ~ (a,b), y ~ (s,t)) => Isomorphic Isoid x y where
iso = Iso
isoid = Isoid
data Isoid x y where
Isoid :: Isoid x x
Iso :: (s -> a) -> (b -> t) -> Isoid (a,b) (s,t)
instance Category Isoid where
id = Isoid
Isoid . x = x
x . Isoid = x
Iso xs ty . Iso sa bt = Iso (sa.xs) (ty.bt)
type AnIso s t a b = Isoid (a,b) (s,t)
type Iso s t a b = forall k x y. (Isomorphic k x y, A k x ~ a, B k x ~ b, A k y ~ s, B k y ~ t) => k x y
plus1 :: (Num a, Num b) => Iso a b a b
plus1 = iso (+1) (subtract 1)
from :: AnIso s t a b -> Iso b a t s
from (Iso sa bt) = iso bt sa
from Isoid = isoid
class Isomorphic k x y => Prismatic k x y where
prism :: (B k x -> B k y) -> (A k y -> Either (B k y) (A k x)) -> k x y
instance (Applicative f, x ~ (a -> f b), y ~ (s -> f t)) => Prismatic (->) x y where
prism bt seta afb = either pure (fmap bt . afb) . seta
data Prismoid x y where
Prismoid :: Prismoid x x
Prism :: (b -> t) -> (s -> Either t a) -> Prismoid (a,b) (s,t)
instance Coalgebraic Prismoid (a,b) where
type A Prismoid (a,b) = a
type B Prismoid (a,b) = b
instance Category Prismoid where
id = Prismoid
x . Prismoid = x
Prismoid . x = x
Prism ty xeys . Prism bt seta = Prism (ty.bt) $ \x ->
case xeys x of
Left y -> Left y
Right s -> case seta s of
Left t -> Left (ty t)
Right a -> Right a
instance (x ~ (a,b), y ~ (s,t)) => Isomorphic Prismoid x y where
iso sa bt = Prism bt (Right . sa)
isoid = Prismoid
instance (x ~ (a,b), y ~ (s,t)) => Prismatic Prismoid x y where
prism = Prism
type Prism s t a b = forall k x y. (Prismatic k x y, A k x ~ a, B k x ~ b, A k y ~ s, B k y ~ t) => k x y
_right :: Prism (Either c a) (Either c b) a b
_right = prism Right (left Left)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment