Skip to content

Commit 82a2339

Browse files
Port Clown, Joker, Product (Product2), Costar from bifunctors/profunctor (#27)
* Update CI to v0.14.0-rc5 * Port Clown, Joker, and Product2 newtypes from purescript-bifunctors and purescript-profunctor to this repo and merge them * Port Costar newtypes from purescript-profunctor to this repo * Add FunctorRight and implement its instances * Update docs for Clown and Joker to refer to paper * Added docs to the newtypes that were ported
1 parent b5f6837 commit 82a2339

File tree

6 files changed

+159
-0
lines changed

6 files changed

+159
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ Notable changes to this project are documented in this file. The format is based
66

77
Breaking changes:
88
- Added support for PureScript 0.14 and dropped support for all previous versions (#24)
9+
- Ported `Clown`, `Joker`, and `Product` (named `Product2` here) from `purescript-bifunctors`/`purescript-profunctor` to this repo (#27)
10+
- Ported `purescript-profunctor`'s `Costar` to this repo (#27)
911

1012
New features:
13+
- Added `FunctorRight` type class (#27)
1114

1215
Bugfixes:
1316

src/Data/Functor/Clown.purs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
module Data.Functor.Clown where
2+
3+
import Prelude
4+
5+
import Data.Functor.FunctorRight (class FunctorRight)
6+
import Data.Newtype (class Newtype)
7+
8+
-- | This advance type's usage and its relation to `Joker` is best understood
9+
-- | by reading through "Clowns to the Left, Jokers to the Right (Functional
10+
-- | Pearl)"
11+
-- | https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.475.6134&rep=rep1&type=pdf
12+
newtype Clown :: (Type -> Type) -> Type -> Type -> Type
13+
newtype Clown f a b = Clown (f a)
14+
15+
derive instance newtypeClown :: Newtype (Clown f a b) _
16+
17+
derive newtype instance eqClown :: Eq (f a) => Eq (Clown f a b)
18+
19+
derive newtype instance ordClown :: Ord (f a) => Ord (Clown f a b)
20+
21+
instance showClown :: Show (f a) => Show (Clown f a b) where
22+
show (Clown x) = "(Clown " <> show x <> ")"
23+
24+
instance functorClown :: Functor (Clown f a) where
25+
map _ (Clown a) = Clown a
26+
27+
instance functorRightClown :: FunctorRight (Clown f) where
28+
rmap = map
29+
30+
hoistClown :: forall f g a b. (f ~> g) -> Clown f a b -> Clown g a b
31+
hoistClown f (Clown a) = Clown (f a)

src/Data/Functor/Costar.purs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
module Data.Functor.Costar where
2+
3+
import Prelude
4+
5+
import Control.Comonad (class Comonad, extract)
6+
import Control.Extend (class Extend, (=<=))
7+
8+
import Data.Distributive (class Distributive, distribute)
9+
import Data.Functor.Invariant (class Invariant, imapF)
10+
import Data.Functor.FunctorRight (class FunctorRight)
11+
import Data.Newtype (class Newtype)
12+
13+
-- | `Costar` turns a `Functor` into a `Profunctor` "backwards".
14+
-- |
15+
-- | `Costar f` is also the co-Kleisli category for `f`.
16+
newtype Costar :: (Type -> Type) -> Type -> Type -> Type
17+
newtype Costar f b a = Costar (f b -> a)
18+
19+
derive instance newtypeCostar :: Newtype (Costar f a b) _
20+
21+
instance semigroupoidCostar :: Extend f => Semigroupoid (Costar f) where
22+
compose (Costar f) (Costar g) = Costar (f =<= g)
23+
24+
instance categoryCostar :: Comonad f => Category (Costar f) where
25+
identity = Costar extract
26+
27+
instance functorCostar :: Functor (Costar f a) where
28+
map f (Costar g) = Costar (f <<< g)
29+
30+
instance functorRightCostar :: FunctorRight (Costar f) where
31+
rmap = map
32+
33+
instance invariantCostar :: Invariant (Costar f a) where
34+
imap = imapF
35+
36+
instance applyCostar :: Apply (Costar f a) where
37+
apply (Costar f) (Costar g) = Costar \a -> f a (g a)
38+
39+
instance applicativeCostar :: Applicative (Costar f a) where
40+
pure a = Costar \_ -> a
41+
42+
instance bindCostar :: Bind (Costar f a) where
43+
bind (Costar m) f = Costar \x -> case f (m x) of Costar g -> g x
44+
45+
instance monadCostar :: Monad (Costar f a)
46+
47+
instance distributiveCostar :: Distributive (Costar f a) where
48+
distribute f = Costar \a -> map (\(Costar g) -> g a) f
49+
collect f = distribute <<< map f

src/Data/Functor/FunctorRight.purs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module Data.Functor.FunctorRight where
2+
3+
-- | Same as `Functor` but works on types that take two type parameters
4+
-- | instead of just one.
5+
class FunctorRight :: (Type -> Type -> Type) -> Constraint
6+
class FunctorRight f where
7+
rmap :: forall a b c. (b -> c) -> f a b -> f a c

src/Data/Functor/Joker.purs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module Data.Functor.Joker where
2+
3+
import Prelude
4+
5+
import Data.Functor.FunctorRight (class FunctorRight)
6+
import Data.Newtype (class Newtype, un)
7+
8+
-- | This advance type's usage and its relation to `Clown` is best understood
9+
-- | by reading through "Clowns to the Left, Jokers to the Right (Functional
10+
-- | Pearl)"
11+
-- | https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.475.6134&rep=rep1&type=pdf
12+
newtype Joker :: (Type -> Type) -> Type -> Type -> Type
13+
newtype Joker g a b = Joker (g b)
14+
15+
derive instance newtypeJoker :: Newtype (Joker f a b) _
16+
17+
derive newtype instance eqJoker :: Eq (f b) => Eq (Joker f a b)
18+
19+
derive newtype instance ordJoker :: Ord (f b) => Ord (Joker f a b)
20+
21+
instance showJoker :: Show (f b) => Show (Joker f a b) where
22+
show (Joker x) = "(Joker " <> show x <> ")"
23+
24+
instance functorJoker :: Functor f => Functor (Joker f a) where
25+
map f (Joker a) = Joker (map f a)
26+
27+
instance functorRightJoker :: Functor f => FunctorRight (Joker f) where
28+
rmap = map
29+
30+
instance applyJoker :: Apply f => Apply (Joker f a) where
31+
apply (Joker f) (Joker g) = Joker $ apply f g
32+
33+
instance applicativeJoker :: Applicative f => Applicative (Joker f a) where
34+
pure = Joker <<< pure
35+
36+
instance bindJoker :: Bind f => Bind (Joker f a) where
37+
bind (Joker ma) amb = Joker $ ma >>= (amb >>> un Joker)
38+
39+
instance monadJoker :: Monad m => Monad (Joker m a)
40+
41+
hoistJoker :: forall f g a b. (f ~> g) -> Joker f a b -> Joker g a b
42+
hoistJoker f (Joker a) = Joker (f a)

src/Data/Functor/Product2.purs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module Data.Functor.Product2 where
2+
3+
import Prelude
4+
import Data.Functor.FunctorRight (class FunctorRight, rmap)
5+
6+
-- | The Product of two types that both take two type parameters (e.g. `Either`,
7+
-- | `Tuple, etc.) where both type parameters are the same.
8+
-- |
9+
-- | ```purescript
10+
-- | Product2 (Tuple 4 true) (Right false) :: Product2 Tuple Either Int Boolean
11+
-- | Product2 (Tuple 4 true) (Left 8) :: Product2 Tuple Either Int Boolean
12+
-- | ```
13+
data Product2 :: (Type -> Type -> Type) -> (Type -> Type -> Type) -> Type -> Type -> Type
14+
data Product2 f g a b = Product2 (f a b) (g a b)
15+
16+
derive instance eqProduct2 :: (Eq (f a b), Eq (g a b)) => Eq (Product2 f g a b)
17+
18+
derive instance ordProduct2 :: (Ord (f a b), Ord (g a b)) => Ord (Product2 f g a b)
19+
20+
instance showProduct2 :: (Show (f a b), Show (g a b)) => Show (Product2 f g a b) where
21+
show (Product2 x y) = "(Product2 " <> show x <> " " <> show y <> ")"
22+
23+
instance functorProduct2 :: (Functor (f a), Functor (g a)) => Functor (Product2 f g a) where
24+
map f (Product2 x y) = Product2 (map f x) (map f y)
25+
26+
instance functorRight :: (FunctorRight f, FunctorRight g) => FunctorRight (Product2 f g) where
27+
rmap f (Product2 x y) = Product2 (rmap f x) (rmap f y)

0 commit comments

Comments
 (0)