Skip to main content

Predicate

Struct Predicate 

Source
pub struct Predicate<A> { /* private fields */ }
Expand description

An intensional set, defined by a predicate function.

A Predicate<A> wraps a function that determines whether a value of type A satisfies some condition. Predicates can be combined using logical operations like AND, OR, NOT, and difference.

Implementations§

Source§

impl<A> Predicate<A>

Source

pub fn new<F>(f: F) -> Self
where F: Fn(&A) -> bool + 'static,

Create a new predicate from a closure.

§Parameters
  • f: A function that evaluates whether a value of type A satisfies the predicate.
§Returns

A new Predicate<A> wrapping the provided function.

§Example
use rustica::datatypes::wrapper::predicate::Predicate;

let is_even = Predicate::new(|x: &i32| *x % 2 == 0);
assert!(is_even.contains(&2));
assert!(!is_even.contains(&3));
§Performance
  • Time Complexity: O(1) - Simply wraps the function in an Rc
  • Memory Usage: O(1) - Stores a single Rc pointer to the function
Source

pub fn contains(&self, a: &A) -> bool

Returns true if the value satisfies the predicate.

§Arguments
  • a - The value to test against the predicate
§Returns

true if the value satisfies the predicate; false otherwise.

§Examples
use rustica::datatypes::wrapper::predicate::Predicate;

let is_positive = Predicate::new(|x: &i32| *x > 0);
assert!(is_positive.contains(&5));
assert!(!is_positive.contains(&-3));
§Performance
  • Time Complexity: O(f) where f is the complexity of the wrapped function
  • Memory Usage: O(1) - No additional memory allocated during evaluation
Source

pub fn union(&self, other: &Predicate<A>) -> Predicate<A>
where A: 'static,

Returns a predicate which is the union of this predicate and another.

The union predicate evaluates to true if either this predicate or the other predicate evaluates to true for a given input.

§Arguments
  • other - Another predicate to union with this one
§Returns

A new Predicate<A> representing the union of both predicates

§Examples
use rustica::datatypes::wrapper::predicate::Predicate;

let is_even = Predicate::new(|x: &i32| *x % 2 == 0);
let is_positive = Predicate::new(|x: &i32| *x > 0);
let even_or_positive = is_even.union(&is_positive);

assert!(even_or_positive.contains(&2));  // Even and positive
assert!(even_or_positive.contains(&-4)); // Even but not positive
assert!(even_or_positive.contains(&3));  // Positive but not even
assert!(!even_or_positive.contains(&-5)); // Neither even nor positive
§Performance
  • Time Complexity: O(1) for creation, O(f1 + f2) for evaluation where f1 and f2 are the complexities of the component predicates
  • Memory Usage: O(1) - Creates a new predicate with references to existing ones
  • Short-circuit Evaluation: Returns early if the first predicate evaluates to true
Source

pub fn intersection(&self, other: &Predicate<A>) -> Predicate<A>
where A: 'static,

Returns a predicate which is the intersection of this predicate and another.

The intersection predicate evaluates to true only if both this predicate and the other predicate evaluate to true for a given input.

§Arguments
  • other - Another predicate to intersect with this one
§Returns

A new Predicate<A> representing the intersection of both predicates

§Examples
use rustica::datatypes::wrapper::predicate::Predicate;

let is_even = Predicate::new(|x: &i32| *x % 2 == 0);
let is_positive = Predicate::new(|x: &i32| *x > 0);
let even_and_positive = is_even.intersection(&is_positive);

assert!(even_and_positive.contains(&2));  // Even and positive
assert!(!even_and_positive.contains(&-4)); // Even but not positive
assert!(!even_and_positive.contains(&3));  // Positive but not even
assert!(!even_and_positive.contains(&-5)); // Neither even nor positive
§Performance
  • Time Complexity: O(1) for creation, O(f1 + f2) for evaluation where f1 and f2 are the complexities of the component predicates
  • Memory Usage: O(1) - Creates a new predicate with references to existing ones
  • Short-circuit Evaluation: Returns early if the first predicate evaluates to false
