Skip to content

Commit 163d2b5

Browse files
committed
Move Kleisli arrows to their own modules
1 parent 035f063 commit 163d2b5

File tree

6 files changed

+123
-71
lines changed

6 files changed

+123
-71
lines changed

linear-base.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ library
2525
Data.Functor.Linear
2626
Data.Vector.Linear
2727
Data.Profunctor.Linear
28+
Data.Profunctor.Kleisli.Linear
29+
Data.Profunctor.Kleisli.NonLinear
2830
Foreign.Marshal.Pure
2931
Prelude.Linear
3032
Prelude.Linear.Internal.Simple

src/Control/Optics/Linear/Internal.hs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import Data.Functor.Const
1414
import Data.Functor.Linear
1515
import Data.Monoid
1616
import Data.Profunctor.Linear
17+
import qualified Data.Profunctor.Kleisli.Linear as Linear
18+
import qualified Data.Profunctor.Kleisli.NonLinear as NonLinear
1719
import Data.Void
1820
import Prelude.Linear
1921
import qualified Prelude as P
@@ -68,51 +70,48 @@ traversed = Optical wander
6870
over :: Optic_ LinearArrow a b s t -> (a ->. b) -> s ->. t
6971
over (Optical l) f = getLA (l (LA f))
7072

71-
traverseOf :: Optic_ (LKleisli f) a b s t -> (a ->. f b) -> s ->. f t
72-
traverseOf (Optical l) f = runLKleisli (l (LKleisli f))
73+
traverseOf :: Optic_ (Linear.Kleisli f) a b s t -> (a ->. f b) -> s ->. f t
74+
traverseOf (Optical l) f = Linear.runKleisli (l (Linear.Kleisli f))
7375

74-
get :: Optic_ (Kleisli (Const a)) a b s t -> s -> a
76+
get :: Optic_ (NonLinear.Kleisli (Const a)) a b s t -> s -> a
7577
get l = gets l P.id
7678

77-
gets :: Optic_ (Kleisli (Const r)) a b s t -> (a -> r) -> s -> r
78-
gets (Optical l) f s = getConst' (runKleisli (l (Kleisli (Const P.. f))) s)
79+
gets :: Optic_ (NonLinear.Kleisli (Const r)) a b s t -> (a -> r) -> s -> r
80+
gets (Optical l) f s = getConst' (NonLinear.runKleisli (l (NonLinear.Kleisli (Const P.. f))) s)
7981

8082
set :: Optic_ (->) a b s t -> b -> s -> t
8183
set (Optical l) x = l (const x)
8284

83-
-- get can't return a linear arrow, so `withIso swap const` needs to be used
84-
-- instead of `get swap`
85-
match :: Optic_ (LKleisli (Either a)) a b s t -> s ->. Either t a
86-
match (Optical l) = withIso swap (\x _ -> x) . runLKleisli (l (LKleisli Left))
85+
match :: Optic_ (Linear.Kleisli (Either a)) a b s t -> s ->. Either t a
86+
match (Optical l) = withIso swap (\x _ -> x) . Linear.runKleisli (l (Linear.Kleisli Left))
8787

8888
-- will be redundant with multiplicity polymorphism
89-
match' :: Optic_ (Kleisli (Either a)) a b s t -> s -> Either t a
90-
match' (Optical l) = get swap P.. runKleisli (l (Kleisli Left))
89+
match' :: Optic_ (NonLinear.Kleisli (Either a)) a b s t -> s -> Either t a
90+
match' (Optical l) = withIso swap (\x _ -> forget x) P.. NonLinear.runKleisli (l (NonLinear.Kleisli Left))
9191

