packages feed

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

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

-- | The data type @Declaration'@: who makes the declaration, and in what capacity (CASA Form 101-02, questions 31 and 32).
module ReOC.Data.Declaration (
  Declaration' (..),
  Declaration'Like (..),
  lawNamesDeclaration',
  Declaration,
  UnfilledDeclaration,
  InheritDeclaration',
  inheritDeclaration',
) where

import Control.Lens (Choice, Optic, prism, prism', review)
import Data.Functor.Const (Const)
import Data.Text (Text)
import ReOC.Data.Declarant (Declarant, UnfilledDeclarant)
import ReOC.Name.DeclaredByAgent (DeclaredByAgentLike (..))
import ReOC.Name.DeclaredByCEO (DeclaredByCEOLike (..))
import ReOC.Name.DeclaredByOther (DeclaredByOtherLike (..))
import ReOC.Name.DeclaredByResponsibleManager (DeclaredByResponsibleManagerLike (..))
import ReOC.Primitive.FormText (FormLine)

-- | Who makes the declaration, and in what capacity (CASA Form 101-02, questions 31 and 32). Its valid form is @Declaration@, and its unfilled form @UnfilledDeclaration@.
data Declaration' a1 a2 a3
  = DeclaredByCEO
  | DeclaredByResponsibleManager a1
  | DeclaredByAgent a2
  | DeclaredByOther a3
  deriving (Eq, Ord, Show)

-- | The name of the data type @Declaration'@.
class Declaration'Like p f x x' a1 a1' a2 a2' a3 a3' | x -> a1 a2 a3 where
  declaration' ::
    Optic p f x x' (Declaration' a1 a2 a3) (Declaration' a1' a2' a3')

-- | Identity
instance (x' ~ Declaration' a1' a2' a3') => Declaration'Like p f (Declaration' a1 a2 a3) x' a1 a1' a2 a2' a3 a3' where
  declaration' = id

-- | Prism
instance (Choice p, Applicative f, x' ~ Declaration' a1 a2 a3) => DeclaredByCEOLike p f (Declaration' a1 a2 a3) x' where
  declaredByCEO = prism' (\() -> DeclaredByCEO) (\case DeclaredByCEO -> Just (); DeclaredByResponsibleManager _ -> Nothing; DeclaredByAgent _ -> Nothing; DeclaredByOther _ -> Nothing)

-- | Prism
instance (Choice p, Applicative f, x' ~ Declaration' a1' a2 a3) => DeclaredByResponsibleManagerLike p f (Declaration' a1 a2 a3) x' a1 a1' where
  declaredByResponsibleManager = prism DeclaredByResponsibleManager (\case DeclaredByCEO -> Left DeclaredByCEO; DeclaredByResponsibleManager x -> Right x; DeclaredByAgent x -> Left (DeclaredByAgent x); DeclaredByOther x -> Left (DeclaredByOther x))

-- | Prism
instance (Choice p, Applicative f, x' ~ Declaration' a1 a2' a3) => DeclaredByAgentLike p f (Declaration' a1 a2 a3) x' a2 a2' where
  declaredByAgent = prism DeclaredByAgent (\case DeclaredByCEO -> Left DeclaredByCEO; DeclaredByResponsibleManager x -> Left (DeclaredByResponsibleManager x); DeclaredByAgent x -> Right x; DeclaredByOther x -> Left (DeclaredByOther x))

-- | Prism
instance (Choice p, Applicative f, x' ~ Declaration' a1 a2 a3') => DeclaredByOtherLike p f (Declaration' a1 a2 a3) x' a3 a3' where
  declaredByOther = prism DeclaredByOther (\case DeclaredByCEO -> Left DeclaredByCEO; DeclaredByResponsibleManager x -> Left (DeclaredByResponsibleManager x); DeclaredByAgent x -> Left (DeclaredByAgent x); DeclaredByOther x -> Right x)

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

Laws:

> lawNamesDeclaration' == id
-}
lawNamesDeclaration' :: Declaration' a1 a2 a3 -> Declaration' a1 a2 a3
lawNamesDeclaration' = \case
  DeclaredByCEO -> review declaredByCEO ()
  DeclaredByResponsibleManager x -> review declaredByResponsibleManager x
  DeclaredByAgent x -> review declaredByAgent x
  DeclaredByOther x -> review declaredByOther x

-- | A valid @Declaration'@.
type Declaration = Declaration' FormLine FormLine Declarant

-- | An unfilled @Declaration'@: each field holds what has been entered, if anything, to be checked by @fillDeclaration@.
type UnfilledDeclaration = Declaration' (Maybe Text) (Maybe Text) UnfilledDeclarant

-- | The classes that a data type holding @Declaration'@ in one field, or in one or more constructors, inherits.
type InheritDeclaration' s a1 a2 a3 =
  ( Declaration'Like (->) (Const ()) s s a1 a1 a2 a2 a3 a3
  , DeclaredByCEOLike (->) (Const ()) s s
  , DeclaredByResponsibleManagerLike (->) (Const ()) s s a1 a1
  , DeclaredByAgentLike (->) (Const ()) s s a2 a2
  , DeclaredByOtherLike (->) (Const ()) s s a3 a3
  )

-- | Checks that a data type inherits every class of @InheritDeclaration'@.
inheritDeclaration' :: (InheritDeclaration' s a1 a2 a3) => proxy s -> ()
inheritDeclaration' _ = ()