packages feed

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

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

-- | The data type @Consequence@: the consequence of a risk (operations manual Appendix E, Table 10).
module ReOC.Data.Consequence (
  Consequence (..),
  ConsequenceLike (..),
  lawNamesConsequence,
  InheritConsequence,
  inheritConsequence,
) where

import Control.Lens (Choice, Optic, prism', review)
import Data.Functor.Const (Const)
import ReOC.Name.Catastrophic (CatastrophicLike (..))
import ReOC.Name.Hazardous (HazardousLike (..))
import ReOC.Name.Minor (MinorLike (..))
import ReOC.Name.Moderate (ModerateLike (..))
import ReOC.Name.Negligible (NegligibleLike (..))

-- | The consequence of a risk (operations manual Appendix E, Table 10).
data Consequence
  = Catastrophic
  | Hazardous
  | Moderate
  | Minor
  | Negligible
  deriving (Eq, Ord, Show)

-- | The name of the data type @Consequence@.
class ConsequenceLike p f x x' where
  consequence ::
    Optic p f x x' Consequence Consequence

-- | Identity
instance (x' ~ Consequence) => ConsequenceLike p f Consequence x' where
  consequence = id

-- | Prism
instance (Choice p, Applicative f, x' ~ Consequence) => CatastrophicLike p f Consequence x' where
  catastrophic = prism' (\() -> Catastrophic) (\case Catastrophic -> Just (); Hazardous -> Nothing; Moderate -> Nothing; Minor -> Nothing; Negligible -> Nothing)

-- | Prism
instance (Choice p, Applicative f, x' ~ Consequence) => HazardousLike p f Consequence x' where
  hazardous = prism' (\() -> Hazardous) (\case Catastrophic -> Nothing; Hazardous -> Just (); Moderate -> Nothing; Minor -> Nothing; Negligible -> Nothing)

-- | Prism
instance (Choice p, Applicative f, x' ~ Consequence) => ModerateLike p f Consequence x' where
  moderate = prism' (\() -> Moderate) (\case Catastrophic -> Nothing; Hazardous -> Nothing; Moderate -> Just (); Minor -> Nothing; Negligible -> Nothing)

-- | Prism
instance (Choice p, Applicative f, x' ~ Consequence) => MinorLike p f Consequence x' where
  minor = prism' (\() -> Minor) (\case Catastrophic -> Nothing; Hazardous -> Nothing; Moderate -> Nothing; Minor -> Just (); Negligible -> Nothing)

-- | Prism
instance (Choice p, Applicative f, x' ~ Consequence) => NegligibleLike p f Consequence x' where
  negligible = prism' (\() -> Negligible) (\case Catastrophic -> Nothing; Hazardous -> Nothing; Moderate -> Nothing; Minor -> Nothing; Negligible -> Just ())

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

Laws:

> lawNamesConsequence == id
-}
lawNamesConsequence :: Consequence -> Consequence
lawNamesConsequence = \case
  Catastrophic -> review catastrophic ()
  Hazardous -> review hazardous ()
  Moderate -> review moderate ()
  Minor -> review minor ()
  Negligible -> review negligible ()

-- | The classes that a data type holding @Consequence@ in one field, or in one or more constructors, inherits.
type InheritConsequence s =
  ( ConsequenceLike (->) (Const ()) s s
  , CatastrophicLike (->) (Const ()) s s
  , HazardousLike (->) (Const ()) s s
  , ModerateLike (->) (Const ()) s s
  , MinorLike (->) (Const ()) s s
  , NegligibleLike (->) (Const ()) s s
  )

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