{-# LANGUAGE RankNTypes #-}
module Fresnel.Review
( -- * Reviews
  Review
, IsReview
  -- * Construction
, unto
, reviewing
, un
  -- * Elimination
, reviews
, review
, (#)
, re
  -- * Utilities
, lphantom
) where

import Data.Bifunctor
import Data.Profunctor
import Data.Profunctor.Unsafe ((#.), (.#))
import Data.Void
import Fresnel.Getter (Getter, to, view)
import Fresnel.Optic
import Fresnel.Prism.Internal (IsPrism)
import Fresnel.Profunctor.Recall

-- Reviews

type Review t b = forall p . IsReview p => Optic' p t b

class (IsPrism p, Bifunctor p, Costrong p) => IsReview p

instance IsReview (Recall e)


-- Construction

unto :: (b -> t) -> Review t b
unto :: (b -> t) -> Review t b
unto b -> t
f = p b t -> p t t
forall (p :: * -> * -> *) b c a.
(Bifunctor p, Profunctor p) =>
p b c -> p a c
lphantom (p b t -> p t t) -> (p b b -> p b t) -> p b b -> p t t
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (b -> t) -> p b b -> p b t
forall (p :: * -> * -> *) b c a.
Profunctor p =>
(b -> c) -> p a b -> p a c
rmap b -> t
f


reviewing :: (Profunctor p, Bifunctor p) => Optic p s t a b -> Optic' p t b
reviewing :: Optic p s t a b -> Optic' p t b
reviewing Optic p s t a b
l p b b
f = p s t -> p t t
forall (p :: * -> * -> *) b c a.
(Bifunctor p, Profunctor p) =>
p b c -> p a c
lphantom (p s t -> p t t) -> Optic p s t a b -> p a b -> p t t
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Optic p s t a b
l (p a b -> p t t) -> p a b -> p t t
forall a b. (a -> b) -> a -> b
$ p b b -> p a b
forall (p :: * -> * -> *) b c a.
(Bifunctor p, Profunctor p) =>
p b c -> p a c
lphantom p b b
f


un :: Getter s a -> Review a s
un :: Getter s a -> Review a s
un Getter s a
o = (s -> a) -> Review a s
forall b t. (b -> t) -> Review t b
unto (Getter s a -> s -> a
forall s a. Getter s a -> s -> a
view Getter s a
o)


-- Elimination

reviews :: Review t b -> (e -> b) -> (e -> t)
reviews :: Review t b -> (e -> b) -> e -> t
reviews Review t b
b = Recall e t t -> e -> t
forall e a b. Recall e a b -> e -> b
runRecall (Recall e t t -> e -> t)
-> (Recall e b b -> Recall e t t) -> Recall e b b -> e -> t
forall (p :: * -> * -> *) a b c (q :: * -> * -> *).
(Profunctor p, Coercible c b) =>
q b c -> p a b -> p a c
#. Recall e b b -> Recall e t t
Review t b
b (Recall e b b -> e -> t)
-> ((e -> b) -> Recall e b b) -> (e -> b) -> e -> t
forall (p :: * -> * -> *) a b c (q :: * -> * -> *).
(Profunctor p, Coercible b a) =>
p b c -> q a b -> p a c
.# (e -> b) -> Recall e b b
forall e a b. (e -> b) -> Recall e a b
Recall

review :: Review t b -> (b -> t)
review :: Review t b -> b -> t
review Review t b
b = Review t b -> (b -> b) -> b -> t
forall t b e. Review t b -> (e -> b) -> e -> t
reviews Review t b
b b -> b
forall a. a -> a
id

(#) :: Review t b -> (b -> t)
# :: Review t b -> b -> t
(#) = Review t b -> b -> t
forall t b. Review t b -> b -> t
review

infixr 8 #


re :: Review t b -> Getter b t
re :: Review t b -> Getter b t
re Review t b
o = (b -> t) -> Getter b t
forall s a. (s -> a) -> Getter s a
to (Review t b -> b -> t
forall t b. Review t b -> b -> t
review Review t b
o)


-- Utilities

lphantom :: (Bifunctor p, Profunctor p) => p b c -> p a c
lphantom :: p b c -> p a c
lphantom = (Void -> a) -> p Void c -> p a c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Void -> a
forall a. Void -> a
absurd (p Void c -> p a c) -> (p b c -> p Void c) -> p b c -> p a c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Void -> b) -> p b c -> p Void c
forall (p :: * -> * -> *) a b c.
Profunctor p =>
(a -> b) -> p b c -> p a c
lmap Void -> b
forall a. Void -> a
absurd