Skip to content

Instantly share code, notes, and snippets.

@sjoerdvisscher
Created March 14, 2011 00:45
Show Gist options
  • Save sjoerdvisscher/868605 to your computer and use it in GitHub Desktop.
Save sjoerdvisscher/868605 to your computer and use it in GitHub Desktop.
If a functor is representable and its key is a fixed point, then there's a much faster way to implement fmap, pure and ap.
{-# LANGUAGE TypeFamilies, DeriveFunctor #-}
import Data.Key (Key)
import Data.Functor.Foldable (Fix(..), fold, unfold)
import Control.Applicative
import Control.Arrow (left)
data RF f a r = RF { getRF :: Key f -> Either a (Key f, r) } deriving Functor
type R f a = Fix (RF f a)
class IndexableFix f where
indexFix :: f a -> R f a
class IndexableFix f => RepresentableFix f where
tabulateFix :: R f a -> f a
index' :: IndexableFix f => f a -> Key f -> a
index' = fold ((either id (uncurry (flip ($))) .) . getRF) . indexFix
fmapRepFix :: RepresentableFix f => (a -> b) -> f a -> f b
fmapRepFix f = tabulateFix . fold (Fix . RF . fmap (left f) . getRF) . indexFix
pureRepFix :: RepresentableFix f => a -> f a
pureRepFix = tabulateFix . Fix . RF . const . Left
apRepFix :: RepresentableFix f => f (a -> b) -> f a -> f b
apRepFix ff fa = tabulateFix (h (indexFix ff) (indexFix fa))
where
h (Fix rf) (Fix ra) = Fix . RF $ \k ->
case (getRF rf k, getRF ra k) of
(Left f, Left x) -> Left (f x)
(Right (k', rf'), Right (_, ra')) -> Right (k', h rf' ra')
bindRepFix :: RepresentableFix f => f a -> (a -> f b) -> f b
-- bindRepFix m f = tabulateFix (Fix . RF $ \k -> let Fix (RF rf) = indexFix (f (index' m k)) in rf k) -- does not produce
bindRepFix m f = undefined
data Stream a = a :<: Stream a deriving Show
data Peano = Z | S Peano
type instance Key Stream = Peano
instance IndexableFix Stream where
indexFix = unfold (RF . f)
where
f (a :<: _ ) Z = Left a
f (_ :<: as) (S n) = Right (n, as)
instance RepresentableFix Stream where
tabulateFix = fold g
where
g (RF f) = a :<: as
where
Left a = f Z
Right (n, as) = f (S n)
instance Functor Stream where
fmap = fmapRepFix
instance Applicative Stream where
pure = pureRepFix
(<*>) = apRepFix
tabulate' :: (Peano -> a) -> Stream a
tabulate' = tabulateFix . Fix . RF . g
where
g f Z = Left (f Z)
g f (S n) = Right (n, Fix . RF . g $ f . S)
instance Monad Stream where
return = pureRepFix
m >>= f = bindRepFix m f
test :: Stream Int
test = 1 :<: fmap (+1) test
fromPeano :: Peano -> Int
fromPeano Z = 0
fromPeano (S n) = 1 + fromPeano n
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment