Prisms
Overview
#Lens “zoom into” a factor of a product. What if we have a sum type instead? For example, consider the following type: data Result a = Ok a | Error String
We can’t create lenses corresponding to the constructors Ok and Error. We need a new type of optics instead, a prism
A prism differs from a lens in two ways:
The focused part of a prism is not always present.
Given a part, the whole can be created from it.
Prism laws
A prism p :: Prism s a should obey the following two laws:
• review preview: If preview finds something, then reviewing that should reconstruct the original:
If preview' p s = Just a, then review' p a = s.
• preview review: Previewing a reviewed a should find that
code:prisms.hs
type Prism s t a b = forall f p. (Applicative f, Choice p) => p a (f b) -> p s (f t)
type Prism' s a = Prism s s a a
prism :: (s -> Either t a) -> (b -> t) -> Prism s t a b
prism pr rv p = dimap pr (either pure (fmap rv)) (right' p)
prism' :: (s -> Maybe a) -> (a -> s) -> Prism' s a
prism' pr = prism pr'
where
pr' s = case pr s of
Nothing -> Left s
Just a -> Right a
review :: (Tagged a (Identity b) -> Tagged s (Identity t)) -> b -> t
review p = runIdentity . unTagged . p . Tagged . Identity
_Ok :: Prism' (Result a) a
_Ok = prism' p Ok
where
p (Ok a) = Just a
p (Error _) = Nothing
_Error :: Prism' (Result a) String
_Error = prism' p Error
where
p (Ok _) = Nothing
p (Error e) = Just e
_Left :: Prism (Either a b) (Either a' b) a a'
_Left = prism (either Right (Left . Right)) Left
_Right :: Prism (Either a b) (Either a b') b b'
_Right = prism (either (Left . Left) Right) Right
_Just :: Prism (Maybe a) (Maybe b) a b
_Just = prism (maybe (Left Nothing) Right) Just
_Nothing :: Prism' (Maybe a) ()
_Nothing = prism' (maybe (Just ()) (const Nothing)) (const Nothing)
_Cons :: Prism a b (a, a) (b, b) _Cons = prism p r
where
p [] = Left []
p (x : xs) = Right (x, xs)
r = uncurry (:)
_Nil = prism' p (const [])
where
p [] = Just ()
p (_ : _) = Nothing
Useful links
https://gyazo.com/2dce437e033838efb4128e1624508353