Source

pub fn diff(&self, remove: &Predicate<A>) -> Predicate<A>
where A: 'static,

Returns a predicate which is the set difference of this predicate and another.

The resulting predicate evaluates to true for inputs that satisfy this predicate but do not satisfy the remove predicate.

§Arguments
  • remove - The predicate to subtract from this one
§Returns

A new Predicate<A> representing the set difference

§Examples
use rustica::datatypes::wrapper::predicate::Predicate;

let is_integer = Predicate::new(|x: &f64| x.fract() == 0.0);
let is_negative = Predicate::new(|x: &f64| *x < 0.0);
let positive_integers = is_integer.diff(&is_negative);

assert!(positive_integers.contains(&2.0));  // Integer and not negative
assert!(!positive_integers.contains(&-3.0)); // Integer but negative
assert!(!positive_integers.contains(&1.5));  // Not an integer
§Performance
  • Time Complexity: O(1) for creation, O(f1 + f2) for evaluation where f1 and f2 are the complexities of the component predicates
  • Memory Usage: O(1) - Creates a new predicate with references to existing ones
  • Short-circuit Evaluation: Returns early if the first predicate evaluates to false
Source

pub fn negate(&self) -> Predicate<A>
where A: 'static,

Returns a predicate that is the negation of this predicate.

The resulting predicate evaluates to true for inputs where this predicate evaluates to false, and vice versa.

§Returns

A new Predicate<A> representing the logical negation

§Examples
use rustica::datatypes::wrapper::predicate::Predicate;

let is_even = Predicate::new(|x: &i32| *x % 2 == 0);
let is_odd = is_even.negate();

assert!(!is_odd.contains(&2));
assert!(is_odd.contains(&3));
§Performance
  • Time Complexity: O(1) for creation, O(f) for evaluation where f is the complexity of the original predicate
  • Memory Usage: O(1) - Creates a new predicate with a reference to the existing one

Trait Implementations§

Source§

impl<A> BitAnd for Predicate<A>
where A: 'static,

Source§

type Output = Predicate<A>

The resulting type after applying the & operator.
Source§

fn bitand(self, rhs: Predicate<A>) -> Predicate<A>

Performs the & operation. Read more
Source§

impl<A> BitOr for Predicate<A>
where A: 'static,

Source§

type Output = Predicate<A>

The resulting type after applying the | operator.
Source§

fn bitor(self, rhs: Predicate<A>) -> Predicate<A>

Performs the | operation. Read more
Source§

impl<A: Clone> Clone for Predicate<A>

Source§

fn clone(&self) -> Predicate<A>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<A> HKT for Predicate<A>

Source§

type Output<B> = Predicate<B>

The same HKT but containing type NewType instead of Source.
Source§

type Source = A

The type contained in this HKT.
Source§

impl<A: 'static> Monoid for Predicate<A>

Source§

fn empty() -> Self

Returns the identity element for the combine operation: a predicate that always returns false.

This represents the empty set in set theory, which when unioned with any other set, yields that other set unchanged. Similarly, when this empty predicate is combined with any other predicate using combine (logical OR), the result is equivalent to the other predicate.

§Performance
  • Time Complexity: O(1) for both creation and evaluation
  • Memory Usage: Minimal, just stores an Rc to a trivial function
  • Evaluation: Always returns false regardless of input
§Type Class Laws
§Left Identity: empty().combine(a) = a
use rustica::datatypes::wrapper::predicate::Predicate;
use rustica::traits::monoid::Monoid;
use rustica::traits::semigroup::Semigroup;

let is_even = Predicate::new(|x: &i32| *x % 2 == 0);
let test_values = [-10, -5, -2, -1, 0, 1, 2, 5, 10];

// Verify left identity law
fn verify_left_identity(a: &Predicate<i32>, x: i32) -> bool {
    let empty = Predicate::<i32>::empty();
    empty.combine(a).contains(&x) == a.contains(&x)
}

