// Copyright (c) 2023 - 2025 IBM Corp. // All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package predicate import ( F "github.com/IBM/fp-go/v2/function" "github.com/IBM/fp-go/v2/monoid" "github.com/IBM/fp-go/v2/semigroup" ) type ( // Semigroup represents a semigroup instance for predicates, providing a way to combine // two predicates into one using an associative operation. Semigroup[A any] = semigroup.Semigroup[Predicate[A]] // Monoid represents a monoid instance for predicates, extending Semigroup with an // identity element (empty predicate). Monoid[A any] = monoid.Monoid[Predicate[A]] ) // SemigroupAny creates a semigroup that combines predicates using logical OR (||). // // When two predicates are combined with this semigroup, the resulting predicate returns // true if either of the original predicates returns true. This implements the associative // operation for disjunction. // // Returns: // - A Semigroup[A] that combines predicates with OR logic // // Example: // // s := SemigroupAny[int]() // isPositive := func(n int) bool { return n > 0 } // isEven := func(n int) bool { return n%2 == 0 } // isPositiveOrEven := s.Concat(isPositive, isEven) // isPositiveOrEven(4) // true (even) // isPositiveOrEven(3) // true (positive) // isPositiveOrEven(-2) // true (even) // isPositiveOrEven(-3) // false (neither) func SemigroupAny[A any]() Semigroup[A] { return semigroup.MakeSemigroup(func(first Predicate[A], second Predicate[A]) Predicate[A] { return F.Pipe1( first, Or(second), ) }) } // SemigroupAll creates a semigroup that combines predicates using logical AND (&&). // // When two predicates are combined with this semigroup, the resulting predicate returns // true only if both of the original predicates return true. This implements the associative // operation for conjunction. // // Returns: // - A Semigroup[A] that combines predicates with AND logic // // Example: // // s := SemigroupAll[int]() // isPositive := func(n int) bool { return n > 0 } // isEven := func(n int) bool { return n%2 == 0 } // isPositiveAndEven := s.Concat(isPositive, isEven) // isPositiveAndEven(4) // true (both) // isPositiveAndEven(3) // false (not even) // isPositiveAndEven(-2) // false (not positive) // isPositiveAndEven(-3) // false (neither) func SemigroupAll[A any]() Semigroup[A] { return semigroup.MakeSemigroup(func(first Predicate[A], second Predicate[A]) Predicate[A] { return F.Pipe1( first, And(second), ) }) } // MonoidAny creates a monoid that combines predicates using logical OR (||). // // This extends SemigroupAny with an identity element: a predicate that always returns false. // The identity element satisfies the property that combining it with any predicate p yields p. // This is useful for folding/reducing a collection of predicates where an empty collection // should result in a predicate that always returns false. // // Returns: // - A Monoid[A] that combines predicates with OR logic and has false as identity // // Example: // // m := MonoidAny[int]() // predicates := []Predicate[int]{ // func(n int) bool { return n > 10 }, // func(n int) bool { return n < 0 }, // } // combined := A.Reduce(m.Empty(), m.Concat)(predicates) // combined(15) // true (> 10) // combined(-5) // true (< 0) // combined(5) // false (neither) func MonoidAny[A any]() Monoid[A] { return monoid.MakeMonoid( SemigroupAny[A]().Concat, F.Constant1[A](false), ) } // MonoidAll creates a monoid that combines predicates using logical AND (&&). // // This extends SemigroupAll with an identity element: a predicate that always returns true. // The identity element satisfies the property that combining it with any predicate p yields p. // This is useful for folding/reducing a collection of predicates where an empty collection // should result in a predicate that always returns true. // // Returns: // - A Monoid[A] that combines predicates with AND logic and has true as identity // // Example: // // m := MonoidAll[int]() // predicates := []Predicate[int]{ // func(n int) bool { return n > 0 }, // func(n int) bool { return n < 100 }, // } // combined := A.Reduce(m.Empty(), m.Concat)(predicates) // combined(50) // true (both conditions) // combined(-5) // false (not > 0) // combined(150) // false (not < 100) func MonoidAll[A any]() Monoid[A] { return monoid.MakeMonoid( SemigroupAll[A]().Concat, F.Constant1[A](true), ) }