packages feed

mixed-types-num-0.5.0.2: src/Numeric/MixedTypes/Kleenean.hs

{-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE DeriveGeneric #-}
{-|
    Module      :  Numeric.MixedType.Kleenean
    Description :  Three-valued logic
    Copyright   :  (c) Michal Konecny
    License     :  BSD3

    Maintainer  :  mikkonecny@gmail.com
    Stability   :  experimental
    Portability :  portable

-}
module Numeric.MixedTypes.Kleenean
(
    Kleenean(..), kleenean, tKleenean
)
where

import Numeric.MixedTypes.PreludeHiding
import qualified Prelude as P

import Test.SmallCheck.Series
import GHC.Generics

import Numeric.MixedTypes.Literals
    ( ConvertibleExactly(..), convertExactly, T(T) )
import Numeric.MixedTypes.Bool
    ( (&&),
      not,
      CanAndOrAsymmetric(..),
      CanNeg(negate),
      CanTestCertainly(..),
      and )

tKleenean :: T Kleenean
tKleenean = T "Kleenean"

data Kleenean = CertainTrue | CertainFalse | TrueOrFalse
  deriving (P.Eq, Show, Generic)

instance Serial IO Kleenean

type CanBeKleenean t = ConvertibleExactly t Kleenean
kleenean :: (CanBeKleenean t) => t -> Kleenean
kleenean = convertExactly

instance ConvertibleExactly Kleenean Kleenean where
  safeConvertExactly = Right

instance ConvertibleExactly Bool Kleenean where
  safeConvertExactly True = Right CertainTrue
  safeConvertExactly False = Right CertainFalse

instance CanTestCertainly Kleenean where
  isCertainlyTrue = (P.== CertainTrue)
  isCertainlyFalse = (P.== CertainFalse)

instance CanNeg Kleenean where
  negate CertainTrue = CertainFalse
  negate CertainFalse = CertainTrue
  negate TrueOrFalse = TrueOrFalse

_testNeg1 :: Kleenean
_testNeg1 = not CertainTrue

instance CanAndOrAsymmetric Kleenean Kleenean
  where
  type AndOrType Kleenean Kleenean = Kleenean
  and2 CertainTrue CertainTrue = CertainTrue
  and2 CertainFalse _ = CertainFalse
  and2 _ CertainFalse = CertainFalse
  and2 _ _ = TrueOrFalse
  or2 CertainFalse CertainFalse = CertainFalse
  or2 CertainTrue _ = CertainTrue
  or2 _ CertainTrue = CertainTrue
  or2 _ _ = TrueOrFalse

instance CanAndOrAsymmetric Bool Kleenean
  where
  type AndOrType Bool Kleenean = Kleenean
  and2 b = and2 (kleenean b)
  or2 b = or2 (kleenean b)

instance CanAndOrAsymmetric Kleenean Bool
  where
  type AndOrType Kleenean Bool = Kleenean
  and2 k b = and2 k (kleenean b)
  or2 k b = or2 k (kleenean b)

_testAndOr1 :: Kleenean
_testAndOr1 = TrueOrFalse && False

_testAndOr2 :: Kleenean
_testAndOr2 = and [CertainTrue, TrueOrFalse, CertainFalse]