Skip to content

Commit

Permalink
Add functional predicate NAND
Browse files Browse the repository at this point in the history
Add new function, NAND, designed to create a composed predicate representing the logical NAND operation
applied to a list of predicates. The NAND operation is a logical operation
that returns true only if all perdicate result in false otherwise false
  • Loading branch information
donutloop committed Feb 25, 2024
1 parent a43bc55 commit 3f5f6a1
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 4 deletions.
16 changes: 16 additions & 0 deletions function/predicate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ func And[T any](predicates ...func(T) bool) func(T) bool {
}
}

// And returns a composed predicate that represents the logical NAND of a list of predicates.
// It evaluates to true only if all predicates evaluate to false for the given value.
func Nand[T any](predicates ...func(T) bool) func(T) bool {
if len(predicates) < 2 {
panic("programming error: predicates count must be at least 2")
}
return func(value T) bool {
for _, predicate := range predicates {
if predicate(value) {
return false // Short-circuit on the first true predicate
}
}
return true // True if all predicates are false
}
}

// Negate returns a predicate that represents the logical negation of this predicate.
func Negate[T any](predicate func(T) bool) func(T) bool {
return func(value T) bool {
Expand Down
16 changes: 16 additions & 0 deletions function/predicate_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ func ExampleAnd() {
// false
}

func ExampleNand() {
isNumericAndLength5 := Nand(
func(s string) bool { return strings.ContainsAny(s, "0123456789") },
func(s string) bool { return len(s) == 5 },
)

fmt.Println(isNumericAndLength5("12345"))
fmt.Println(isNumericAndLength5("1234"))
fmt.Println(isNumericAndLength5("abcdef"))

// Output:
// false
// false
// true
}

func ExampleNor() {
match := Nor(
func(s string) bool { return strings.ContainsAny(s, "0123456789") },
Expand Down
26 changes: 22 additions & 4 deletions function/predicate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,21 @@ func TestPredicatesAndPure(t *testing.T) {
assert.ShouldBeFalse(isNumericAndLength5("abcde"))
}

func TestPredicatesNandPure(t *testing.T) {
t.Parallel()

assert := internal.NewAssert(t, "TestPredicatesNandPure")

isNumericAndLength5 := Nand(
func(s string) bool { return strings.ContainsAny(s, "0123456789") },
func(s string) bool { return len(s) == 5 },
)

assert.ShouldBeFalse(isNumericAndLength5("12345"))
assert.ShouldBeFalse(isNumericAndLength5("1234"))
assert.ShouldBeTrue(isNumericAndLength5("abcdef"))
}

func TestPredicatesNorPure(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -108,9 +123,12 @@ func TestPredicatesMix(t *testing.T) {

assert.ShouldBeFalse(c("hello!"))

c = Nor(a, b)
assert.ShouldBeFalse(c("hello!"))
k := Nor(a, b)
assert.ShouldBeFalse(k("hello!"))

o := Xnor(a, b)
assert.ShouldBeTrue(o("hello!"))

c = Xnor(a, b)
assert.ShouldBeTrue(c("hello!"))
p := Nand(c, k)
assert.ShouldBeTrue(p("hello!"))
}

0 comments on commit 3f5f6a1

Please sign in to comment.