// Test with multiple values
for &val in test_values.iter() {
    assert!(verify_left_identity(&is_even, val));
}
§Right Identity: a.combine(empty()) = a
use rustica::datatypes::wrapper::predicate::Predicate;
use rustica::traits::monoid::Monoid;
use rustica::traits::semigroup::Semigroup;

let is_positive = Predicate::new(|x: &i32| *x > 0);
let test_values = [-10, -5, -2, -1, 0, 1, 2, 5, 10];

// Verify right identity law
fn verify_right_identity(a: &Predicate<i32>, x: i32) -> bool {
    let empty = Predicate::<i32>::empty();
    a.combine(&empty).contains(&x) == a.contains(&x)
}

// Test with multiple values
for &val in test_values.iter() {
    assert!(verify_right_identity(&is_positive, val));
}
§Examples
use rustica::datatypes::wrapper::predicate::Predicate;
use rustica::traits::monoid::Monoid;
use rustica::traits::semigroup::Semigroup;

// Create the empty predicate
let empty_pred = Predicate::<i32>::empty();

// It always returns false
assert!(!empty_pred.contains(&42));
assert!(!empty_pred.contains(&-7));
assert!(!empty_pred.contains(&0));

// Combining with other predicates
let is_positive = Predicate::new(|x: &i32| *x > 0);
let combined = empty_pred.combine(&is_positive);

// The result is equivalent to the non-empty predicate
assert!(combined.contains(&5));
assert!(!combined.contains(&-5));
Source§

impl<A> Not for Predicate<A>
where A: 'static,

Source§

type Output = Predicate<A>

The resulting type after applying the ! operator.
Source§

fn not(self) -> Predicate<A>

Performs the unary ! operation. Read more
Source§

impl<A: 'static> Semigroup for Predicate<A>

Source§

fn combine(&self, other: &Self) -> Self

Combines two predicates using logical OR operation (union).

The resulting predicate will evaluate to true for an input if either this predicate or the other predicate evaluates to true for that input. This is equivalent to the union of the two sets defined by these predicates.

§Performance
  • Time Complexity: O(1) for creation, O(f1 + f2) for evaluation where f1 and f2 are the complexities of the component predicates
  • Memory Usage: O(1) - Creates a new predicate with references to existing predicates
  • Short-circuit Evaluation: Returns early if the first predicate evaluates to true
  • Cloning: Only the Rc pointers are cloned, not the underlying functions
§Type Class Laws
§Associativity: (a combine b) combine c = a combine (b combine c)
use rustica::datatypes::wrapper::predicate::Predicate;
use rustica::traits::semigroup::Semigroup;

// Define three simple predicates
let is_even = Predicate::new(|x: &i32| *x % 2 == 0);
let is_positive = Predicate::new(|x: &i32| *x > 0);
let is_multiple_of_3 = Predicate::new(|x: &i32| *x % 3 == 0);

// Test values
let test_values = [-6, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 9, 12];

// Verify associativity
fn verify_associativity(a: &Predicate<i32>, b: &Predicate<i32>, c: &Predicate<i32>, x: &i32) -> bool {
    let left = a.combine(&b).combine(c).contains(x);
    let right = a.combine(&b.combine(c)).contains(x);
    left == right
}

// Verify the law for all test values
for &val in test_values.iter() {
    assert!(verify_associativity(&is_even, &is_positive, &is_multiple_of_3, &val));
}
§Examples
use rustica::datatypes::wrapper::predicate::Predicate;
use rustica::traits::semigroup::Semigroup;

let is_even = Predicate::new(|x: &i32| *x % 2 == 0);
let is_large = Predicate::new(|x: &i32| *x > 100);

// Combine predicates using Semigroup trait
let is_even_or_large = is_even.combine(&is_large);

