Skip to content

Commit 93c9c82

Browse files
committed
A plethora of optics
1 parent c02e5d2 commit 93c9c82

File tree

3 files changed

+118
-13
lines changed

3 files changed

+118
-13
lines changed

src/Control/Optics/Linear/Internal.hs

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,49 @@ module Control.Optics.Linear.Internal
1313
, Iso, Iso'
1414
, Lens, Lens'
1515
, Prism, Prism'
16-
, Traversal, Traversal'
16+
, PTraversal, PTraversal'
17+
, DTraversal, DTraversal'
1718
-- * Composing optics
1819
, (.>)
1920
-- * Common optics
2021
, swap, assoc
2122
, _1, _2
2223
, _Left, _Right
2324
, _Just, _Nothing
24-
, traversed
25+
, ptraversed, dtraversed
26+
, both, both'
27+
, get', gets', set'
2528
-- * Using optics
2629
, get, set, gets
2730
, match, match', build
31+
, preview
2832
, over, over'
2933
, traverseOf, traverseOf'
3034
, lengthOf
3135
, withIso
36+
, toListOf
3237
-- * Constructing optics
33-
, iso, prism
38+
, iso, prism, lens
3439
)
3540
where
3641

3742
import qualified Control.Arrow as NonLinear
3843
import qualified Data.Bifunctor.Linear as Bifunctor
3944
import Data.Bifunctor.Linear (SymmetricMonoidal)
4045
import Data.Monoid
46+
import Data.Functor.Const
47+
import Data.Functor.Linear
4148
import Data.Profunctor.Linear
4249
import Data.Functor.Linear
4350
import qualified Data.Profunctor.Kleisli.Linear as Linear
4451
import Data.Void
45-
import Prelude.Linear
52+
import Prelude.Linear hiding ((<$>))
53+
-- ^ XXX: not entirely sure why the hiding is necessary here...
4654
import qualified Prelude as P
4755

56+
-- TODO: documentation in this module
57+
-- Put the functions in some sensible order: possibly split into separate
58+
-- Lens/Prism/Traversal/Iso modules
4859
newtype Optic_ arr a b s t = Optical (a `arr` b -> s `arr` t)
4960

5061
type Optic c a b s t =
@@ -56,8 +67,12 @@ type Lens a b s t = Optic (Strong (,) ()) a b s t
5667
type Lens' a s = Lens a a s s
5768
type Prism a b s t = Optic (Strong Either Void) a b s t
5869
type Prism' a s = Prism a a s s
59-
type Traversal a b s t = Optic Wandering a b s t
60-
type Traversal' a s = Traversal a a s s
70+
type PTraversal a b s t = Optic PWandering a b s t
71+
type PTraversal' a s = PTraversal a a s s
72+
type DTraversal a b s t = Optic DWandering a b s t
73+
type DTraversal' a s = DTraversal a a s s
74+
-- XXX: these will unify into
75+
-- type Traversal (p :: Multiplicity) a b s t = Optic (Wandering p) a b s t
6176

6277
swap :: SymmetricMonoidal m u => Iso (a `m` b) (c `m` d) (b `m` a) (d `m` c)
6378
swap = iso Bifunctor.swap Bifunctor.swap
@@ -68,6 +83,10 @@ assoc = iso Bifunctor.lassoc Bifunctor.rassoc
6883
(.>) :: Optic_ arr a b s t -> Optic_ arr x y a b -> Optic_ arr x y s t
6984
Optical f .> Optical g = Optical (f P.. g)
7085

86+
-- c is the complement (probably)
87+
lens :: (s ->. (c,a)) -> ((c,b) ->. t) -> Lens a b s t
88+
lens sca cbt = Optical $ \f -> dimap sca cbt (second f)
89+
7190
prism :: (b ->. t) -> (s ->. Either t a) -> Prism a b s t
7291
prism b s = Optical $ \f -> dimap s (either id id) (second (rmap b f))
7392

@@ -77,6 +96,37 @@ _1 = Optical first
7796
_2 :: Lens a b (c,a) (c,b)
7897
_2 = Optical second
7998

