<A>(isEquivalent: (self: A, that: A) => boolean): (
self: Iterable<A>
) => Iterable<A>
<A>(
self: Iterable<A>,
isEquivalent: (self: A, that: A) => boolean
): Iterable<A>Deduplicates adjacent elements that are identical using the provided isEquivalent function.
Example (Deduplicating adjacent elements with custom equivalence)
import { Iterable } from "effect"
// Remove adjacent duplicates with custom equality
const numbers = [1, 1, 2, 2, 3, 1, 1]
const dedupedNumbers = Iterable.dedupeAdjacentWith(numbers, (a, b) => a === b)
console.log(Array.from(dedupedNumbers)) // [1, 2, 3, 1]
// Case-insensitive deduplication
const words = ["Hello", "HELLO", "world", "World", "test"]
const caseInsensitive = (a: string, b: string) =>
a.toLowerCase() === b.toLowerCase()
const dedupedWords = Iterable.dedupeAdjacentWith(words, caseInsensitive)
console.log(Array.from(dedupedWords)) // ["Hello", "world", "test"]
// Deduplication by object property
const users = [
{ id: 1, name: "Alice" },
{ id: 1, name: "Alice Updated" }, // different name, same id
{ id: 2, name: "Bob" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" }
]
const byId = (a: typeof users[0], b: typeof users[0]) => a.id === b.id
const dedupedUsers = Iterable.dedupeAdjacentWith(users, byId)
console.log(Array.from(dedupedUsers).map((u) => u.id)) // [1, 2, 3]
// Approximate numeric equality
const floats = [1.0, 1.01, 1.02, 2.0, 2.01, 3.0]
const approxEqual = (a: number, b: number) => Math.abs(a - b) < 0.1
const dedupedFloats = Iterable.dedupeAdjacentWith(floats, approxEqual)
console.log(Array.from(dedupedFloats)) // [1.0, 2.0, 3.0]export const const dedupeAdjacentWith: {
<A>(
isEquivalent: (self: A, that: A) => boolean
): (self: Iterable<A>) => Iterable<A>
<A>(
self: Iterable<A>,
isEquivalent: (self: A, that: A) => boolean
): Iterable<A>
}
Deduplicates adjacent elements that are identical using the provided isEquivalent function.
Example (Deduplicating adjacent elements with custom equivalence)
import { Iterable } from "effect"
// Remove adjacent duplicates with custom equality
const numbers = [1, 1, 2, 2, 3, 1, 1]
const dedupedNumbers = Iterable.dedupeAdjacentWith(numbers, (a, b) => a === b)
console.log(Array.from(dedupedNumbers)) // [1, 2, 3, 1]
// Case-insensitive deduplication
const words = ["Hello", "HELLO", "world", "World", "test"]
const caseInsensitive = (a: string, b: string) =>
a.toLowerCase() === b.toLowerCase()
const dedupedWords = Iterable.dedupeAdjacentWith(words, caseInsensitive)
console.log(Array.from(dedupedWords)) // ["Hello", "world", "test"]
// Deduplication by object property
const users = [
{ id: 1, name: "Alice" },
{ id: 1, name: "Alice Updated" }, // different name, same id
{ id: 2, name: "Bob" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" }
]
const byId = (a: typeof users[0], b: typeof users[0]) => a.id === b.id
const dedupedUsers = Iterable.dedupeAdjacentWith(users, byId)
console.log(Array.from(dedupedUsers).map((u) => u.id)) // [1, 2, 3]
// Approximate numeric equality
const floats = [1.0, 1.01, 1.02, 2.0, 2.01, 3.0]
const approxEqual = (a: number, b: number) => Math.abs(a - b) < 0.1
const dedupedFloats = Iterable.dedupeAdjacentWith(floats, approxEqual)
console.log(Array.from(dedupedFloats)) // [1.0, 2.0, 3.0]
dedupeAdjacentWith: {
<function (type parameter) A in <A>(isEquivalent: (self: A, that: A) => boolean): (self: Iterable<A>) => Iterable<A>A>(isEquivalent: (self: A, that: A) => booleanisEquivalent: (self: Aself: function (type parameter) A in <A>(isEquivalent: (self: A, that: A) => boolean): (self: Iterable<A>) => Iterable<A>A, that: Athat: function (type parameter) A in <A>(isEquivalent: (self: A, that: A) => boolean): (self: Iterable<A>) => Iterable<A>A) => boolean): (self: Iterable<A>self: interface Iterable<T, TReturn = any, TNext = any>Iterable<function (type parameter) A in <A>(isEquivalent: (self: A, that: A) => boolean): (self: Iterable<A>) => Iterable<A>A>) => interface Iterable<T, TReturn = any, TNext = any>Iterable<function (type parameter) A in <A>(isEquivalent: (self: A, that: A) => boolean): (self: Iterable<A>) => Iterable<A>A>
<function (type parameter) A in <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A>(self: Iterable<A>self: interface Iterable<T, TReturn = any, TNext = any>Iterable<function (type parameter) A in <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A>, isEquivalent: (self: A, that: A) => booleanisEquivalent: (self: Aself: function (type parameter) A in <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A, that: Athat: function (type parameter) A in <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A) => boolean): interface Iterable<T, TReturn = any, TNext = any>Iterable<function (type parameter) A in <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A>
} = dual<(...args: Array<any>) => any, <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean) => Iterable<A>>(arity: 2, body: <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean) => Iterable<A>): ((...args: Array<any>) => any) & (<A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean) => Iterable<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: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A>(self: Iterable<A>self: interface Iterable<T, TReturn = any, TNext = any>Iterable<function (type parameter) A in <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A>, isEquivalent: (self: A, that: A) => booleanisEquivalent: (self: Aself: function (type parameter) A in <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A, that: Athat: function (type parameter) A in <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A) => boolean): interface Iterable<T, TReturn = any, TNext = any>Iterable<function (type parameter) A in <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A> => ({
[var Symbol: SymbolConstructorSymbol.SymbolConstructor.iterator: typeof Symbol.iteratorA method that returns the default iterator for an object. Called by the semantics of the
for-of statement.
iterator]() {
const const iterator: Iterator<A, any, any>iterator = self: Iterable<A>self[var Symbol: SymbolConstructorSymbol.SymbolConstructor.iterator: typeof Symbol.iteratorA method that returns the default iterator for an object. Called by the semantics of the
for-of statement.
iterator]()
let let first: booleanfirst = true
let let last: Alast: function (type parameter) A in <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A
function function (local function) next(): IteratorResult<A>next(): type IteratorResult<T, TReturn = any> =
| IteratorYieldResult<T>
| IteratorReturnResult<TReturn>
IteratorResult<function (type parameter) A in <A>(self: Iterable<A>, isEquivalent: (self: A, that: A) => boolean): Iterable<A>A> {
const const result: IteratorResult<A, any>result = const iterator: Iterator<A, any, any>iterator.Iterator<A, any, any>.next(...[value]: [] | [any]): IteratorResult<A, any>next()
if (const result: IteratorResult<A, any>result.done?: boolean | undefineddone) {
return { IteratorReturnResult<TReturn>.done: truedone: true, IteratorReturnResult<any>.value: anyvalue: var undefinedundefined }
}
if (let first: booleanfirst) {
let first: booleanfirst = false
let last: Alast = const result: IteratorYieldResult<A>result.IteratorYieldResult<A>.value: Avalue
return const result: IteratorYieldResult<A>result
}
const const current: Acurrent = const result: IteratorYieldResult<A>result.IteratorYieldResult<A>.value: Avalue
if (isEquivalent: (self: A, that: A) => booleanisEquivalent(let last: Alast, const current: Acurrent)) {
return function (local function) next(): IteratorResult<A>next()
}
let last: Alast = const current: Acurrent
return const result: IteratorYieldResult<A>result
}
return { Iterator<A, any, any>.next(...[value]: [] | [any]): IteratorResult<A, any>next }
}
}))