Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions src/Control/Optics/Linear/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,27 @@ module Control.Optics.Linear.Internal
, _Just, _Nothing
, traversed
-- * Using optics
, get, set, gets
, get, set, gets, setSwap
, match, build
, over, over'
, traverseOf, traverseOf'
, lengthOf
, withIso, withPrism
, toListOf, lengthOf
, withIso, withLens, withPrism
-- * Constructing optics
, iso, prism
, iso, lens, prism
)
where

import qualified Control.Arrow as NonLinear
import qualified Data.Bifunctor.Linear as Bifunctor
import Data.Bifunctor.Linear (SymmetricMonoidal)
import Data.Profunctor.Linear
import Data.Functor.Compose hiding (getCompose)
import Data.Functor.Linear
import qualified Data.Profunctor.Kleisli.Linear as Linear
import Data.Void
import GHC.Exts (FUN)
import GHC.Types
import Prelude.Linear
import qualified Prelude as P

Expand All @@ -67,6 +70,10 @@ assoc = iso Bifunctor.lassoc Bifunctor.rassoc
(.>) :: Optic_ arr a b s t -> Optic_ arr x y a b -> Optic_ arr x y s t
Optical f .> Optical g = Optical (f P.. g)


lens :: (s #-> (a, b #-> t)) -> Lens a b s t
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice; me likey 😏

lens k = Optical $ \f -> dimap k (\(x,g) -> g $ x) (first f)

prism :: (b #-> t) -> (s #-> Either t a) -> Prism a b s t
prism b s = Optical $ \f -> dimap s (either id id) (second (rmap b f))

Expand Down Expand Up @@ -97,6 +104,9 @@ over (Optical l) f = getLA (l (LA f))
traverseOf :: Optic_ (Linear.Kleisli f) a b s t -> (a #-> f b) -> s #-> f t
traverseOf (Optical l) f = Linear.runKleisli (l (Linear.Kleisli f))

toListOf :: Optic_ (NonLinear.Kleisli (Const [a])) a b s t -> s -> [a]
toListOf l = gets l (\a -> [a])

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

Expand All @@ -106,6 +116,9 @@ gets (Optical l) f s = getConst' (NonLinear.runKleisli (l (NonLinear.Kleisli (Co
set :: Optic_ (->) a b s t -> b -> s -> t
set (Optical l) x = l (const x)

setSwap :: Optic_ (Linear.Kleisli (Compose (LinearArrow b) ((,) a))) a b s t -> s #-> b #-> (a, t)
setSwap (Optical l) s = getLA (getCompose (Linear.runKleisli (l (Linear.Kleisli (\a -> Compose (LA (\b -> (a,b)))))) s))

match :: Optic_ (Market a b) a b s t -> s #-> Either t a
match (Optical l) = snd (runMarket (l (Market id Right)))

Expand Down Expand Up @@ -139,3 +152,10 @@ withIso (Optical l) f = f fro to
withPrism :: Optic_ (Market a b) a b s t -> ((b #-> t) -> (s #-> Either t a) -> r) -> r
withPrism (Optical l) f = f b m
where Market b m = l (Market id Right)

withLens :: Optic_ (Linear.Kleisli (Compose ((,) a) (FUN 'One b))) a b s t -> s #-> (a, b #-> t)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this is just migration and that I'm going to take a pass through optics, this, although complicated, is fine right now. When I take a pass I'm going to comment that withLens is (kind of) the dual of lens and the (Optic_ ...) is basically (a #-> (a, b -> b)) -> (s #-> (s, t -> t)).

One question: could we change FUN 'One b to (->) b which is much more readable to me?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

withLens is (kind of) the dual of lens

The better term is inverse

could we change FUN 'One b to (->) b which is much more readable to me?

It would not work. (->) is FUN 'Many. There are many ways to make this simpler, but I don't think that they are much needed. The type after Optic_ is not meant to be read. See the lens library for how to document such primitives.

withLens (Optical l) s = getCompose (Linear.runKleisli (l (Linear.Kleisli (\a -> Compose (a, id)))) s)

-- linear variant of getCompose
getCompose :: Compose f g a #-> f (g a)
getCompose (Compose x) = x
9 changes: 9 additions & 0 deletions src/Data/Functor/Linear/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Data.Functor.Linear.Internal where

import Prelude.Linear.Internal
import Prelude (Maybe(..), Either(..))
import Data.Functor.Compose
import Data.Functor.Const
import Data.Monoid.Linear
import Data.Functor.Identity
Expand Down Expand Up @@ -97,6 +98,14 @@ instance Applicative Identity where
pure = Identity
Identity f <*> Identity x = Identity (f x)

instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose x) = Compose (fmap (fmap f) x)

instance (Applicative f, Applicative g) => Applicative (Compose f g) where
pure x = Compose (pure (pure x))
(Compose f) <*> (Compose x) = Compose (liftA2 (<*>) f x)
liftA2 f (Compose x) (Compose y) = Compose (liftA2 (liftA2 f) x y)

Comment on lines +101 to +108
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like these. I needed them for linear-streams.

---------------------------------
-- Monad transformer instances --
---------------------------------
Expand Down