99+
-- XXX: these will unify to
100+
-- > both :: forall (p :: Multiplicity). Traversal p a b (a,a) (b,b)
101+
both' :: PTraversal a b (a,a) (b,b)
102+
both' = _Pairing .> ptraversed
103+
104+
both :: DTraversal a b (a,a) (b,b)
105+
both = _Pairing .> dtraversed
106+
107+
-- XXX: these are a special case of Bitraversable, but just the simple case
108+
-- is included here for now
109+
_Pairing :: Iso (Pair a) (Pair b) (a,a) (b,b)
110+
_Pairing = iso Paired unpair
111+
112+
newtype Pair a = Paired (a,a)
113+
unpair :: Pair a ->. (a,a)
114+
unpair (Paired x) = x
115+
116+
instance P.Functor Pair where
117+
fmap f (Paired (x,y)) = Paired (f x, f y)
118+
instance Functor Pair where
119+
fmap f (Paired (x,y)) = Paired (f x, f y)
120+
instance Foldable Pair where
121+
foldMap f (Paired (x,y)) = f x P.<> f y
122+
instance P.Traversable Pair where
123+
traverse f (Paired (x,y)) = Paired P.<$> ((,) P.<$> f x P.<*> f y)
124+
instance Traversable Pair where
125+
traverse f (Paired (x,y)) = Paired <$> ((,) <$> f x <*> f y)
126+
127+
toListOf :: Optic_ (NonLinear.Kleisli (Const [a])) a b s t -> s -> [a]
128+
toListOf l = gets l (\a -> [a])
129+
80130
_Left :: Prism a b (Either a c) (Either b c)
81131
_Left = Optical first
82132

@@ -89,8 +139,11 @@ _Just = prism Just (maybe (Left Nothing) Right)
89139
_Nothing :: Prism' () (Maybe a)
90140
_Nothing = prism (\() -> Nothing) Left
91141

92-
traversed :: Traversable t => Traversal a b (t a) (t b)
93-
traversed = Optical wander
142+
ptraversed :: P.Traversable t => PTraversal a b (t a) (t b)
143+
ptraversed = Optical pwander
144+
145+
dtraversed :: Traversable t => DTraversal a b (t a) (t b)
146+
dtraversed = Optical dwander
94147

95148
over :: Optic_ LinearArrow a b s t -> (a ->. b) -> s ->. t
96149
over (Optical l) f = getLA (l (LA f))
@@ -104,6 +157,18 @@ get l = gets l P.id
104157
gets :: Optic_ (NonLinear.Kleisli (Const r)) a b s t -> (a -> r) -> s -> r
105158
gets (Optical l) f s = getConst' (NonLinear.runKleisli (l (NonLinear.Kleisli (Const P.. f))) s)
106159

160+
preview :: Optic_ (NonLinear.Kleisli (Const (Maybe (First a)))) a b s t -> s -> Maybe a
161+
preview (Optical l) s = getFirst P.<$> (getConst (NonLinear.runKleisli (l (NonLinear.Kleisli (\a -> Const (Just (First a))))) s))
162+
163+
get' :: Optic_ (Linear.Kleisli (Const (Top, a))) a b s t -> s ->. (Top, a)
164+
get' l = gets' l id
165+
166+
gets' :: Optic_ (Linear.Kleisli (Const (Top, r))) a b s t -> (a ->. r) -> s ->. (Top, r)
167+
gets' (Optical l) f s = getConst' (Linear.runKleisli (l (Linear.Kleisli (\a -> Const (mempty, f a)))) s)
168+
169+
set' :: Optic_ (Linear.Kleisli (MyFunctor a b)) a b s t -> s ->. b ->. (a, t)
170+
set' (Optical l) = runMyFunctor . Linear.runKleisli (l (Linear.Kleisli (\a -> MyFunctor (\b -> (a,b)))))
171+
107172
set :: Optic_ (->) a b s t -> b -> s -> t
108173
set (Optical l) x = l (const x)
109174

src/Data/Profunctor/Kleisli/Linear.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ instance Control.Applicative f => Strong Either Void (Kleisli f) where
4141
first (Kleisli f) = Kleisli (either (Data.fmap Left . f) (Control.pure . Right))
4242
second (Kleisli g) = Kleisli (either (Control.pure . Left) (Data.fmap Right . g))
4343

44-
instance Control.Applicative f => Wandering (Kleisli f) where
45-
wander (Kleisli f) = Kleisli (Data.traverse f)
44+
instance Control.Applicative f => DWandering (Kleisli f) where
45+
dwander (Kleisli f) = Kleisli (Data.traverse f)
4646

4747
-- | Linear co-Kleisli arrows for the comonad `w`. These arrows are still
4848
-- useful in the case where `w` is not a comonad however, and some

