Skip to content

Commit 035f063

Browse files
committed
Add more basic prisms and isos and match/build
1 parent 79b456e commit 035f063

File tree

4 files changed

+76
-7
lines changed

4 files changed

+76
-7
lines changed

src/Control/Optics/Linear/Internal.hs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,17 @@ type Traversal a b s t = Optic Wandering a b s t
3333
type Traversal' a s = Traversal a a s s
3434

3535
swap :: SymmetricMonoidal m u => Iso (a `m` b) (c `m` d) (b `m` a) (d `m` c)
36-
swap = Optical (dimap Bifunctor.swap Bifunctor.swap)
36+
swap = iso Bifunctor.swap Bifunctor.swap
3737

3838
assoc :: SymmetricMonoidal m u => Iso ((a `m` b) `m` c) ((d `m` e) `m` f) (a `m` (b `m` c)) (d `m` (e `m` f))
39-
assoc = Optical (dimap Bifunctor.lassoc Bifunctor.rassoc)
39+
assoc = iso Bifunctor.lassoc Bifunctor.rassoc
4040

4141
(.>) :: Optic_ arr a b s t -> Optic_ arr x y a b -> Optic_ arr x y s t
4242
Optical f .> Optical g = Optical (f P.. g)
4343

44+
prism :: (b ->. t) -> (s ->. Either t a) -> Prism a b s t
45+
prism b s = Optical $ \f -> dimap s (either id id) (second (rmap b f))
46+
4447
_1 :: Lens a b (a,c) (b,c)
4548
_1 = Optical first
4649

@@ -53,6 +56,12 @@ _Left = Optical first
5356
_Right :: Prism a b (Either c a) (Either c b)
5457
_Right = Optical second
5558

59+
_Just :: Prism a b (Maybe a) (Maybe b)
60+
_Just = prism Just (maybe (Left Nothing) Right)
61+
62+
_Nothing :: Prism' () (Maybe a)
63+
_Nothing = prism (\() -> Nothing) Left
64+
5665
traversed :: Traversable t => Traversal a b (t a) (t b)
5766
traversed = Optical wander
5867

@@ -66,11 +75,29 @@ get :: Optic_ (Kleisli (Const a)) a b s t -> s -> a
6675
get l = gets l P.id
6776

6877
gets :: Optic_ (Kleisli (Const r)) a b s t -> (a -> r) -> s -> r
69-
gets (Optical l) f s = getConst (runKleisli (l (Kleisli (Const P.. f))) s)
78+
gets (Optical l) f s = getConst' (runKleisli (l (Kleisli (Const P.. f))) s)
7079

