module Pandora.Paradigm.Primary.Functor.Predicate where

import Pandora.Core.Functor (type (|->))
import Pandora.Core.Morphism ((!))
import Pandora.Pattern.Category ((.), ($))
import Pandora.Pattern.Functor.Contravariant (Contravariant ((>$<)))
import Pandora.Pattern.Functor.Determinable (Determinable (determine))
import Pandora.Pattern.Functor.Pointable (Pointable (point))
import Pandora.Pattern.Functor.Avoidable (Avoidable (empty))
import Pandora.Pattern.Object.Setoid (Setoid ((==)))
import Pandora.Paradigm.Primary.Object.Boolean (Boolean (True), (?))

newtype Predicate a = Predicate (a -> Boolean)

instance Contravariant Predicate where
	a -> b
f >$< :: (a -> b) -> Predicate b -> Predicate a
>$< Predicate b -> Boolean
g = (a -> Boolean) -> Predicate a
forall a. (a -> Boolean) -> Predicate a
Predicate ((a -> Boolean) -> Predicate a) -> (a -> Boolean) -> Predicate a
forall (m :: * -> * -> *) a b. Category m => m a b -> m a b
$ b -> Boolean
g (b -> Boolean) -> (a -> b) -> a -> Boolean
forall (m :: * -> * -> *) b c a.
Category m =>
m b c -> m a b -> m a c
. a -> b
f

instance Determinable Predicate where
	determine :: Predicate a
determine = (a -> Boolean) -> Predicate a
forall a. (a -> Boolean) -> Predicate a
Predicate (Boolean
True Boolean -> a -> Boolean
forall a b. a -> b -> a
!)

equate :: Setoid a => a |-> Predicate
equate :: a |-> Predicate
equate a
x = (a -> Boolean) -> Predicate a
forall a. (a -> Boolean) -> Predicate a
Predicate (a -> a -> Boolean
forall a. Setoid a => a -> a -> Boolean
== a
x)

satisfy :: (Pointable t, Avoidable t) => Predicate a -> a -> t a
satisfy :: Predicate a -> a -> t a
satisfy (Predicate a -> Boolean
p) a
x = a -> Boolean
p a
x Boolean -> t a -> t a -> t a
forall a. Boolean -> a -> a -> a
? a -> t a
forall (t :: * -> *) a. Pointable t => a |-> t
point a
x (t a -> t a) -> t a -> t a
forall (m :: * -> * -> *) a b. Category m => m a b -> m a b
$ t a
forall (t :: * -> *) a. Avoidable t => t a
empty