src/Data/Profunctor/Linear.hs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,38 @@
1+
{-# LANGUAGE GADTs #-}
12
{-# LANGUAGE FlexibleContexts #-}
3+
{-# LANGUAGE FlexibleInstances #-}
24
{-# LANGUAGE KindSignatures #-}
35
{-# LANGUAGE LambdaCase #-}
46
{-# LANGUAGE LinearTypes #-}
57
{-# LANGUAGE MultiParamTypeClasses #-}
68
{-# LANGUAGE NoImplicitPrelude #-}
9+
{-# LANGUAGE RankNTypes #-}
710
{-# LANGUAGE TupleSections #-}
811
{-# LANGUAGE TypeOperators #-}
912

13+
{-# OPTIONS_GHC -fno-warn-orphans #-}
14+
1015
module Data.Profunctor.Linear
1116
( Profunctor(..)
1217
, Monoidal(..)
1318
, Strong(..)
14-
, Wandering(..)
19+
, PWandering(..)
20+
, DWandering(..)
1521
, LinearArrow(..), getLA
1622
, Exchange(..)
23+
, Top
24+
, MyFunctor(..), runMyFunctor
1725
) where
1826

1927
import qualified Data.Functor.Linear as Data
28+
import qualified Control.Monad.Linear as Control
2029
import Data.Bifunctor.Linear hiding (first, second)
2130
import Prelude.Linear
2231
import Data.Void
2332
import qualified Prelude
2433
import Control.Arrow (Kleisli(..))
34+
import Data.Monoid.Linear
35+
import Data.Functor.Const
2536

2637
-- TODO: write laws
2738

@@ -55,8 +66,17 @@ class (SymmetricMonoidal m u, Profunctor arr) => Strong m u arr where
5566
second arr = dimap swap swap (first arr)
5667
{-# INLINE second #-}
5768

58-
class (Strong (,) () arr, Strong Either Void arr) => Wandering arr where
59-
wander :: Data.Traversable f => a `arr` b -> f a `arr` f b
69+
-- XXX: Just as Prelude.Functor/Data.Functor will combine into
70+
-- > `class Functor (p :: Multiplicity) f`
71+
-- so will Traversable, and then we would instead write
72+
-- > class (...) => Wandering (p :: Multiplicity) arr where
73+
-- > wander :: Traversable p f => a `arr` b -> f a `arr` f b
74+
-- For now, however, we cannot do this, so we use two classes instead:
75+
-- PreludeWandering and DataWandering
76+
class (Strong (,) () arr, Strong Either Void arr) => PWandering arr where
77+
pwander :: Prelude.Traversable f => a `arr` b -> f a `arr` f b
78+
class (Strong (,) () arr, Strong Either Void arr) => DWandering arr where
79+
dwander :: Data.Traversable f => a `arr` b -> f a `arr` f b
6080

6181
---------------
6282
-- Instances --
@@ -85,6 +105,8 @@ instance Strong (,) () (->) where
85105
instance Strong Either Void (->) where
86106
first f (Left x) = Left (f x)
87107
first _ (Right y) = Right y
108+
instance PWandering (->) where
109+
pwander = Prelude.fmap
88110

89111
data Exchange a b s t = Exchange (s ->. a) (b ->. t)
90112
instance Profunctor (Exchange a b) where
@@ -101,3 +123,21 @@ instance Prelude.Applicative f => Strong Either Void (Kleisli f) where
101123
first (Kleisli f) = Kleisli $ \case
102124
Left x -> Prelude.fmap Left (f x)
103125
Right y -> Prelude.pure (Right y)
126+
127+
instance Control.Functor (Const (Top, a)) where
128+
fmap f (Const (t, x)) = Const (throw f <> t, x)
129+
instance Monoid a => Control.Applicative (Const (Top, a)) where
130+
pure x = Const (throw x, mempty)
131+
Const x <*> Const y = Const (x <> y)
132+
133+
-- TODO: pick a more sensible name for this
134+
newtype MyFunctor a b t = MyFunctor (b ->. (a, t))
135+
runMyFunctor :: MyFunctor a b t ->. b ->. (a, t)
136+
runMyFunctor (MyFunctor f) = f
137+
138+
instance Data.Functor (MyFunctor a b) where
139+
fmap f (MyFunctor g) = MyFunctor (getLA (second (LA f)) . g)
140+
instance Control.Functor (MyFunctor a b) where
141+
fmap f (MyFunctor g) = MyFunctor (thing f . g)
142+
where thing :: (c ->. d) ->. (e, c) ->. (e, d)
143+
thing k (x,y) = (x, k y)

0 commit comments

Comments
 (0)