packages feed

ema-0.8.0.0: src/Ema/Route/Prism/Type.hs

module Ema.Route.Prism.Type where

import Optics.Core (A_Prism, Is, NoIx, Optic', Prism', castOptic, preview, prism', review, (%))

--  DerivingVia prevents us from directly using Prism' here
--  https://stackoverflow.com/q/71489589/55246

{- | Isomorphic to @Prism' s a@, but coercion-friendly.

 Use `fromPrism_` and `toPrism_` to convert between the optics @Prism'@ and this
 @Prism_@.
-}
type Prism_ s a = (a -> s, s -> Maybe a)

-- | Convert a `Prism_` to a @Prism'@.
fromPrism_ :: Prism_ s a -> Prism' s a
fromPrism_ = uncurry prism'

-- | Convert a @Prism'@ to a `Prism_`.
toPrism_ :: Prism' s a -> Prism_ s a
toPrism_ = review &&& preview

-- | map over the filepath, route and model of the given route prism.
mapRoutePrism ::
  (pr `Is` A_Prism, pf `Is` A_Prism) =>
  -- | How to transform the encoded `FilePath`
  Optic' pf NoIx FilePath FilePath ->
  -- | How to transform the decode route
  Optic' pr NoIx r1 r2 ->
  -- | How to transform (contramap) the resultant model
  (b -> a) ->
  -- | The route prism to fmap.
  (a -> Prism_ FilePath r1) ->
  (b -> Prism_ FilePath r2)
mapRoutePrism (castOptic -> fp) (castOptic -> rp) m enc =
  toPrism_ . cpmap fp rp m (fromPrism_ . enc)
  where
    cpmap ::
      forall a b c d x y.
      Prism' b a ->
      Prism' c d ->
      (y -> x) ->
      (x -> Prism' a c) ->
      (y -> Prism' b d)
    cpmap p q f r x =
      p % r (f x) % q