idris2-profunctors/Data/Profunctor/Types.idr

313 lines
7.7 KiB
Idris
Raw Permalink Normal View History

2023-03-07 22:15:08 -05:00
||| This module contains the Profunctor interface itself, along with a few
||| examples of profunctors.
2023-03-04 23:31:48 -05:00
module Data.Profunctor.Types
import Data.Contravariant
import Data.Morphisms
%default total
2023-03-07 22:15:08 -05:00
------------------------------------------------------------------------------
-- Profunctor interface
------------------------------------------------------------------------------
||| An interface for (self-enriched) profunctors `Idr -/-> Idr`.
|||
||| Formally, a profunctor is a binary functor that is contravariant in its
||| first argument and covariant in its second. A common example of a profunctor
||| is the (non-dependent) function type.
|||
||| Implementations can be defined by specifying either `dimap` or both `lmap`
||| and `rmap`.
|||
||| Laws:
||| * `dimap id id = id`
||| * `dimap (f . g) (h . i) = dimap g h . dimap f i`
2023-03-04 23:31:48 -05:00
public export
interface Profunctor p where
2023-03-07 22:15:08 -05:00
||| Map over both parameters of a profunctor at the same time, with the
||| left function argument mapping contravariantly.
2023-03-04 23:31:48 -05:00
dimap : (a -> b) -> (c -> d) -> p b c -> p a d
dimap f g = lmap f . rmap g
2023-03-07 22:15:08 -05:00
||| Map contravariantly over the first parameter of a profunctor.
2023-03-04 23:31:48 -05:00
lmap : (a -> b) -> p b c -> p a c
lmap f = dimap f id
2023-03-07 22:15:08 -05:00
||| Map covariantly over the second parameter of a profunctor.
2023-03-04 23:31:48 -05:00
rmap : (b -> c) -> p a b -> p a c
rmap = dimap id
2023-03-04 23:57:12 -05:00
infix 0 :->
2023-03-07 22:15:08 -05:00
||| A transformation between profunctors that preserves their type parameters.
|||
||| Formally, this is a natural transformation of functors `Idrᵒᵖ * Idr => Idr`.
|||
||| If the transformation is `tr`, then we have the following law:
||| * `tr . dimap f g = dimap f g . tr`
2023-03-04 23:57:12 -05:00
public export
0 (:->) : (p, q : k -> k' -> Type) -> Type
p :-> q = forall a, b. p a b -> q a b
2023-03-04 23:57:12 -05:00
2023-03-07 22:15:08 -05:00
------------------------------------------------------------------------------
-- Implementations for existing types
------------------------------------------------------------------------------
2023-03-04 23:31:48 -05:00
public export
2023-03-04 23:31:48 -05:00
Profunctor Morphism where
dimap f g (Mor h) = Mor (g . h . f)
lmap f (Mor g) = Mor (g . f)
rmap = map
namespace Profunctor
2023-03-07 22:15:08 -05:00
||| A named implementation of `Profunctor` for function types.
||| Use this to avoid having to use a type wrapper like `Morphism`.
public export
2023-03-04 23:31:48 -05:00
[Function] Profunctor (\a,b => a -> b) where
dimap f g h = g . h . f
lmap = flip (.)
rmap = (.)
public export
2023-03-04 23:31:48 -05:00
Functor f => Profunctor (Kleislimorphism f) where
dimap f g (Kleisli h) = Kleisli (map g . h . f)
lmap f (Kleisli g) = Kleisli (g . f)
rmap = map
2023-03-07 22:15:08 -05:00
------------------------------------------------------------------------------
2023-03-08 13:30:55 -05:00
-- New profunctor types
2023-03-07 22:15:08 -05:00
------------------------------------------------------------------------------
2023-03-04 23:31:48 -05:00
2023-03-07 22:15:08 -05:00
||| Lift a functor into a profunctor in the return type.
|||
||| This type is equivalent to `Kleislimorphism` except for the polymorphic type
||| of `b`.
2023-03-04 23:31:48 -05:00
public export
2023-03-04 23:56:35 -05:00
record Star {0 k : Type} (f : k -> Type) a (b : k) where
2023-03-04 23:31:48 -05:00
constructor MkStar
applyStar : a -> f b
public export
2023-03-04 23:31:48 -05:00
Functor f => Functor (Star f a) where
map f (MkStar g) = MkStar (map f . g)
public export
2023-03-04 23:31:48 -05:00
Applicative f => Applicative (Star f a) where
pure = MkStar . const . pure
MkStar f <*> MkStar g = MkStar (\x => f x <*> g x)
public export
2023-03-04 23:31:48 -05:00
Monad f => Monad (Star f a) where
MkStar f >>= g = MkStar $ \x => do
a <- f x
applyStar (g a) x
public export
2023-03-04 23:31:48 -05:00
Contravariant f => Contravariant (Star f a) where
contramap f (MkStar g) = MkStar (contramap f . g)
public export
2023-03-04 23:31:48 -05:00
Functor f => Profunctor (Star f) where
dimap f g (MkStar h) = MkStar (map g . h . f)
lmap f (MkStar g) = MkStar (g . f)
rmap f (MkStar g) = MkStar (map f . g)
2023-03-07 22:15:08 -05:00
||| Lift a functor into a profunctor in the argument type.
2023-03-04 23:31:48 -05:00
public export
2023-03-04 23:56:35 -05:00
record Costar {0 k : Type} (f : k -> Type) (a : k) b where
2023-03-04 23:31:48 -05:00
constructor MkCostar
applyCostar : f a -> b
public export
2023-03-04 23:31:48 -05:00
Functor (Costar f a) where
map f (MkCostar g) = MkCostar (f . g)
public export
2023-03-04 23:31:48 -05:00
Applicative (Costar f a) where
pure = MkCostar . const
MkCostar f <*> MkCostar g = MkCostar (\x => f x (g x))
public export
2023-03-04 23:31:48 -05:00
Monad (Costar f a) where
MkCostar f >>= g = MkCostar (\x => applyCostar (g (f x)) x)
public export
2023-03-04 23:31:48 -05:00
Functor f => Profunctor (Costar f) where
dimap f g (MkCostar h) = MkCostar (g . h . map f)
lmap f (MkCostar g) = MkCostar (g . map f)
rmap f (MkCostar g) = MkCostar (f . g)
2023-03-07 22:15:08 -05:00
||| The profunctor that ignores its argument type.
||| Equivalent to `const id` up to isomorphism.
2023-03-04 23:31:48 -05:00
public export
2023-03-04 23:56:35 -05:00
record Tagged {0 k : Type} (a : k) b where
2023-03-04 23:35:26 -05:00
constructor Tag
2023-03-06 16:44:26 -05:00
runTagged : b
2023-03-04 23:31:48 -05:00
2023-03-07 22:15:08 -05:00
||| Retag the value with a different type-level parameter.
2023-03-04 23:31:48 -05:00
public export
retag : Tagged a c -> Tagged b c
2023-03-04 23:35:26 -05:00
retag (Tag x) = Tag x
2023-03-04 23:31:48 -05:00
public export
2023-03-04 23:31:48 -05:00
Functor (Tagged a) where
2023-03-04 23:35:26 -05:00
map f (Tag x) = Tag (f x)
2023-03-04 23:31:48 -05:00
public export
2023-03-04 23:31:48 -05:00
Applicative (Tagged a) where
2023-03-04 23:35:26 -05:00
pure = Tag
Tag f <*> Tag x = Tag (f x)
2023-03-04 23:31:48 -05:00
public export
2023-03-04 23:31:48 -05:00
Monad (Tagged a) where
2023-03-06 16:44:26 -05:00
join = runTagged
2023-03-04 23:35:26 -05:00
Tag x >>= f = f x
2023-03-04 23:31:48 -05:00
public export
2023-03-04 23:31:48 -05:00
Foldable (Tagged a) where
2023-03-04 23:35:26 -05:00
foldr f x (Tag y) = f y x
foldl f x (Tag y) = f x y
2023-03-04 23:31:48 -05:00
null = const False
2023-03-04 23:35:26 -05:00
foldlM f x (Tag y) = f x y
toList (Tag x) = [x]
foldMap f (Tag x) = f x
2023-03-04 23:31:48 -05:00
public export
2023-03-04 23:31:48 -05:00
Traversable (Tagged a) where
2023-03-04 23:35:26 -05:00
traverse f (Tag x) = map Tag (f x)
2023-03-04 23:31:48 -05:00
public export
2023-03-04 23:31:48 -05:00
Profunctor Tagged where
2023-03-04 23:35:26 -05:00
dimap _ f (Tag x) = Tag (f x)
2023-03-04 23:31:48 -05:00
lmap = const retag
2023-03-04 23:35:26 -05:00
rmap f (Tag x) = Tag (f x)
||| `Forget r` is equivalent to `Star (Const r)`.
public export
record Forget {0 k : Type} r a (b : k) where
constructor MkForget
runForget : a -> r
public export
reforget : Forget r a b -> Forget r a c
reforget (MkForget k) = MkForget k
public export
Functor (Forget r a) where
map _ = reforget
public export
Contravariant (Forget {k=Type} r a) where
contramap _ = reforget
public export
Monoid r => Applicative (Forget r a) where
pure _ = MkForget (const neutral)
MkForget f <*> MkForget g = MkForget (f <+> g)
public export
Monoid r => Monad (Forget {k=Type} r a) where
join = reforget
(>>=) = reforget .: const
public export
Foldable (Forget r a) where
foldr _ x _ = x
foldl _ x _ = x
null = const True
foldlM _ x _ = pure x
toList _ = []
foldMap _ _ = neutral
public export
Traversable (Forget r a) where
traverse _ = pure . reforget
public export
Profunctor (Forget r) where
dimap f _ (MkForget k) = MkForget (k . f)
lmap f (MkForget k) = MkForget (k . f)
rmap = map
||| `Coforget r` is equivalent to `Costar (Const r)`.
public export
record Coforget {0 k : Type} r (a : k) b where
constructor MkCoforget
runCoforget : r -> b
public export
recoforget : Coforget r a c -> Coforget r b c
recoforget (MkCoforget k) = MkCoforget k
public export
Functor (Coforget r a) where
map f (MkCoforget k) = MkCoforget (f . k)
public export
Bifunctor (Coforget r) where
bimap _ f (MkCoforget k) = MkCoforget (f . k)
mapFst _ = recoforget
mapSnd = map
public export
Applicative (Coforget r a) where
pure = MkCoforget . const
MkCoforget f <*> MkCoforget g = MkCoforget (\r => f r (g r))
public export
Monad (Coforget r a) where
MkCoforget k >>= f = MkCoforget (\r => runCoforget (f $ k r) r)
public export
Profunctor (Coforget r) where
dimap _ f (MkCoforget k) = MkCoforget (f . k)
lmap _ = recoforget
rmap = map
------------------------------------------------------------------------------
-- Identity functor
------------------------------------------------------------------------------
-- A few convenience definitions for use in other modules.
public export
[FunctorId] Functor Prelude.id where
map = id
public export
[ApplicativeId] Applicative Prelude.id using FunctorId where
pure = id
(<*>) = id
public export
[MonadId] Monad Prelude.id using ApplicativeId where
join = id
(>>=) = flip id
public export
[FoldableId] Foldable Prelude.id where
foldr = flip
foldl = id
null _ = False
foldlM = id
toList = pure
foldMap = id
public export
[TraversableId] Traversable Prelude.id using FunctorId FoldableId where
traverse = id