92-
build :: Optic_ (CoLKleisli (Const b)) a b s t -> b ->. t
93-
build (Optical l) x = runCoLKleisli (l (CoLKleisli getConst')) (Const x)
92+
build :: Optic_ (Linear.CoKleisli (Const b)) a b s t -> b ->. t
93+
build (Optical l) x = Linear.runCoKleisli (l (Linear.CoKleisli getConst')) (Const x)
9494

9595
-- XXX: move this to Prelude
9696
-- | Linearly typed patch for the newtype deconstructor. (Temporary until
9797
-- inference will get this from the newtype declaration.)
9898
getConst' :: Const a b ->. a
9999
getConst' (Const x) = x
100100

101-
lengthOf :: Num r => Optic_ (Kleisli (Const (Sum r))) a b s t -> s -> r
101+
lengthOf :: Num r => Optic_ (NonLinear.Kleisli (Const (Sum r))) a b s t -> s -> r
102102
lengthOf l s = getSum (gets l (const (Sum 1)) s)
103103

104104
-- XXX: the below two functions will be made redundant with multiplicity
105105
-- polymorphism on over and traverseOf'
106106
over' :: Optic_ (->) a b s t -> (a -> b) -> s -> t
107107
over' (Optical l) f = l f
108108

109-
traverseOf' :: Optic_ (Kleisli f) a b s t -> (a -> f b) -> s -> f t
110-
traverseOf' (Optical l) f = runKleisli (l (Kleisli f))
109+
traverseOf' :: Optic_ (NonLinear.Kleisli f) a b s t -> (a -> f b) -> s -> f t
110+
traverseOf' (Optical l) f = NonLinear.runKleisli (l (NonLinear.Kleisli f))
111111

112112
iso :: (s ->. a) -> (b ->. t) -> Iso a b s t
113113
iso f g = Optical (dimap f g)
114114

115115
withIso :: Optic_ (Exchange a b) a b s t -> ((s ->. a) -> (b ->. t) -> r) -> r
116116
withIso (Optical l) f = f fro to
117117
where Exchange fro to = l (Exchange id id)
118-
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{-# LANGUAGE FlexibleInstances #-}
2+
{-# LANGUAGE LinearTypes #-}
3+
{-# LANGUAGE MultiParamTypeClasses #-}
4+
{-# LANGUAGE NoImplicitPrelude #-}
5+
{-# LANGUAGE TupleSections #-}
6+
module Data.Profunctor.Kleisli.Linear
7+
( Kleisli(..)
8+
, CoKleisli(..)
9+
)
10+
where
11+
12+
-- | This module is intended to be imported qualified
13+
14+
import Data.Functor.Const
15+
import Data.Profunctor.Linear
16+
import Data.Void
17+
import Prelude.Linear (Either(..), either)
18+
import Prelude.Linear.Internal.Simple
19+
import qualified Control.Monad.Linear as Control
20+
import qualified Data.Functor.Linear as Data
21+
22+
-- Ideally, there would only be one Kleisli arrow, parametrised by
23+
-- a multiplicity parameter:
24+
-- newtype Kleisli p m a b = Kleisli { runKleisli :: a # p -> m b }
25+
--
26+
-- Some instances would also still work, eg
27+
-- instance Functor p f => Profunctor (Kleisli p f)
28+
29+
-- | Linear Kleisli arrows for the monad `m`. These arrows are still useful
30+
-- in the case where `m` is not a monad however, and some profunctorial
31+
-- properties still hold in this weaker setting.
32+
newtype Kleisli m a b = Kleisli { runKleisli :: a ->. m b }
33+
34+
instance Data.Functor f => Profunctor (Kleisli f) where
35+
dimap f g (Kleisli h) = Kleisli (Data.fmap g . h . f)
36+
37+
instance Control.Functor f => Strong (,) () (Kleisli f) where
38+
first (Kleisli f) = Kleisli (\(a,b) -> (,b) Control.<$> f a)
39+
second (Kleisli g) = Kleisli (\(a,b) -> (a,) Control.<$> g b)
40+
41+
instance Control.Applicative f => Strong Either Void (Kleisli f) where
42+
first (Kleisli f) = Kleisli (either (Data.fmap Left . f) (Control.pure . Right))
43+
second (Kleisli g) = Kleisli (either (Control.pure . Left) (Data.fmap Right . g))
44+
45+
instance Control.Applicative f => Wandering (Kleisli f) where
46+
wander (Kleisli f) = Kleisli (Data.traverse f)
47+
48+
-- | Linear co-Kleisli arrows for the comonad `w`. These arrows are still
49+
-- useful in the case where `w` is not a comonad however, and some
50+
-- profunctorial properties still hold in this weaker setting.
51+
-- However stronger requirements on `f` are needed for profunctorial
52+
-- strength, so we have fewer instances.
53+
--
54+
-- Category theoretic remark: duality doesn't work in the obvious way, since
55+
-- (,) isn't the categorical product. Instead, we have a product (&), called
56+
-- "With", defined by
57+
-- > type With a b = forall r. Either (a ->. r) (b ->. r) ->. r
58+
-- which satisfies the universal property of the product of `a` and `b`.
59+
-- CoKleisli arrows are strong with respect to this monoidal structure,
60+
-- although this might not be useful...
61+
newtype CoKleisli w a b = CoKleisli { runCoKleisli :: w a ->. b }
62+
63+
instance Data.Functor f => Profunctor (CoKleisli f) where
64+
dimap f g (CoKleisli h) = CoKleisli (g . h . Data.fmap f)
65+
66+
-- instance of a more general idea, but this will do for now
67+
instance Strong Either Void (CoKleisli (Const x)) where
68+
first (CoKleisli f) = CoKleisli (\(Const x) -> Left (f (Const x)))
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{-# LANGUAGE FlexibleInstances #-}
2+
{-# LANGUAGE LambdaCase #-}
3+
{-# LANGUAGE LinearTypes #-}
4+
{-# LANGUAGE MultiParamTypeClasses #-}
5+
{-# LANGUAGE NoImplicitPrelude #-}
6+
{-# LANGUAGE TupleSections #-}
7+
8+
module Data.Profunctor.Kleisli.NonLinear
9+
( Kleisli(..)
10+
)
11+
where
12+
13+
import Data.Profunctor.Linear
14+
import Data.Void
15+
import qualified Prelude
16+
import Prelude.Linear (Either(..), forget)
17+
import Prelude.Linear.Internal.Simple (($))
18+
19+
-- Non-linear Kleisli arrows for the monad `m`. As in the linear case,
20+
-- these arrows are still useful if `m` is only a `Functor` or an
21+
-- `Applicative`.
22+
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
23+
24+
instance Prelude.Functor f => Profunctor (Kleisli f) where
25+
dimap f g (Kleisli h) = Kleisli (\x -> forget g Prelude.<$> h (f x))
26+
27+
instance Prelude.Functor f => Strong (,) () (Kleisli f) where
28+
first (Kleisli f) = Kleisli (\(a,b) -> (,b) Prelude.<$> f a)
29+
second (Kleisli g) = Kleisli (\(a,b) -> (a,) Prelude.<$> g b)
30+
31+
instance Prelude.Applicative f => Strong Either Void (Kleisli f) where
32+
first (Kleisli f) = Kleisli $ \case
33+
Left x -> Prelude.fmap Left (f x)
34+
Right y -> Prelude.pure (Right y)

src/Data/Profunctor/Linear.hs

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
{-# LANGUAGE FlexibleContexts #-}
2-
{-# LANGUAGE FlexibleInstances #-}
32
{-# LANGUAGE KindSignatures #-}
4-
{-# LANGUAGE LambdaCase #-}
53
{-# LANGUAGE LinearTypes #-}
64
{-# LANGUAGE MultiParamTypeClasses #-}
75
{-# LANGUAGE NoImplicitPrelude #-}
@@ -14,19 +12,13 @@ module Data.Profunctor.Linear
1412
, Strong(..)
1513
, Wandering(..)
1614
, LinearArrow(..), getLA
17-
, Kleisli(..)
18-
, LKleisli(..)
19-
, CoLKleisli(..)
2015
, Exchange(..)
2116
) where
2217

23-
import qualified Control.Monad.Linear as Control
2418
import qualified Data.Functor.Linear as Data
2519
import Data.Bifunctor.Linear hiding (first, second)
26-
import Data.Functor.Const
2720
import Prelude.Linear
2821
import Data.Void
29-
import qualified Prelude
3022

3123
-- TODO: write laws
3224

@@ -69,7 +61,6 @@ class (Strong (,) () arr, Strong Either Void arr) => Wandering arr where
6961

7062
newtype LinearArrow a b = LA (a ->. b)
7163
-- | Temporary deconstructor since inference doesn't get it right
72-
-- TODO: maybe use TH to automatically write things like this?
7364
getLA :: LinearArrow a b ->. a ->. b
7465
getLA (LA f) = f
7566

@@ -84,37 +75,6 @@ instance Strong Either Void LinearArrow where
8475
first (LA f) = LA $ either (Left . f) Right
8576
second (LA g) = LA $ either Left (Right . g)
8677

87-
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
88-
89-
instance Prelude.Functor f => Profunctor (Kleisli f) where
90-
dimap f g (Kleisli h) = Kleisli (\x -> forget g Prelude.<$> h (f x))
91-
92-
instance Prelude.Functor f => Strong (,) () (Kleisli f) where
93-
first (Kleisli f) = Kleisli (\(a,b) -> (,b) Prelude.<$> f a)
94-
second (Kleisli g) = Kleisli (\(a,b) -> (a,) Prelude.<$> g b)
95-
96-
instance Prelude.Applicative f => Strong Either Void (Kleisli f) where
97-
first (Kleisli f) = Kleisli $ \case
98-
Left x -> Prelude.fmap Left (f x)
99-
Right y -> Prelude.pure (Right y)
100-
101-
102-
newtype LKleisli m a b = LKleisli { runLKleisli :: a ->. m b }
103-
104-
instance Data.Functor f => Profunctor (LKleisli f) where
105-
dimap f g (LKleisli h) = LKleisli (Data.fmap g . h . f)
106-
107-
instance Control.Functor f => Strong (,) () (LKleisli f) where
108-
first (LKleisli f) = LKleisli (\(a,b) -> (,b) Control.<$> f a)
109-
second (LKleisli g) = LKleisli (\(a,b) -> (a,) Control.<$> g b)
110-
111-
instance Control.Applicative f => Strong Either Void (LKleisli f) where
112-
first (LKleisli f) = LKleisli (either (Data.fmap Left . f) (Control.pure . Right))
113-
second (LKleisli g) = LKleisli (either (Control.pure . Left) (Data.fmap Right . g))
114-
115-
instance Control.Applicative f => Wandering (LKleisli f) where
116-
wander (LKleisli f) = LKleisli (Data.traverse f)
117-
11878
instance Profunctor (->) where
11979
dimap f g h x = g (h (f x))
12080
instance Strong (,) () (->) where
@@ -123,19 +83,6 @@ instance Strong Either Void (->) where
12383
first f (Left x) = Left (f x)
12484
first _ (Right y) = Right y
12585

126-
-- XXX: Since CoLKleisli has uses, it might be better to replace all this
127-
-- with a Bif-like structure...
128-
--
129-
newtype CoLKleisli w a b = CoLKleisli { runCoLKleisli :: w a ->. b }
130-
131-
instance Data.Functor f => Profunctor (CoLKleisli f) where
132-
dimap f g (CoLKleisli h) = CoLKleisli (g . h . Data.fmap f)
133-
134-
-- instance of a more general idea, but this will do for now
135-
instance Strong Either Void (CoLKleisli (Const x)) where
136-
first (CoLKleisli f) = CoLKleisli (\(Const x) -> Left (f (Const x)))
137-
13886
data Exchange a b s t = Exchange (s ->. a) (b ->. t)
13987
instance Profunctor (Exchange a b) where
14088
dimap f g (Exchange p q) = Exchange (p . f) (g . q)
141-

src/Prelude/Linear.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ maybe :: b -> (a ->. b) -> Maybe a ->. b
7272
maybe x _ Nothing = x
7373
maybe _ f (Just y) = f y
7474

75-
-- XXX: temporary
75+
-- XXX: temporary: with multiplicity polymorphism functions expecting a
76+
-- non-linear arrow would allow a linear arrow passed, so this would be
77+
-- redundant
7678
-- | Convenience operator when a higher-order function expects a non-linear
7779
-- arrow but we have a linear arrow
7880
forget :: (a ->. b) ->. a -> b

0 commit comments

Comments
 (0)