packages feed

casa-reoc-0.1.0.0: src/ReOC/Data/RiskLevel.hs

{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wall #-}
-- The checks of inheritance (inheritRiskLevel) have a constraint that their body does not use, by design.
{-# OPTIONS_GHC -Wno-redundant-constraints #-}

-- | The data type @RiskLevel@: the level of a risk, given by the risk rating matrix (operations manual Appendix E, Table 12).
module ReOC.Data.RiskLevel (
  RiskLevel (..),
  RiskLevelLike (..),
  lawNamesRiskLevel,
  InheritRiskLevel,
  inheritRiskLevel,
) where

import Control.Lens (Choice, Optic, prism', review)
import Data.Functor.Const (Const)
import ReOC.Name.High (HighLike (..))
import ReOC.Name.Low (LowLike (..))
import ReOC.Name.Medium (MediumLike (..))

-- | The level of a risk, given by the risk rating matrix (operations manual Appendix E, Table 12).
data RiskLevel
  = High
  | Medium
  | Low
  deriving (Eq, Ord, Show)

-- | The name of the data type @RiskLevel@.
class RiskLevelLike p f x x' where
  riskLevel ::
    Optic p f x x' RiskLevel RiskLevel

-- | Identity
instance (x' ~ RiskLevel) => RiskLevelLike p f RiskLevel x' where
  riskLevel = id

-- | Prism
instance (Choice p, Applicative f, x' ~ RiskLevel) => HighLike p f RiskLevel x' where
  high = prism' (\() -> High) (\case High -> Just (); Medium -> Nothing; Low -> Nothing)

-- | Prism
instance (Choice p, Applicative f, x' ~ RiskLevel) => MediumLike p f RiskLevel x' where
  medium = prism' (\() -> Medium) (\case High -> Nothing; Medium -> Just (); Low -> Nothing)

-- | Prism
instance (Choice p, Applicative f, x' ~ RiskLevel) => LowLike p f RiskLevel x' where
  low = prism' (\() -> Low) (\case High -> Nothing; Medium -> Nothing; Low -> Just ())

{- | Rebuilds a value from the name of each field or constructor.

Laws:

> lawNamesRiskLevel == id
-}
lawNamesRiskLevel :: RiskLevel -> RiskLevel
lawNamesRiskLevel = \case
  High -> review high ()
  Medium -> review medium ()
  Low -> review low ()

-- | The classes that a data type holding @RiskLevel@ in one field, or in one or more constructors, inherits.
type InheritRiskLevel s =
  ( RiskLevelLike (->) (Const ()) s s
  , HighLike (->) (Const ()) s s
  , MediumLike (->) (Const ()) s s
  , LowLike (->) (Const ()) s s
  )

-- | Checks that a data type inherits every class of @InheritRiskLevel@.
inheritRiskLevel :: (InheritRiskLevel s) => proxy s -> ()
inheritRiskLevel _ = ()