<A>(that: Equivalence<A>): (self: Equivalence<A>) => Equivalence<A>
<A>(self: Equivalence<A>, that: Equivalence<A>): Equivalence<A>Combines two equivalence relations using logical AND.
When to use
Use when you need to combine exactly two equivalences with AND semantics.
Details
Returns true only if both equivalences return true. The comparison
short-circuits when the first equivalence returns false. The result is also
an equivalence that satisfies reflexive, symmetric, and transitive
properties.
Example (Combining name and age equivalences)
import { Equivalence } from "effect"
interface Person {
name: string
age: number
}
const nameEquivalence = Equivalence.mapInput(
Equivalence.strictEqual<string>(),
(p: Person) => p.name
)
const ageEquivalence = Equivalence.mapInput(
Equivalence.strictEqual<number>(),
(p: Person) => p.age
)
const personEquivalence = Equivalence.combine(nameEquivalence, ageEquivalence)
const person1 = { name: "Alice", age: 30 }
const person2 = { name: "Alice", age: 30 }
const person3 = { name: "Alice", age: 31 }
console.log(personEquivalence(person1, person2)) // true
console.log(personEquivalence(person1, person3)) // false (different age)export const const combine: {
<A>(that: Equivalence<A>): (
self: Equivalence<A>
) => Equivalence<A>
<A>(
self: Equivalence<A>,
that: Equivalence<A>
): Equivalence<A>
}
Combines two equivalence relations using logical AND.
When to use
Use when you need to combine exactly two equivalences with AND semantics.
Details
Returns true only if both equivalences return true. The comparison
short-circuits when the first equivalence returns false. The result is also
an equivalence that satisfies reflexive, symmetric, and transitive
properties.
Example (Combining name and age equivalences)
import { Equivalence } from "effect"
interface Person {
name: string
age: number
}
const nameEquivalence = Equivalence.mapInput(
Equivalence.strictEqual<string>(),
(p: Person) => p.name
)
const ageEquivalence = Equivalence.mapInput(
Equivalence.strictEqual<number>(),
(p: Person) => p.age
)
const personEquivalence = Equivalence.combine(nameEquivalence, ageEquivalence)
const person1 = { name: "Alice", age: 30 }
const person2 = { name: "Alice", age: 30 }
const person3 = { name: "Alice", age: 31 }
console.log(personEquivalence(person1, person2)) // true
console.log(personEquivalence(person1, person3)) // false (different age)
combine: {
<function (type parameter) A in <A>(that: Equivalence<A>): (self: Equivalence<A>) => Equivalence<A>A>(that: Equivalence<A>that: type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<function (type parameter) A in <A>(that: Equivalence<A>): (self: Equivalence<A>) => Equivalence<A>A>): (self: Equivalence<A>self: type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<function (type parameter) A in <A>(that: Equivalence<A>): (self: Equivalence<A>) => Equivalence<A>A>) => type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<function (type parameter) A in <A>(that: Equivalence<A>): (self: Equivalence<A>) => Equivalence<A>A>
<function (type parameter) A in <A>(self: Equivalence<A>, that: Equivalence<A>): Equivalence<A>A>(self: Equivalence<A>self: type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<function (type parameter) A in <A>(self: Equivalence<A>, that: Equivalence<A>): Equivalence<A>A>, that: Equivalence<A>that: type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<function (type parameter) A in <A>(self: Equivalence<A>, that: Equivalence<A>): Equivalence<A>A>): type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<function (type parameter) A in <A>(self: Equivalence<A>, that: Equivalence<A>): Equivalence<A>A>
} = dual<(...args: Array<any>) => any, <A>(self: Equivalence<A>, that: Equivalence<A>) => Equivalence<A>>(arity: 2, body: <A>(self: Equivalence<A>, that: Equivalence<A>) => Equivalence<A>): ((...args: Array<any>) => any) & (<A>(self: Equivalence<A>, that: Equivalence<A>) => Equivalence<A>) (+1 overload)Creates a function that can be called in data-first style or data-last
(pipe-friendly) style.
When to use
Use to expose one implementation through both direct and pipe-friendly
call styles.
Details
Pass either the arity of the uncurried function or a predicate that decides
whether the current call is data-first. Arity is the common case. Use a
predicate when optional arguments make arity ambiguous.
Example (Selecting data-first or data-last style by arity)
import { Function, pipe } from "effect"
const sum = Function.dual<
(that: number) => (self: number) => number,
(self: number, that: number) => number
>(2, (self, that) => self + that)
console.log(sum(2, 3)) // 5
console.log(pipe(2, sum(3))) // 5
Example (Defining overloads with call signatures)
import { Function, pipe } from "effect"
const sum: {
(that: number): (self: number) => number
(self: number, that: number): number
} = Function.dual(2, (self: number, that: number): number => self + that)
console.log(sum(2, 3)) // 5
console.log(pipe(2, sum(3))) // 5
Example (Selecting data-first or data-last style with a predicate)
import { Function, pipe } from "effect"
const sum = Function.dual<
(that: number) => (self: number) => number,
(self: number, that: number) => number
>(
(args) => args.length === 2,
(self, that) => self + that
)
console.log(sum(2, 3)) // 5
console.log(pipe(2, sum(3))) // 5
dual(2, <function (type parameter) A in <A>(self: Equivalence<A>, that: Equivalence<A>): Equivalence<A>A>(self: Equivalence<A>self: type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<function (type parameter) A in <A>(self: Equivalence<A>, that: Equivalence<A>): Equivalence<A>A>, that: Equivalence<A>that: type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<function (type parameter) A in <A>(self: Equivalence<A>, that: Equivalence<A>): Equivalence<A>A>): type Equivalence<in A> = (
self: A,
that: A
) => boolean
Represents an equivalence relation over type A.
When to use
Use as a type annotation when you accept or return an equivalence function.
Details
- Returns
boolean: true if values are equivalent, false otherwise
- Must satisfy reflexive, symmetric, and transitive properties
Example (Defining simple number equivalence)
import type { Equivalence } from "effect"
const numberEq: Equivalence.Equivalence<number> = (a, b) => a === b
console.log(numberEq(1, 1)) // true
console.log(numberEq(1, 2)) // false
Example (Defining custom object equivalence)
import type { Equivalence } from "effect"
interface Point {
x: number
y: number
}
const pointEq: Equivalence.Equivalence<Point> = (a, b) =>
a.x === b.x && a.y === b.y
console.log(pointEq({ x: 1, y: 2 }, { x: 1, y: 2 })) // true
Equivalence<function (type parameter) A in <A>(self: Equivalence<A>, that: Equivalence<A>): Equivalence<A>A> => const make: <A>(
isEquivalent: (self: A, that: A) => boolean
) => Equivalence<A>
Creates a custom equivalence relation with an optimized reference equality check.
When to use
Use when you need an equality rule that the built-in instances and input
mapping helpers cannot express, and you can provide a law-abiding comparison.
Details
The returned equivalence first checks reference equality (===) for
performance. If the values are not the same reference, it falls back to the
provided equivalence function, which must satisfy reflexive, symmetric, and
transitive properties.
Example (Case-insensitive string equivalence)
import { Equivalence } from "effect"
const caseInsensitive = Equivalence.make<string>((a, b) =>
a.toLowerCase() === b.toLowerCase()
)
console.log(caseInsensitive("Hello", "HELLO")) // true
console.log(caseInsensitive("foo", "bar")) // false
// Same reference optimization
const str = "test"
console.log(caseInsensitive(str, str)) // true (fast path)
Example (Comparing numbers with tolerance)
import { Equivalence } from "effect"
const tolerance = Equivalence.make<number>((a, b) => Math.abs(a - b) < 0.0001)
console.log(tolerance(1.0, 1.001)) // false
console.log(tolerance(1.0, 1.00001)) // true
make((x: Ax, y: Ay) => self: Equivalence<A>self(x: Ax, y: Ay) && that: Equivalence<A>that(x: Ax, y: Ay)))