packages feed

rerefined-0.3.0: src/Rerefined/Predicate/Logical/And.hs

{-# LANGUAGE UndecidableInstances #-} -- for easier PredicateName
{-# LANGUAGE OverloadedStrings #-} -- for builder

module Rerefined.Predicate.Logical.And where

import Rerefined.Predicate.Common.Binary
import Rerefined.Predicate.Common
import Rerefined.Refine.Unsafe
import Rerefined.Refined

-- | Logical conjunction. Also AND logic gate.
data And l r

-- | Precendence of 3 (matching 'Data.Bool.&&').
instance (Predicate l, Predicate r) => Predicate (And l r) where
    type PredicateName d (And l r) = PredicateNameBOp " ∧ " 3 d l r

instance (Refine l a, Refine r a, KnownPredicateName (And l r))
  => Refine (And l r) a where
    validate p a =
        case l of
          Nothing ->
            case r of
              Nothing -> Nothing
              Just er -> validateFail p "AND:  right failed"    [er    ]
          Just el ->
            case r of
              Nothing -> validateFail p "AND:   left failed"    [    el]
              Just er -> validateFail p "AND:    l&r failed"    [er, el]
      where
        l = validate (proxy# @l) a
        r = validate (proxy# @r) a

-- | Take just the left predicate from an 'And'.
rerefineAndL :: Refined (And l r) a -> Refined l a
rerefineAndL = unsafeRerefine

-- | Take just the right predicate from an 'And'.
rerefineAndR :: Refined (And l r) a -> Refined r a
rerefineAndR = unsafeRerefine

-- | Eliminate an 'And' by applying the left predicate, then the right.
eliminateAndLR :: Refined (And l r) a -> Refined r (Refined l a)
eliminateAndLR = unsafeRefine . unsafeRefine . unrefine

-- | Eliminate an 'And' by applying the right predicate, then the left.
eliminateAndRL :: Refined (And l r) a -> Refined l (Refined r a)
eliminateAndRL = unsafeRefine . unsafeRefine . unrefine

-- | Introduce an 'And' given a double-'Refined'. Inner is left.
introduceAndLR :: Refined r (Refined l a) -> Refined (And l r) a
introduceAndLR = unsafeRefine . unrefine . unrefine

-- | Introduce an 'And' given a double-'Refined'. Inner is right.
introduceAndRL :: Refined l (Refined r a) -> Refined (And l r) a
introduceAndRL = unsafeRefine . unrefine . unrefine