assert!(is_even_or_large.contains(&2));      // Even but not large
assert!(is_even_or_large.contains(&200));    // Both even and large
assert!(is_even_or_large.contains(&101));    // Large but not even
assert!(!is_even_or_large.contains(&51));    // Neither even nor large
Source§

fn combine_owned(self, other: Self) -> Self

Combines two predicates by consuming them, using logical OR operation (union).

This is the ownership-consuming variant of combine. The resulting predicate will evaluate to true for an input if either of the original predicates would evaluate to true for that input.

§Performance
  • Time Complexity: O(1) for creation, O(f1 + f2) for evaluation
  • Memory Usage: More efficient than combine when both predicates are no longer needed separately
  • Ownership: Consumes both predicates rather than cloning references
§Examples
use rustica::datatypes::wrapper::predicate::Predicate;
use rustica::traits::semigroup::Semigroup;

let is_divisible_by_2 = Predicate::new(|x: &i32| *x % 2 == 0);
let is_divisible_by_3 = Predicate::new(|x: &i32| *x % 3 == 0);

// Consume both predicates to create a new one
let is_divisible_by_2_or_3 = is_divisible_by_2.combine_owned(is_divisible_by_3);

assert!(is_divisible_by_2_or_3.contains(&6));   // Divisible by both 2 and 3
assert!(is_divisible_by_2_or_3.contains(&4));   // Divisible by 2 only
assert!(is_divisible_by_2_or_3.contains(&9));   // Divisible by 3 only
assert!(!is_divisible_by_2_or_3.contains(&5));  // Divisible by neither
Source§

impl<A> Sub for Predicate<A>
where A: 'static,

Source§

type Output = Predicate<A>

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: Predicate<A>) -> Predicate<A>

Performs the - operation. Read more

Auto Trait Implementations§

§

impl<A> !RefUnwindSafe for Predicate<A>

§

impl<A> !Send for Predicate<A>

§

impl<A> !Sync for Predicate<A>

§

impl<A> !UnwindSafe for Predicate<A>

§

impl<A> Freeze for Predicate<A>

§

impl<A> Unpin for Predicate<A>

§

impl<A> UnsafeUnpin for Predicate<A>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> MonoidExt for T
where T: Monoid,

Source§

fn is_empty_monoid(&self) -> bool
where Self: PartialEq,

Checks if this monoid value is equal to the identity element. Read more
Source§

impl<T> PureExt for T
where T: Clone,

Source§

fn to_pure<P>(&self) -> P::Output<Self>
where P: Pure, Self: Clone,

Lift a value into a context. Read more
Source§

fn to_pure_owned<P>(self) -> P::Output<Self>
where P: Pure, Self: Clone,

Lift a value into a context, consuming the value. Read more
Source§

fn pair_with<P, U>(&self, other: &U) -> P::Output<(Self, U)>
where P: Pure, Self: Clone, U: Clone,

Lift a pair of values into a context. Read more
Source§

fn lift_other<P, U>(&self, other: &U) -> P::Output<U>
where P: Pure, U: Clone,

Lift another value into a context. Read more
Source§

fn combine_with<P, U, V>( &self, other: &U, f: impl Fn(&Self, &U) -> V, ) -> P::Output<V>
where P: Pure, Self: Clone, U: Clone, V: Clone,

Combine two values into a new value and lift it into a context. Read more
Source§

impl<T> SemigroupExt for T
where T: Semigroup,

Source§

fn combine_all<I>(self, others: I) -> Self
where I: IntoIterator<Item = Self>, Self: Sized,

Combines self with all the values in an iterator. Read more
Source§

fn combine_all_owned<I>(vals: I) -> Self
where I: IntoIterator<Item = Self>, Self: Sized,

Combines all elements in an iterator into one value, starting from the first. Read more
Source§

fn combine_n(&self, n: &usize) -> Self
where Self: Clone,

Combines the semigroup value with itself a specified number of times.
Source§

fn combine_n_owned(self, n: usize) -> Self
where Self: Clone,

Combines the semigroup value with itself a specified number of times, by value.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.