summaryrefslogtreecommitdiff
path: root/src/Data/Profunctor/Optic/View.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Data/Profunctor/Optic/View.hs')
-rw-r--r--src/Data/Profunctor/Optic/View.hs615
1 files changed, 443 insertions, 172 deletions
diff --git a/src/Data/Profunctor/Optic/View.hs b/src/Data/Profunctor/Optic/View.hs
index f37c72f..98a5a28 100644
--- a/src/Data/Profunctor/Optic/View.hs
+++ b/src/Data/Profunctor/Optic/View.hs
@@ -1,16 +1,110 @@
-module Data.Profunctor.Optic.View where
-
-import Data.Profunctor.Optic.Type
-import Data.Profunctor.Optic.Prelude
+{-# LANGUAGE QuantifiedConstraints #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE TupleSections #-}
+module Data.Profunctor.Optic.View (
+ -- * Types
+ View
+ , AView
+ , Ixview
+ , AIxview
+ , PrimView
+ , Review
+ , AReview
+ , Cxview
+ , ACxview
+ , PrimReview
+ -- * Constructors
+ , to
+ , ixto
+ , from
+ , cxfrom
+ , cloneView
+ , cloneReview
+ -- * Optics
+ , like
+ , ixlike
+ , relike
+ , cxlike
+ , toProduct
+ , fromSum
+ -- * Primitive operators
+ , withPrimView
+ , withPrimReview
+ -- * Operators
+ , (^.)
+ , (^%)
+ , view
+ , ixview
+ , views
+ , ixviews
+ , use
+ , ixuse
+ , uses
+ , ixuses
+ , (#^)
+ , review
+ , cxview
+ , reviews
+ , cxviews
+ , reuse
+ , reuses
+ , cxuse
+ , cxuses
+ -- * MonadIO
+ , throws
+ , throws_
+ , throwsTo
+ -- * Carriers
+ , Star(..)
+ , Tagged(..)
+) where
+
+import Control.Exception (Exception)
+import Control.Monad.IO.Class
import Control.Monad.Reader as Reader
import Control.Monad.Writer as Writer hiding (Sum(..))
-import Control.Monad.State as State hiding (StateT(..))
+import Control.Monad.State as State
+import Data.Profunctor.Optic.Type
+import Data.Profunctor.Optic.Import
+import Data.Profunctor.Optic.Index
+import GHC.Conc (ThreadId)
+import qualified Control.Exception as Ex
+import qualified Data.Bifunctor as B
+
+-- $setup
+-- >>> :set -XNoOverloadedStrings
+-- >>> :set -XTypeApplications
+-- >>> :set -XFlexibleContexts
+-- >>> :set -XRank2Types
+-- >>> import Data.Either
+-- >>> import Control.Monad.State
+-- >>> import Control.Monad.Writer
+-- >>> import Data.Int.Instance ()
+-- >>> import Data.List.Index as LI
+-- >>> :load Data.Profunctor.Optic
+-- >>> let catchOn :: Int -> Cxprism' Int (Maybe String) String ; catchOn n = cxjust $ \k -> if k==n then Just "caught" else Nothing
+-- >>> let ixtraversed :: Ixtraversal Int [a] [b] a b ; ixtraversed = ixtraversalVl LI.itraverse
+-- >>> let ixat :: Int -> Ixtraversal0' Int [a] a; ixat = inserted (\i s -> flip LI.ifind s $ \n _ -> n == i) (\i a s -> LI.modifyAt i (const a) s)
+
+type APrimView r s t a b = Optic (Star (Const r)) s t a b
+
+type AView s a = Optic' (Star (Const a)) s a
+
+type AIxview r i s a = IndexedOptic' (Star (Const (Maybe i , r))) i s a
+
+type APrimReview s t a b = Optic Tagged s t a b
+
+type AReview t b = Optic' Tagged t b
+
+type ACxview k t b = CoindexedOptic' Tagged k t b
---------------------------------------------------------------------
-- 'View' & 'Review'
---------------------------------------------------------------------
--- | Build a 'View' from an arbitrary function.
+
+-- | Obtain a 'View' from an arbitrary function.
--
-- @
-- 'to' f '.' 'to' g ≡ 'to' (g '.' f)
@@ -23,7 +117,7 @@ import Control.Monad.State as State hiding (StateT(..))
-- >>> 5 ^. to succ
-- 6
--
--- >>> (0, -5) ^. _2 . to abs
+-- >>> (0, -5) ^. t22 . to abs
-- 5
--
-- @
@@ -34,13 +128,19 @@ to :: (s -> a) -> PrimView s t a b
to f = coercer . lmap f
{-# INLINE to #-}
--- | Build a 'Review' from an arbitrary function.
+-- | TODO: Document
+--
+ixto :: (s -> (i , a)) -> Ixview i s a
+ixto f = to $ f . snd
+{-# INLINE ixto #-}
+
+-- | Obtain a 'Review' from an arbitrary function.
--
-- @
-- 'from' ≡ 're' . 'to'
-- @
--
--- >>> (from Prelude.length) # [1,2,3]
+-- >>> (from Prelude.length) #^ [1,2,3]
-- 3
--
-- @
@@ -51,34 +151,16 @@ from :: (b -> t) -> PrimReview s t a b
from f = coercel . rmap f
{-# INLINE from #-}
--- ^ @
--- 'toBoth' :: 'View' s a -> 'View' s b -> 'View' s (a, b)
--- @
---
-toBoth :: AView s a1 -> AView s a2 -> PrimView s t (a1 , a2) b
-toBoth l r = to (view l &&& view r)
-{-# INLINE toBoth #-}
-
--- | TODO: Document
---
-fromBoth :: AReview t1 b -> AReview t2 b -> PrimReview s (t1 , t2) a b
-fromBoth l r = from (review l &&& review r)
-{-# INLINE fromBoth #-}
-
-- | TODO: Document
--
-toEither :: AView s1 a -> AView s2 a -> PrimView (s1 + s2) t a b
-toEither l r = to (view l ||| view r)
-{-# INLINE toEither #-}
+cxfrom :: ((k -> b) -> t) -> Cxview k t b
+cxfrom f = from $ \kb _ -> f kb
+{-# INLINE cxfrom #-}
-- | TODO: Document
--
-fromEither :: AReview t b1 -> AReview t b2 -> PrimReview s t a (b1 + b2)
-fromEither l r = from (review l ||| review r)
-{-# INLINE fromEither #-}
-
--- ^ @
--- 'cloneView' :: 'AView' s a -> 'View' s a
+-- @
+-- 'cloneView' :: 'AView' s a -> 'View' s a
-- 'cloneView' :: 'Monoid' a => 'AView' s a -> 'Fold' s a
-- @
--
@@ -96,75 +178,26 @@ cloneReview = from . review
-- Primitive operators
---------------------------------------------------------------------
--- | Map each part of a structure viewed to a SEC.
---
--- @
--- 'Data.Foldable.foldMap' = 'viewOf' 'folding''
--- 'viewOf' ≡ 'views'
--- @
---
--- >>> viewOf both id (["foo"], ["bar", "baz"])
--- ["foo","bar","baz"]
---
--- @
--- 'viewOf' :: 'Iso'' s a -> (a -> r) -> s -> r
--- 'viewOf' :: 'Lens'' s a -> (a -> r) -> s -> r
--- 'viewOf' :: 'Monoid' r => 'Prism'' s a -> (a -> r) -> s -> r
--- 'viewOf' :: 'Monoid' r => 'Traversal'' s a -> (a -> r) -> s -> r
--- 'viewOf' :: 'Monoid' r => 'Traversal0'' s a -> (a -> r) -> s -> r
--- 'viewOf' :: 'Semigroup' r => 'Traversal1'' s a -> (a -> r) -> s -> r
--- 'viewOf' :: 'Monoid' r => 'Fold' s a -> (a -> r) -> s -> r
--- 'viewOf' :: 'Semigroup' r => 'Fold1' s a -> (a -> r) -> s -> r
--- 'viewOf' :: 'AView' s a -> (a -> r) -> s -> r
--- @
+-- | TODO: Document
--
-viewOf :: Optic' (FoldRep r) s a -> (a -> r) -> s -> r
-viewOf = between ((getConst .) . runStar) (Star . (Const . ))
-{-# INLINE viewOf #-}
+withPrimView :: APrimView r s t a b -> (a -> r) -> s -> r
+withPrimView o = (getConst #.) #. runStar #. o .# Star .# (Const #.)
+{-# INLINE withPrimView #-}
-- | TODO: Document
--
-reviewOf :: Optic' (CofoldRep r) t b -> (r -> b) -> r -> t
-reviewOf = between ((. Const) . runCostar) (Costar . (. getConst))
-{-# INLINE reviewOf #-}
+withPrimReview :: APrimReview s t a b -> (t -> r) -> b -> r
+withPrimReview o f = f . unTagged #. o .# Tagged
+{-# INLINE withPrimReview #-}
---------------------------------------------------------------------
--- Common 'View's and 'Review's
+-- Optics
---------------------------------------------------------------------
--- | TODO: Document
---
-coercedr :: PrimView a x a y
-coercedr = coercer
-{-# INLINE coercedr #-}
-
--- | TODO: Document
---
-coercedl :: PrimReview x b y b
-coercedl = coercel
-{-# INLINE coercedl #-}
-
--- | TODO: Document
---
-_1' :: PrimView (a , c) (b , c) a b
-_1' = to fst
-
--- | TODO: Document
---
-_2' :: PrimView (c , a) (c , b) a b
-_2' = to snd
-
--- | TODO: Document
---
-_L' :: PrimReview (a + c) (b + c) a b
-_L' = from Left
-
--- | TODO: Document
+-- | Obtain a constant-valued (index-preserving) 'View' from an arbitrary value.
--
-_R' :: PrimReview (c + a) (c + b) a b
-_R' = from Right
-
--- | Build a constant-valued (index-preserving) 'PrimView' from an arbitrary value.
+-- This can be useful as a second case 'failing' a 'Fold'
+-- e.g. @foo `failing` 'like' 0@
--
-- @
-- 'like' a '.' 'like' b ≡ 'like' b
@@ -172,14 +205,22 @@ _R' = from Right
-- a '^.' 'like' b ≡ a '^.' 'to' ('const' b)
-- @
--
--- This can be useful as a second case 'failing' a 'Fold'
--- e.g. @foo `failing` 'like' 0@
+--
+-- @
+-- 'like' :: a -> 'View' s a
+-- @
--
like :: a -> PrimView s t a b
like = to . const
{-# INLINE like #-}
--- | Build a constant-valued (index-preserving) 'PrimReview' from an arbitrary value.
+-- | TODO: Document
+--
+ixlike :: i -> a -> Ixview i s a
+ixlike i a = ixto (const (i, a))
+{-# INLINE ixlike #-}
+
+-- | Obtain a constant-valued (index-preserving) 'Review' from an arbitrary value.
--
-- @
-- 'relike' a '.' 'relike' b ≡ 'relike' a
@@ -191,143 +232,373 @@ relike :: t -> PrimReview s t a b
relike = from . const
{-# INLINE relike #-}
+-- | Obtain a constant-valued 'Cxview' from an arbitrary value.
+--
+cxlike :: t -> Cxview k t b
+cxlike = cxfrom . const
+{-# INLINE cxlike #-}
+
+-- | Combine two 'View's into a 'View' to a product.
+--
+-- @
+-- 'toProduct' :: 'View' s a1 -> 'View' s a2 -> 'View' s (a1 , a2)
+-- @
+--
+toProduct :: AView s a1 -> AView s a2 -> PrimView s t (a1 , a2) b
+toProduct l r = to (view l &&& view r)
+{-# INLINE toProduct #-}
+
+-- | Combine two 'Review's into a 'Review' from a sum.
+--
+-- @
+-- 'fromSum' :: 'Review' t b1 -> 'Review' t b2 -> 'Review' t (b1 + b2)
+-- @
+--
+fromSum :: AReview t b1 -> AReview t b2 -> PrimReview s t a (b1 + b2)
+fromSum l r = from (review l ||| review r)
+{-# INLINE fromSum #-}
+
---------------------------------------------------------------------
--- Derived operators
+-- Operators
---------------------------------------------------------------------
infixl 8 ^.
--- | TODO: Document
+-- | An infix alias for 'view'. Dual to '#'.
+--
+-- Fixity and semantics are such that subsequent field accesses can be
+-- performed with ('Prelude..').
+--
+-- >>> ("hello","world") ^. t22
+-- "world"
+--
+-- >>> import Data.Complex
+-- >>> ((0, 1 :+ 2), 3) ^. t21 . t22 . to magnitude
+-- 2.23606797749979
+--
+-- @
+-- ('^.') :: s -> 'View' s a -> a
+-- ('^.') :: 'Data.Monoid.Monoid' m => s -> 'Data.Profunctor.Optic.Fold.Fold' s m -> m
+-- ('^.') :: s -> 'Data.Profunctor.Optic.Iso.Iso'' s a -> a
+-- ('^.') :: s -> 'Data.Profunctor.Optic.Lens.Lens'' s a -> a
+-- ('^.') :: s -> 'Data.Profunctor.Optic.Prism.Coprism'' s a -> a
+-- ('^.') :: 'Data.Monoid.Monoid' m => s -> 'Data.Profunctor.Optic.Traversal.Traversal'' s m -> m
+-- @
--
(^.) :: s -> AView s a -> a
(^.) = flip view
{-# INLINE ( ^. ) #-}
-infixr 8 #
+infixl 8 ^%
--- | An infix alias for 'review'. Dual to '^.'.
+-- | Bring the index and value of a indexed optic into the current environment as a pair.
+--
+-- This a flipped, infix variant of 'ixview' and an indexed variant of '^.'.
+--
+-- The fixity and semantics are such that subsequent field accesses can be
+-- performed with ('Prelude..').
+--
+-- The result probably doesn't have much meaning when applied to an 'Ixfold'.
+--
+(^%) :: Monoid i => s -> AIxview a i s a -> (Maybe i , a)
+(^%) = flip ixview
+{-# INLINE (^%) #-}
+
+-- | View the value pointed to by a 'View', 'Data.Profunctor.Optic.Iso.Iso' or
+-- 'Lens' or the result of folding over all the results of a
+-- 'Data.Profunctor.Optic.Fold.Fold' or 'Data.Profunctor.Optic.Traversal.Traversal' that points
+-- at a monoidal value.
--
-- @
--- 'from' f # x ≡ f x
--- l # x ≡ x '^.' 're' l
+-- 'view' '.' 'to' ≡ 'id'
-- @
--
--- This is commonly used when using a 'Prism' as a smart constructor.
+-- >>> view t22 (1, "hello")
+-- "hello"
--
--- >>> _Left # 4
--- Left 4
+-- >>> view (to succ) 5
+-- 6
+--
+-- >>> view (t22 . t21) ("hello",("world","!!!"))
+-- "world"
+--
+view :: MonadReader s m => AView s a -> m a
+view o = views o id
+{-# INLINE view #-}
+
+-- | Bring the index and value of a indexed optic into the current environment as a pair.
+--
+-- >>> ixview ixfirst ("foo", 42)
+-- (Just (),"foo")
+--
+-- >>> ixview (ixat 3 . ixfirst) [(0,'f'),(1,'o'),(2,'o'),(3,'b'),(4,'a'),(5,'r') :: (Int, Char)]
+-- (Just 3,3)
+--
+-- In order to 'ixview' a 'Choice' optic (e.g. 'Ixtraversal0', 'Ixtraversal', 'Ixfold', etc),
+-- /a/ must have a 'Monoid' instance:
--
--- But it can be used for any 'Prism'
+-- >>> ixview (ixat 0) ([] :: [Int])
+-- (Nothing,0)
+-- >>> ixview (ixat 0) ([1] :: [Int])
+-- (Just 0,1)
--
--- >>> base 16 # 123
--- "7b"
+-- /Note/ when applied to a 'Ixtraversal' or 'Ixfold', then 'ixview' will return a monoidal
+-- summary of the indices tupled with a monoidal summary of the values:
+--
+-- >>> (ixview @_ @_ @Int @Int) ixtraversed [1,2,3,4]
+-- (Just 6,10)
+--
+ixview :: MonadReader s m => Monoid i => AIxview a i s a -> m (Maybe i , a)
+ixview o = asks $ withPrimView o (B.first Just) . (mempty,)
+{-# INLINE ixview #-}
+
+-- | Map each part of a structure viewed to a semantic edixtor combinator.
+--
+-- @
+-- 'views o f ≡ withFold o f'
+-- 'Data.Foldable.foldMap' = 'views' 'folding''
+-- @
+--
+-- >>> views both id (["foo"], ["bar", "baz"])
+-- ["foo","bar","baz"]
--
-- @
--- (#) :: 'Iso'' s a -> a -> s
--- (#) :: 'Prism'' s a -> a -> s
--- (#) :: 'Review' s a -> a -> s
--- (#) :: 'Equality'' s a -> a -> s
+-- 'views' :: 'AView' s a -> (a -> r) -> s -> r
+-- 'views' :: 'Iso'' s a -> (a -> r) -> s -> r
+-- 'views' :: 'Lens'' s a -> (a -> r) -> s -> r
+-- 'views' :: 'Coprism'' s a -> (a -> r) -> s -> r
+-- 'views' :: 'Monoid' r => 'Traversal'' s a -> (a -> r) -> s -> r
+-- 'views' :: 'Semigroup' r => 'Traversal1'' s a -> (a -> r) -> s -> r
+-- 'views' :: 'Monoid' r => 'Fold' s a -> (a -> r) -> s -> r
+-- 'views' :: 'Semigroup' r => 'Fold1' s a -> (a -> r) -> s -> r
-- @
--
-(#) :: AReview t b -> b -> t
-o # b = review o b
-{-# INLINE ( # ) #-}
+views :: MonadReader s m => Optic' (Star (Const r)) s a -> (a -> r) -> m r
+views o f = asks $ withPrimView o f
+{-# INLINE views #-}
--- ^ @
--- 'view o ≡ foldMapOf o id'
--- 'review' ≡ 'view' '.' 're'
--- 'reviews' ≡ 'views' '.' 're'
+-- | Bring a function of the index and value of an indexed optic into the current environment.
+--
+-- 'ixviews' ≡ 'iwithFold'
+--
+-- >>> ixviews (ixat 2) (-) ([0,1,2] :: [Int])
+-- 0
+--
+-- In order to 'ixviews' a 'Choice' optic (e.g. 'Ixtraversal0', 'Ixtraversal', 'Ixfold', etc),
+-- /a/ must have a 'Monoid' instance (here from the 'rings' package):
+--
+-- >>> ixviews (ixat 3) (flip const) ([1] :: [Int])
+-- 0
+--
+-- Use 'ixview' if there is a need to disambiguate between 'mempty' as a miss vs. as a return value.
+--
+ixviews :: MonadReader s m => Monoid i => IndexedOptic' (Star (Const r)) i s a -> (i -> a -> r) -> m r
+ixviews o f = asks $ withPrimView o (uncurry f) . (mempty,)
+
+-- | TODO: Document
+--
+use :: MonadState s m => AView s a -> m a
+use o = gets (view o)
+{-# INLINE use #-}
+
+-- | Bring the index and value of an indexed optic into the current environment as a pair.
+--
+ixuse :: MonadState s m => Monoid i => AIxview a i s a -> m (Maybe i , a)
+ixuse o = gets (ixview o)
+
+-- | Use the target of a 'Lens', 'Data.Profunctor.Optic.Iso.Iso' or
+-- 'View' in the current state, or use a summary of a
+-- 'Data.Profunctor.Optic.Fold.Fold' or 'Data.Profunctor.Optic.Traversal.Traversal' that
+-- points to a monoidal value.
+--
+-- >>> evalState (uses t21 length) ("hello","world!")
+-- 5
+--
+-- @
+-- 'uses' :: 'MonadState' s m => 'Data.Profunctor.Optic.Iso.Iso'' s a -> (a -> r) -> m r
+-- 'uses' :: 'MonadState' s m => 'Data.Profunctor.Optic.View.View' s a -> (a -> r) -> m r
+-- 'uses' :: 'MonadState' s m => 'Data.Profunctor.Optic.Lens.Lens'' s a -> (a -> r) -> m r
+-- 'uses' :: 'MonadState' s m => 'Data.Profunctor.Optic.Prism.Coprism'' s a -> (a -> r) -> m r
+-- 'uses' :: 'MonadState' s m => 'Data.Monoid.Monoid' r => 'Data.Profunctor.Optic.Traversal.Traversal'' s a -> (a -> r) -> m r
+-- 'uses' :: 'MonadState' s m => 'Data.Monoid.Monoid' r => 'Data.Profunctor.Optic.Fold.Fold' s a -> (a -> r) -> m r
-- @
--
-view :: MonadReader s m => AView s a -> m a
-view = (`views` id)
-{-# INLINE view #-}
+-- @
+-- 'uses' :: 'MonadState' s m => 'Getting' r s t a b -> (a -> r) -> m r
+-- @
+--
+uses :: MonadState s m => Optic' (Star (Const r)) s a -> (a -> r) -> m r
+uses l f = gets (views l f)
+{-# INLINE uses #-}
+
+-- | Bring a function of the index and value of an indexed optic into the current environment.
+--
+ixuses :: MonadState s m => Monoid i => IndexedOptic' (Star (Const r)) i s a -> (i -> a -> r) -> m r
+ixuses o f = gets $ withPrimView o (uncurry f) . (mempty,)
+
+infixr 8 #^
+
+-- | An infix variant of 'review'. Dual to '^.'.
+--
+-- @
+-- 'from' f #^ x ≡ f x
+-- o #^ x ≡ x '^.' 're' o
+-- @
+--
+-- This is commonly used when using a 'Prism' as a smart constructor.
+--
+-- >>> left #^ 4
+-- Left 4
+--
+-- @
+-- (#^) :: 'Iso'' s a -> a -> s
+-- (#^) :: 'Prism'' s a -> a -> s
+-- (#^) :: 'Colens'' s a -> a -> s
+-- (#^) :: 'Review' s a -> a -> s
+-- (#^) :: 'Equality'' s a -> a -> s
+-- @
+--
+(#^) :: AReview t b -> b -> t
+o #^ b = review o b
+{-# INLINE (#^) #-}
--- ^ @
--- 'review o ≡ cofoldMapOf o id'
+-- | Turn an optic around and look through the other end.
+--
+-- @
+-- 'review' ≡ 'view' '.' 're'
+-- 'review' . 'from' ≡ 'id'
+-- @
+--
+-- >>> review (from succ) 5
+-- 6
+--
+-- @
+-- 'review' :: 'Iso'' s a -> a -> s
+-- 'review' :: 'Prism'' s a -> a -> s
+-- 'review' :: 'Colens'' s a -> a -> s
-- @
--
review :: MonadReader b m => AReview t b -> m t
-review = (`reviews` id)
+review o = reviews o id
{-# INLINE review #-}
--- ^ @
--- 'views o f ≡ foldMapOf o f'
--- @
-views :: MonadReader s m => Optic' (FoldRep r) s a -> (a -> r) -> m r
-views o f = Reader.asks $ viewOf o f
-{-# INLINE views #-}
+-- | Bring a function of the index of a co-indexed optic into the current environment.
+--
+cxview :: MonadReader b m => ACxview k t b -> m (k -> t)
+cxview o = cxviews o id
+{-# INLINE cxview #-}
--- | This can be used to turn an 'Iso' or 'Prism' around and 'view' a value (or the current environment) through it the other way,
--- applying a function.
+-- | Turn an optic around and look through the other end, applying a function.
--
-- @
-- 'reviews' ≡ 'views' '.' 're'
-- 'reviews' ('from' f) g ≡ g '.' f
-- @
--
--- >>> reviews _Left isRight "mustard"
+-- >>> reviews left isRight "mustard"
-- False
--
-- >>> reviews (from succ) (*2) 3
-- 8
--
--- Usually this function is used in the @(->)@ 'Monad' with a 'Prism' or 'Iso', in which case it may be useful to think of
--- it as having one of these more restricted type signatures:
+-- @
+-- 'reviews' :: 'Iso'' t b -> (t -> r) -> b -> r
+-- 'reviews' :: 'Prism'' t b -> (t -> r) -> b -> r
+-- 'reviews' :: 'Colens'' t b -> (t -> r) -> b -> r
+-- @
+--
+reviews :: MonadReader b m => AReview t b -> (t -> r) -> m r
+reviews o f = asks $ withPrimReview o f
+{-# INLINE reviews #-}
+
+-- | Bring a continuation of the index of a co-indexed optic into the current environment.
--
-- @
--- 'reviews' :: 'Iso'' s a -> (s -> r) -> a -> r
--- 'reviews' :: 'Prism'' s a -> (s -> r) -> a -> r
+-- cxviews :: ACxview k t b -> ((k -> t) -> r) -> b -> r
-- @
--
--- However, when working with a 'Monad' transformer stack, it is sometimes useful to be able to 'review' the current environment, in which case
--- it may be beneficial to think of it as having one of these slightly more liberal type signatures:
+cxviews :: MonadReader b m => ACxview k t b -> ((k -> t) -> r) -> m r
+cxviews o f = asks $ withPrimReview o f . const
+
+-- | Turn an optic around and 'use' a value (or the current environment) through it the other way.
--
-- @
--- 'reviews' :: 'MonadReader' a m => 'Iso'' s a -> (s -> r) -> m r
--- 'reviews' :: 'MonadReader' a m => 'Prism'' s a -> (s -> r) -> m r
+-- 'reuse' ≡ 'use' '.' 're'
+-- 'reuse' '.' 'from' ≡ 'gets'
+-- @
+--
+-- >>> evalState (reuse left) 5
+-- Left 5
+--
+-- >>> evalState (reuse (from succ)) 5
+-- 6
+--
-- @
--- ^ @
--- 'reviews o f ≡ cofoldMapOf o f'
+-- 'reuse' :: 'MonadState' a m => 'Iso'' s a -> m s
+-- 'reuse' :: 'MonadState' a m => 'Prism'' s a -> m s
+-- 'reuse' :: 'MonadState' a m => 'Colens'' s a -> m s
-- @
--
-reviews :: MonadReader r m => ACofold r t b -> (r -> b) -> m t
-reviews o f = Reader.asks $ reviewOf o f
-{-# INLINE reviews #-}
-
----------------------------------------------------------------------
--- 'MonadState' and 'MonadWriter'
----------------------------------------------------------------------
+reuse :: MonadState b m => AReview t b -> m t
+reuse o = gets (unTagged #. o .# Tagged)
+{-# INLINE reuse #-}
-- | TODO: Document
--
-use :: MonadState s m => AView s a -> m a
-use o = State.gets (view o)
-{-# INLINE use #-}
+cxuse :: MonadState b m => ACxview k t b -> m (k -> t)
+cxuse o = gets (cxview o)
+{-# INLINE cxuse #-}
--- | Extracts the portion of a log that is focused on by a 'View'.
+-- | Turn an optic around and 'use' the current state through it the other way, applying a function.
+--
+-- @
+-- 'reuses' ≡ 'uses' '.' 're'
+-- 'reuses' ('from' f) g ≡ 'gets' (g '.' f)
+-- @
--
--- Given a 'Fold' or a 'Traversal', then a monoidal summary of the parts
--- of the log that are visited will be returned.
+-- >>> evalState (reuses left isLeft) (5 :: Int)
+-- True
--
-- @
--- 'listening' :: 'MonadWriter' w m => 'View' w u -> m a -> m (a, u)
--- 'listening' :: 'MonadWriter' w m => 'Lens'' w u -> m a -> m (a, u)
--- 'listening' :: 'MonadWriter' w m => 'Iso'' w u -> m a -> m (a, u)
--- 'listening' :: ('MonadWriter' w m, 'Monoid' u) => 'Fold' w u -> m a -> m (a, u)
--- 'listening' :: ('MonadWriter' w m, 'Monoid' u) => 'Traversal'' w u -> m a -> m (a, u)
--- 'listening' :: ('MonadWriter' w m, 'Monoid' u) => 'Prism'' w u -> m a -> m (a, u)
+-- 'reuses' :: 'MonadState' a m => 'Iso'' s a -> (s -> r) -> m r
+-- 'reuses' :: 'MonadState' a m => 'Prism'' s a -> (s -> r) -> m r
+-- 'reuses' :: 'MonadState' a m => 'Prism'' s a -> (s -> r) -> m r
-- @
-listening :: MonadWriter w m => AView w u -> m a -> m (a, u)
-listening l m = do
- (a, w) <- Writer.listen m
- return (a, view l w)
-{-# INLINE listening #-}
+--
+reuses :: MonadState b m => AReview t b -> (t -> r) -> m r
+reuses o tr = gets (tr . unTagged #. o .# Tagged)
+{-# INLINE reuses #-}
-- | TODO: Document
--
-listenings :: MonadWriter w m => Optic' (FoldRep v) w u -> (u -> v) -> m a -> m (a, v)
-listenings l uv m = do
- (a, w) <- listen m
- return (a, views l uv w)
-{-# INLINE listenings #-}
+cxuses :: MonadState b m => ACxview k t b -> ((k -> t) -> r) -> m r
+cxuses o f = gets (cxviews o f)
+{-# INLINE cxuses #-}
+
+---------------------------------------------------------------------
+-- 'MonadIO'
+---------------------------------------------------------------------
+
+-- | Throw an exception described by an optic.
+--
+-- @
+-- 'throws' o e \`seq\` x ≡ 'throws' o e
+-- @
+--
+throws :: MonadIO m => Exception e => AReview e b -> b -> m r
+throws o = reviews o $ liftIO . Ex.throwIO
+{-# INLINE throws #-}
+
+-- | Variant of 'throws' for error constructors with no arguments.
+--
+throws_ :: MonadIO m => Exception e => AReview e () -> m r
+throws_ o = throws o ()
+
+-- | Raise an 'Exception' specified by an optic in the target thread.
+--
+-- @
+-- 'throwsTo' thread o ≡ 'throwTo' thread . 'review' o
+-- @
+--
+throwsTo :: MonadIO m => Exception e => ThreadId -> AReview e b -> b -> m ()
+throwsTo tid o = reviews o (liftIO . Ex.throwTo tid)