{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- | -- Module : Data.Can.Optics -- Copyright : (c) 2020-2022 Emily Pillmore -- License : BSD-style -- -- Maintainer : Emily Pillmore -- Stability : Experimental -- Portability : FlexibleInstances, MPTC, Type Families, UndecideableInstances -- -- 'Prism's and 'Traversal's for the 'Can' datatype. -- module Data.Can.Optics ( -- * Isos _CanIso -- * Prisms , _Non , _One , _Eno , _Two -- * Traversals , oneing , enoing , twoed , twoing ) where import Data.Can import Optics.AffineTraversal import Optics.Each.Core import Optics.Iso import Optics.IxTraversal import Optics.Prism import Optics.Traversal -- ------------------------------------------------------------------- -- -- Isos -- | A 'Control.Lens.Iso' between a wedge coproduct and pointed coproduct. -- _CanIso :: Iso (Can a b) (Can c d) (Maybe a, Maybe b) (Maybe c, Maybe d) _CanIso = iso f g where f t = (canFst t, canSnd t) g (Nothing, Nothing) = Non g (Just a, Nothing) = One a g (Nothing, Just b) = Eno b g (Just a, Just b) = Two a b -- ------------------------------------------------------------------- -- -- Traversals -- | An 'AffineTraversal' of the first parameter, suitable for use -- with "Optics". -- oneing :: AffineTraversal (Can a c) (Can b c) a b oneing = atraversalVL $ \point f -> \case Non -> point Non One a -> One <$> f a Eno c -> point (Eno c) Two a c -> flip Two c <$> f a -- | An 'AffineTraversal' of the second parameter, suitable for use -- with "Optics". -- enoing :: AffineTraversal (Can a b) (Can a c) b c enoing = atraversalVL $ \point f -> \case Non -> point Non One a -> point (One a) Eno b -> Eno <$> f b Two a b -> Two a <$> f b -- | An 'AffineTraversal' of the pair, suitable for use -- with "Optics". -- -- /Note:/ cannot change type. -- twoed :: AffineTraversal' (Can a b) (a,b) twoed = atraversalVL $ \point f -> \case Non -> point Non One a -> point (One a) Eno b -> point (Eno b) Two a b -> uncurry Two <$> f (a,b) -- | A 'Traversal' of the pair ala 'both', suitable for use -- with "Optics". -- twoing :: Traversal (Can a a) (Can b b) a b twoing = traversalVL $ \f -> \case Non -> pure Non One a -> One <$> f a Eno a -> Eno <$> f a Two a b -> Two <$> f a <*> f b -- ------------------------------------------------------------------- -- -- Prisms -- | A 'Prism'' selecting the 'Non' constructor. -- -- /Note:/ cannot change type. -- _Non :: Prism' (Can a b) () _Non = prism (const Non) $ \case Non -> Right () One a -> Left (One a) Eno b -> Left (Eno b) Two a b -> Left (Two a b) -- | A 'Prism'' selecting the 'One' constructor. -- -- /Note:/ cannot change type. -- _One :: Prism' (Can a b) a _One = prism One $ \case Non -> Left Non One a -> Right a Eno b -> Left (Eno b) Two a b -> Left (Two a b) -- | A 'Prism'' selecting the 'Eno' constructor. -- -- /Note:/ cannot change type. -- _Eno :: Prism' (Can a b) b _Eno = prism Eno $ \case Non -> Left Non One a -> Left (One a) Eno b -> Right b Two a b -> Left (Two a b) -- | A 'Prism'' selecting the 'Two' constructor. -- -- /Note:/ cannot change type. -- _Two :: Prism' (Can a b) (a,b) _Two = prism (uncurry Two) $ \case Non -> Left Non One a -> Left (One a) Eno b -> Left (Eno b) Two a b -> Right (a,b) -- ------------------------------------------------------------------- -- -- Orphans instance Swapped Can where swapped = iso swapCan swapCan instance (a ~ a', b ~ b') => Each Bool (Can a a') (Can b b') a b where each = itraversalVL $ \f -> \case Non -> pure Non One a -> One <$> f True a Eno a -> Eno <$> f False a Two a b -> Two <$> f True a <*> f False b