functor-combo-0.0.2: src/FunctorCombo/Functor.hs
{-# LANGUAGE TypeOperators, EmptyDataDecls, StandaloneDeriving, DeriveFunctor #-}
{-# OPTIONS_GHC -Wall #-}
----------------------------------------------------------------------
-- |
-- Module : FunctorCombo.Functor
-- Copyright : (c) Conal Elliott 2010
-- License : BSD3
--
-- Maintainer : conal@conal.net
-- Stability : experimental
--
-- Standard building blocks for functors
----------------------------------------------------------------------
module FunctorCombo.Functor
(
Const(..),Void,Unit,Id(..),unId,inId,inId2,(:+:)(..),eitherF
, (:*:)(..),(:.)(..),unO,inO,inO2,(~>)
) where
import Control.Applicative (Applicative(..),Const(..))
import Control.Compose (Id(..),unId,inId,inId2,(:.)(..),unO,inO,inO2,(~>))
-- infixl 9 :.
infixl 7 :*:
infixl 6 :+:
{--------------------------------------------------------------------
Generic functor constructors
--------------------------------------------------------------------}
-- | Empty/zero type constructor (no inhabitants)
data Void a
-- | Unit type constructor (one inhabitant)
type Unit = Const ()
-- From Control.Compose:
--
-- newtype Id a = Id a
-- | Product on unary type constructors
data (f :*: g) a = f a :*: g a deriving (Show)
-- | Sum on unary type constructors
data (f :+: g) a = InL (f a) | InR (g a) deriving (Show)
eitherF :: (f a -> b) -> (g a -> b) -> (f :+: g) a -> b
eitherF p _ (InL fa) = p fa
eitherF _ q (InR ga) = q ga
-- From Control.Compose:
--
-- newtype (g :. f) a = O (g (f a))
{--------------------------------------------------------------------
Functor and Applicative instances for generic constructors
--------------------------------------------------------------------}
instance Functor Void where
fmap _ = error "Void fmap: no void value" -- so ghc won't complain
-- instance Functor Id where
-- fmap h (Id a) = Id (h a)
-- deriving instance Functor Id
-- instance (Functor f, Functor g) => Functor (f :+: g) where
-- fmap h (InL fa) = InL (fmap h fa)
-- fmap h (InR ga) = InR (fmap h ga)
-- i.e.,
--
-- fmap h . InL == InL . fmap h
-- fmap h . InR == InR . fmap h
deriving instance (Functor f, Functor g) => Functor (f :+: g)
-- instance (Functor f, Functor g) => Functor (f :*: g) where
-- fmap h (fa :*: ga) = fmap h fa :*: fmap h ga
-- Or:
deriving instance (Functor f, Functor g) => Functor (f :*: g)
-- TODO: Verify that the deriving instances are equivalent to the explicit versions.
-- What about Applicative instances? I think Void could implement (<*>)
-- but not pure. Hm. Id and (:*:) are easy, while (:+:) is problematic.
-- instance Applicative Id where
-- pure a = Id a
-- Id f <*> Id x = Id (f x)
-- instance Applicative Id where
-- pure = Id
-- (<*>) = inId2 ($)
instance (Applicative f, Applicative g) => Applicative (f :*: g) where
pure a = pure a :*: pure a
(f :*: g) <*> (a :*: b) = (f <*> a) :*: (g <*> b)
-- instance (Functor g, Functor f) => Functor (g :. f) where
-- fmap = inO.fmap.fmap
-- or
-- deriving instance (Functor g, Functor f) => Functor (g :. f)