7180
set :: Optic_ (->) a b s t -> b -> s -> t
7281
set (Optical l) x = l (const x)
7382

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))
87+
88+
-- 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))
91+
92+
build :: Optic_ (CoLKleisli (Const b)) a b s t -> b ->. t
93+
build (Optical l) x = runCoLKleisli (l (CoLKleisli getConst')) (Const x)
94+
95+
-- XXX: move this to Prelude
96+
-- | Linearly typed patch for the newtype deconstructor. (Temporary until
97+
-- inference will get this from the newtype declaration.)
98+
getConst' :: Const a b ->. a
99+
getConst' (Const x) = x
100+
74101
lengthOf :: Num r => Optic_ (Kleisli (Const (Sum r))) a b s t -> s -> r
75102
lengthOf l s = getSum (gets l (const (Sum 1)) s)
76103

@@ -81,3 +108,11 @@ over' (Optical l) f = l f
81108

82109
traverseOf' :: Optic_ (Kleisli f) a b s t -> (a -> f b) -> s -> f t
83110
traverseOf' (Optical l) f = runKleisli (l (Kleisli f))
111+
112+
iso :: (s ->. a) -> (b ->. t) -> Iso a b s t
113+
iso f g = Optical (dimap f g)
114+
115+
withIso :: Optic_ (Exchange a b) a b s t -> ((s ->. a) -> (b ->. t) -> r) -> r
116+
withIso (Optical l) f = f fro to
117+
where Exchange fro to = l (Exchange id id)
118+

src/Data/Functor/Linear.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
module Data.Functor.Linear where
1616

1717
import Prelude.Linear.Internal.Simple
18+
import Data.Functor.Const
1819

1920
class Functor f where
2021
fmap :: (a ->. b) -> f a ->. f b
@@ -70,3 +71,6 @@ instance Functor [] where
7071
instance Traversable [] where
7172
traverse _f [] = pure []
7273
traverse f (a : as) = (:) <$> f a <*> traverse f as
74+
75+
instance Functor (Const x) where
76+
fmap _ (Const x) = Const x

src/Data/Profunctor/Linear.hs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{-# LANGUAGE FlexibleContexts #-}
2+
{-# LANGUAGE FlexibleInstances #-}
23
{-# LANGUAGE KindSignatures #-}
34
{-# LANGUAGE LambdaCase #-}
45
{-# LANGUAGE LinearTypes #-}
@@ -12,14 +13,17 @@ module Data.Profunctor.Linear
1213
, Monoidal(..)
1314
, Strong(..)
1415
, Wandering(..)
15-
, LinearArrow(..)
16+
, LinearArrow(..), getLA
1617
, Kleisli(..)
1718
, LKleisli(..)
19+
, CoLKleisli(..)
20+
, Exchange(..)
1821
) where
1922

2023
import qualified Control.Monad.Linear as Control
2124
import qualified Data.Functor.Linear as Data
2225
import Data.Bifunctor.Linear hiding (first, second)
26+
import Data.Functor.Const
2327
import Prelude.Linear
2428
import Data.Void
2529
import qualified Prelude
@@ -63,7 +67,11 @@ class (Strong (,) () arr, Strong Either Void arr) => Wandering arr where
6367
-- Instances --
6468
---------------
6569

66-
newtype LinearArrow a b = LA { getLA :: a ->. b }
70+
newtype LinearArrow a b = LA (a ->. b)
71+
-- | Temporary deconstructor since inference doesn't get it right
72+
-- TODO: maybe use TH to automatically write things like this?
73+
getLA :: LinearArrow a b ->. a ->. b
74+
getLA (LA f) = f
6775

6876
instance Profunctor LinearArrow where
6977
dimap f g (LA h) = LA $ g . h . f
@@ -90,8 +98,6 @@ instance Prelude.Applicative f => Strong Either Void (Kleisli f) where
9098
Left x -> Prelude.fmap Left (f x)
9199
Right y -> Prelude.pure (Right y)
92100

93-
forget :: (a ->. b) -> a -> b
94-
forget f x = f x
95101

96102
newtype LKleisli m a b = LKleisli { runLKleisli :: a ->. m b }
97103

@@ -116,3 +122,20 @@ instance Strong (,) () (->) where
116122
instance Strong Either Void (->) where
117123
first f (Left x) = Left (f x)
118124
first _ (Right y) = Right y
125+
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+
138+
data Exchange a b s t = Exchange (s ->. a) (b ->. t)
139+
instance Profunctor (Exchange a b) where
140+
dimap f g (Exchange p q) = Exchange (p . f) (g . q)
141+

src/Prelude/Linear.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ module Prelude.Linear
1818
, (.)
1919
, either
2020
, maybe
21+
, forget
2122
-- * Unrestricted
2223
-- $ unrestricted
2324
, Unrestricted(..)
@@ -71,6 +72,12 @@ maybe :: b -> (a ->. b) -> Maybe a ->. b
7172
maybe x _ Nothing = x
7273
maybe _ f (Just y) = f y
7374

75+
-- XXX: temporary
76+
-- | Convenience operator when a higher-order function expects a non-linear
77+
-- arrow but we have a linear arrow
78+
forget :: (a ->. b) ->. a -> b
79+
forget f x = f x
80+
7481
-- $ unrestricted
7582

7683
-- | @Unrestricted a@ represents unrestricted values of type @a@ in a linear context,

0 commit comments

Comments
 (0)