packages feed

logical-constraints-0.1.3.0: Logical/OrdConstraints.hs

{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_HADDOCK show-extensions #-}

-- |
-- Module      :  Logical.OrdConstraints
-- Copyright   :  (c) Oleksandr Zhabenko 2022-2023
-- License     :  MIT
-- Stability   :  Experimental
-- Maintainer  :  oleksandr.zhabenko@yahoo.com
--
-- Some simple logical encoding 'syntactical sugar' to represent point-wise or intervals-based logics.
-- If you would like to use data types not in the functions of the module  imported, but in your
-- own ones, please, consider using before the 'validOrdCs' function for them. If you use just
-- the functions defined here, you do not need to use it before because it is used internally.

module Logical.OrdConstraints where

import Control.Exception
import Data.Foldable (Foldable, any)
import GHC.Base hiding (O)
import GHC.List hiding (any)
import Text.Show 
import Text.Read
import GHC.Real (rem)
import Data.Maybe (fromMaybe)

-- | Data type to encode the simple logical contstraints for some 'Ord'ered data type value to be kept in some bounds (to lay in some intervals or points). 'O' constructor  encodes
-- point-wise logics, and 'C' encodes intervals logics.
data OrdConstraints a = O [a] | C [a] deriving (Eq, Ord, Show, Read)

-- | Primary intention: the @t@ here refers to 'Foldable' @t@.
type OrdCs t a = t (OrdConstraints a)

-- | The predicate to check whether the data is  encoded logically correct just enough to be used by the functions in the library (minimal necessary validation). Checks whether 
-- at least just one point or interval is set.
validOrdCs :: Ord a =>  OrdConstraints a -> Bool
validOrdCs (O (_:_)) = True
validOrdCs (C xs@(_:_:_)) = (length xs `rem` 2) == 0
validOrdCs _ = False

ordCs2Predicate1 :: Ord a => OrdConstraints a -> a -> Bool
ordCs2Predicate1 x@(O xs) y
 | validOrdCs x = any (== y) xs
 | otherwise = error "Logical.OrdConstraints.ordCs2Predicate1: Not valid logical constraint by constrution semantics."
ordCs2Predicate1 x@(C xs) y
 | validOrdCs x = any (\(t:u:_) -> y >= t && y <= u) . f $ xs
 | otherwise = error "Logical.OrdConstraints.ordCs2Predicate1: Not valid logical constraint by constrution semantics." 
    where f (x:y:xs) = [x,y]:f xs
          f [] = []

ordCs2HPred1 :: (Ord a, Foldable t1) => OrdCs t1 a -> a -> Bool
ordCs2HPred1 cs y = any (\c -> ordCs2Predicate1 c y) $ cs

-- | Just the head of the list is used. Therefore, is intended to be used mainly with the singleton list as the second argument.
ordCs2Predicate :: Ord a => OrdConstraints a -> [a] -> Bool
ordCs2Predicate x ys
 | null ys = False
 | otherwise = ordCs2Predicate1 x (head ys)
{-# INLINE ordCs2Predicate #-}

-- | Just the head of the list is used. Therefore, is intended to be used mainly with the singleton list as the second argument.
ordCs2HPred :: (Ord a, Foldable t1) => OrdCs t1 a -> [a] -> Bool
ordCs2HPred cs ys 
 | null ys = False
 | otherwise = any (\c -> ordCs2Predicate1 c (head ys)) $ cs

ordCs2PredicateG :: (Ord a, Foldable t) => OrdConstraints a -> (t a -> Maybe a) -> t a -> Bool
ordCs2PredicateG x@(O xs) p ys
 | validOrdCs x = any (\k -> (fromMaybe False . fmap (== k) . p $ ys)) xs
 | otherwise = error "Logical.OrdConstraints.ordCs2PredicateG: Not valid logical constraint by constrution semantics."
ordCs2PredicateG x@(C xs) p ys
 | validOrdCs x = any (\(t:u:_) -> fromMaybe False . fmap (\k -> k >= t && k <= u) . p $ ys) . f $ xs
 | otherwise = error "Logical.OrdConstraints.ordCs2PredicateG: Not valid logical constraint by constrution semantics."
    where f (x:y:xs) = [x,y]:f xs
          f [] = []

ordCs2HPredG :: (Ord a, Foldable t, Foldable t1) => OrdCs t1 a -> (t a -> Maybe a) -> t a -> Bool
ordCs2HPredG cs p ys = any (\c -> ordCs2PredicateG c p ys) $ cs