valuations-0.0.3: src/Data/Valuation/ProjectValuation.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wall -Werror #-}
-- | A projection function that updates a value given a set of variables.
module Data.Valuation.ProjectValuation
( ProjectValuation (..),
ProjectValuation',
SetProjectValuation,
-- * optics
HasProjectValuation (..),
AsProjectValuation (..),
-- * combinators
semigroupProjectValuation,
applyHasProjectValuation,
applyAsProjectValuation,
)
where
import Control.Category (Category (..))
import Control.Lens
( Lens',
Prism',
Rewrapped,
Wrapped (..),
iso,
review,
_Wrapped,
)
import Data.Functor.Contravariant (Contravariant (..))
import Data.Functor.Contravariant.Conclude (Conclude (..))
import Data.Functor.Contravariant.Decide (Decide (..))
import Data.Functor.Contravariant.Divise (Divise (..))
import Data.Functor.Contravariant.Divisible (Decidable (..), Divisible (..))
import Data.Profunctor (Profunctor (..), Strong (..))
import Data.Semigroupoid (Semigroupoid (..))
import Data.Set (Set)
import Data.Valuation.Semigroup
( Semigroup',
applySemigroup,
runSemigroup,
)
import Witherable (Filterable (mapMaybe))
import Prelude hiding (Semigroup, id, (.))
import qualified Prelude
-- $setup
-- >>> :set -Wno-name-shadowing -Wno-type-defaults
-- >>> import Data.Void (Void)
-- |
-- >>> let ProjectValuation f = ProjectValuation (\s v -> v + sum s) in f [1,2,3] (10 :: Int)
-- 16
--
-- >>> let ProjectValuation f = ProjectValuation (\s v -> v + length s) in f [1,2,3] (10 :: Int)
-- 13
newtype ProjectValuation p v set var
= ProjectValuation (p (set var) (p v v))
type ProjectValuation' v set var =
ProjectValuation (->) v set var
instance
(ProjectValuation p v set var ~ t) =>
Rewrapped (ProjectValuation p' v' set' var') t
instance Wrapped (ProjectValuation p v set var) where
type Unwrapped (ProjectValuation p v set var) = p (set var) (p v v)
_Wrapped' = iso (\(ProjectValuation x) -> x) ProjectValuation
-- | Classy lens for types that contain a 'ProjectValuation'.
class HasProjectValuation c p v set var | c -> p v set var where
projectValuation :: Lens' c (ProjectValuation p v set var)
instance HasProjectValuation (ProjectValuation p v set var) p v set var where
projectValuation = id
-- | Classy prism for types that can be constructed from a 'ProjectValuation'.
class AsProjectValuation c p v set var | c -> p v set var where
_ProjectValuation :: Prism' c (ProjectValuation p v set var)
instance AsProjectValuation (ProjectValuation p v set var) p v set var where
_ProjectValuation = id
-- | Lens to the underlying function of a 'HasProjectValuation'.
applyHasProjectValuation :: (HasProjectValuation pv p v set var) => Lens' pv (p (set var) (p v v))
applyHasProjectValuation = projectValuation . _Wrapped
-- | Prism to the underlying function of an 'AsProjectValuation'.
applyAsProjectValuation :: (AsProjectValuation pv p v set var) => Prism' pv (p (set var) (p v v))
applyAsProjectValuation = _ProjectValuation . _Wrapped
-- |
-- >>> import Data.Functor.Contravariant (contramap)
-- >>> let pv = ProjectValuation (\s v -> v + sum s) :: ProjectValuation (->) Int [] Int
-- >>> let ProjectValuation f = contramap (*2) pv in f [1,2,3] 10
-- 22
--
-- >>> import Data.Functor.Contravariant (contramap)
-- >>> let pv = ProjectValuation (\s v -> v + sum s) :: ProjectValuation (->) Int [] Int
-- >>> let ProjectValuation f = contramap negate pv in f [1,2,3] 0
-- -6
instance (Functor set, Profunctor p) => Contravariant (ProjectValuation p v set) where
contramap f (ProjectValuation g) = ProjectValuation (lmap (fmap f) g)
-- |
-- >>> import Data.Functor.Contravariant.Divisible (conquer, divide)
-- >>> let ProjectValuation f = conquer :: ProjectValuation (->) Int [] Int in f [1,2,3] 42
-- 42
--
-- >>> import Data.Functor.Contravariant.Divisible (conquer, divide)
-- >>> let ProjectValuation f = conquer :: ProjectValuation (->) String [] Char in f "abc" "hello"
-- "hello"
--
-- >>> import Data.Functor.Contravariant.Divisible (conquer, divide)
-- >>> let pvB = ProjectValuation (\s v -> v + sum s) :: ProjectValuation (->) Int [] Int
-- >>> let pvC = ProjectValuation (\s v -> v * length s) :: ProjectValuation (->) Int [] Int
-- >>> let ProjectValuation f = divide (\x -> (x, x * 10)) pvB pvC in f [1,2,3] 5
-- 21
--
-- >>> import Data.Functor.Contravariant.Divisible (conquer, divide)
-- >>> let pvB = ProjectValuation (\s v -> v + sum s) :: ProjectValuation (->) Int [] Int
-- >>> let pvC = ProjectValuation (\s v -> v * length s) :: ProjectValuation (->) Int [] Int
-- >>> let ProjectValuation f = divide (\x -> (x, x)) pvB pvC in f [1,2,3] 5
-- 21
instance (Functor set, Strong p, Category p) => Divisible (ProjectValuation p v set) where
conquer = ProjectValuation (rmap (const id) id)
divide split (ProjectValuation pb) (ProjectValuation pc) =
let pb' = lmap (fmap (fst . split)) pb
pc' = lmap (fmap (snd . split)) pc
in ProjectValuation (lmap (\x -> (x, x)) (rmap (uncurry (.)) (second' pc' . first' pb')))
-- |
-- >>> import Data.Functor.Contravariant.Divisible (choose, lose)
-- >>> import Data.Void (Void, absurd)
-- >>> let ProjectValuation f = lose absurd :: ProjectValuation (->) Int [] Void in f [] 42
-- 42
--
-- >>> import Data.Functor.Contravariant.Divisible (choose)
-- >>> let pvB = ProjectValuation (\s v -> v + sum s) :: ProjectValuation (->) Int [] Int
-- >>> let pvC = ProjectValuation (\s v -> v * length s) :: ProjectValuation (->) Int [] Int
-- >>> let ProjectValuation f = choose (\x -> if even x then Left x else Right x) pvB pvC in f [1,2,3,4] 10
-- 26
--
-- >>> import Data.Functor.Contravariant.Divisible (choose)
-- >>> let pvB = ProjectValuation (\s v -> v + sum s) :: ProjectValuation (->) Int [] Int
-- >>> let pvC = ProjectValuation (\s v -> v * length s) :: ProjectValuation (->) Int [] Int
-- >>> let ProjectValuation f = choose Left pvB pvC in f [1,2,3] 10
-- 6
--
-- >>> import Data.Functor.Contravariant.Divisible (choose)
-- >>> let pvB = ProjectValuation (\s v -> v + sum s) :: ProjectValuation (->) Int [] Int
-- >>> let pvC = ProjectValuation (\s v -> v * length s) :: ProjectValuation (->) Int [] Int
-- >>> let ProjectValuation f = choose Right pvB pvC in f [1,2,3] 10
-- 30
instance (Filterable set, Strong p, Category p) => Decidable (ProjectValuation p v set) where
lose _ = ProjectValuation (rmap (const id) id)
choose ch (ProjectValuation pb) (ProjectValuation pc) =
let pb' = lmap (mapMaybe (either Just (const Nothing) . ch)) pb
pc' = lmap (mapMaybe (either (const Nothing) Just . ch)) pc
in ProjectValuation (lmap (\x -> (x, x)) (rmap (uncurry (.)) (second' pc' . first' pb')))
-- |
-- >>> import Data.Functor.Contravariant.Divise (divise)
-- >>> let pvB = ProjectValuation (\s v -> v + sum s) :: ProjectValuation (->) Int [] Int
-- >>> let pvC = ProjectValuation (\s v -> v * length s) :: ProjectValuation (->) Int [] Int
-- >>> let ProjectValuation f = divise (\x -> (x, x * 10)) pvB pvC in f [1,2,3] 5
-- 21
instance (Functor set, Strong p, Semigroupoid p) => Divise (ProjectValuation p v set) where
divise split (ProjectValuation pb) (ProjectValuation pc) =
let pb' = lmap (fmap (fst . split)) pb
pc' = lmap (fmap (snd . split)) pc
in ProjectValuation (lmap (\x -> (x, x)) (rmap (uncurry o) (second' pc' `o` first' pb')))
-- |
-- >>> import Data.Functor.Contravariant.Decide (decide)
-- >>> let pvB = ProjectValuation (\s v -> v + sum s) :: ProjectValuation (->) Int [] Int
-- >>> let pvC = ProjectValuation (\s v -> v * length s) :: ProjectValuation (->) Int [] Int
-- >>> let ProjectValuation f = decide (\x -> if even x then Left x else Right x) pvB pvC in f [1,2,3,4] 10
-- 26
instance (Filterable set, Strong p, Semigroupoid p) => Decide (ProjectValuation p v set) where
decide ch (ProjectValuation pb) (ProjectValuation pc) =
let pb' = lmap (mapMaybe (either Just (const Nothing) . ch)) pb
pc' = lmap (mapMaybe (either (const Nothing) Just . ch)) pc
in ProjectValuation (lmap (\x -> (x, x)) (rmap (uncurry o) (second' pc' `o` first' pb')))
-- |
-- >>> import Data.Functor.Contravariant.Conclude (conclude)
-- >>> import Data.Void (absurd)
-- >>> let ProjectValuation f = conclude absurd :: ProjectValuation (->) Int [] Void in f [] 42
-- 42
instance (Filterable set, Strong p, Semigroupoid p, Category p) => Conclude (ProjectValuation p v set) where
conclude _ = ProjectValuation (rmap (const id) id)
-- |
-- >>> let ProjectValuation f = runSemigroup semigroupProjectValuation (ProjectValuation (\_ v -> v + 1)) (ProjectValuation (\_ v -> v * 2)) in f [] (3 :: Int)
-- 7
semigroupProjectValuation :: Semigroup' (ProjectValuation (->) v set var)
semigroupProjectValuation = review applySemigroup (\(ProjectValuation p1) (ProjectValuation p2) -> ProjectValuation (\s -> p1 s . p2 s))
-- |
-- >>> let p1 = ProjectValuation (\s v -> v + sum s) :: ProjectValuation (->) Int [] Int
-- >>> let p2 = ProjectValuation (\s v -> v * length s) :: ProjectValuation (->) Int [] Int
-- >>> let ProjectValuation f = p1 <> p2 in f [1,2,3] 5
-- 21
instance Prelude.Semigroup (ProjectValuation (->) v set var) where
(<>) = runSemigroup semigroupProjectValuation
-- |
-- >>> let p = ProjectValuation (\s v -> v + sum s) :: ProjectValuation (->) Int [] Int
-- >>> let ProjectValuation f = mempty <> p in f [1,2,3] 5
-- 11
instance Monoid (ProjectValuation (->) v set var) where
mempty = ProjectValuation (const id)
-- | A 'ProjectValuation' specialised to 'Set'.
type SetProjectValuation p v var =
ProjectValuation p v Set var