<B, A>(f: (b: B) => A): (self: Equivalence<A>) => Equivalence<B>
<A, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>Transforms an equivalence relation by mapping the input values before comparison.
When to use
Use when you need an equivalence for one type by comparing a derived value.
Details
- Applies the transformation function to both values before comparing
- The transformation function should be pure and have no side effects
- The resulting equivalence compares the transformed values using the provided equivalence
- The result is also an equivalence that satisfies reflexive, symmetric, and transitive properties
- Useful for comparing by one property or normalizing values before comparison, such as case-insensitive strings
Example (Deriving equivalence from an object property)
import { Equivalence } from "effect"
interface User {
id: number
name: string
email: string
}
// Create equivalence based on user ID only
const userByIdEq = Equivalence.mapInput(
Equivalence.strictEqual<number>(),
(user: User) => user.id
)
const user1 = { id: 1, name: "Alice", email: "[email protected]" }
const user2 = { id: 1, name: "Alice Smith", email: "[email protected]" }
const user3 = { id: 2, name: "Bob", email: "[email protected]" }
console.log(userByIdEq(user1, user2)) // true (same ID)
console.log(userByIdEq(user1, user3)) // false (different ID)Example (Case-insensitive string equivalence)
import { Equivalence } from "effect"
const caseInsensitiveEq = Equivalence.mapInput(
Equivalence.strictEqual<string>(),
(s: string) => s.toLowerCase()
)
console.log(caseInsensitiveEq("Hello", "HELLO")) // true
console.log(caseInsensitiveEq("Hello", "World")) // falseexport const const mapInput: {
<B, A>(f: (b: B) => A): (
self: Equivalence<A>
) => Equivalence<B>
<A, B>(
self: Equivalence<A>,
f: (b: B) => A
): Equivalence<B>
}
Transforms an equivalence relation by mapping the input values before comparison.
When to use
Use when you need an equivalence for one type by comparing a derived value.
Details
- Applies the transformation function to both values before comparing
- The transformation function should be pure and have no side effects
- The resulting equivalence compares the transformed values using the provided equivalence
- The result is also an equivalence that satisfies reflexive, symmetric, and transitive properties
- Useful for comparing by one property or normalizing values before
comparison, such as case-insensitive strings
Example (Deriving equivalence from an object property)
import { Equivalence } from "effect"
interface User {
id: number
name: string
email: string
}
// Create equivalence based on user ID only
const userByIdEq = Equivalence.mapInput(
Equivalence.strictEqual<number>(),
(user: User) => user.id
)
const user1 = { id: 1, name: "Alice", email: "[email protected]" }
const user2 = { id: 1, name: "Alice Smith", email: "[email protected]" }
const user3 = { id: 2, name: "Bob", email: "[email protected]" }
console.log(userByIdEq(user1, user2)) // true (same ID)
console.log(userByIdEq(user1, user3)) // false (different ID)
Example (Case-insensitive string equivalence)
import { Equivalence } from "effect"
const caseInsensitiveEq = Equivalence.mapInput(
Equivalence.strictEqual<string>(),
(s: string) => s.toLowerCase()
)
console.log(caseInsensitiveEq("Hello", "HELLO")) // true
console.log(caseInsensitiveEq("Hello", "World")) // false
mapInput: {
<function (type parameter) B in <B, A>(f: (b: B) => A): (self: Equivalence<A>) => Equivalence<B>B, function (type parameter) A in <B, A>(f: (b: B) => A): (self: Equivalence<A>) => Equivalence<B>A>(f: (b: B) => Af: (b: Bb: function (type parameter) B in <B, A>(f: (b: B) => A): (self: Equivalence<A>) => Equivalence<B>B) => function (type parameter) A in <B, A>(f: (b: B) => A): (self: Equivalence<A>) => Equivalence<B>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 <B, A>(f: (b: B) => A): (self: Equivalence<A>) => Equivalence<B>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) B in <B, A>(f: (b: B) => A): (self: Equivalence<A>) => Equivalence<B>B>
<function (type parameter) A in <A, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>A, function (type parameter) B in <A, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>B>(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, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>A>, f: (b: B) => Af: (b: Bb: function (type parameter) B in <A, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>B) => function (type parameter) A in <A, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>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) B in <A, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>B>
} = dual<(...args: Array<any>) => any, <A, B>(self: Equivalence<A>, f: (b: B) => A) => Equivalence<B>>(arity: 2, body: <A, B>(self: Equivalence<A>, f: (b: B) => A) => Equivalence<B>): ((...args: Array<any>) => any) & (<A, B>(self: Equivalence<A>, f: (b: B) => A) => Equivalence<B>) (+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, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>A, function (type parameter) B in <A, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>B>(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, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>A>, f: (b: B) => Af: (b: Bb: function (type parameter) B in <A, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>B) => function (type parameter) A in <A, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>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) B in <A, B>(self: Equivalence<A>, f: (b: B) => A): Equivalence<B>B> => 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: Bx, y: By) => self: Equivalence<A>self(f: (b: B) => Af(x: Bx), f: (b: B) => Af(y: By)))
)