// ets_tracing: off import "../../../Operator/index.js" import type { Option } from "@effect-ts/system/Option" import type { MutableSet } from "@effect-ts/system/Support/Mutable" import type { Associative } from "../../../Associative/index.js" import { makeAssociative } from "../../../Associative/index.js" import type { Either } from "../../../Either/index.js" import type { Equal } from "../../../Equal/index.js" import { makeEqual } from "../../../Equal/index.js" import type { Predicate, Refinement } from "../../../Function/index.js" import { identity, not } from "../../../Function/index.js" import type { Identity } from "../../../Identity/index.js" import { makeIdentity } from "../../../Identity/index.js" import type { Ord } from "../../../Ord/index.js" import type { Show } from "../../../Show/index.js" import * as Tp from "../Tuple/index.js" export type Set = ReadonlySet export const empty: Set = new Set() /** * Get an Associative that performs Set intersection */ export function getIntersectionAssociative(E: Equal): Associative> { return makeAssociative(intersection_(E)) } /** * Get an Identity that performs Set union */ export function getUnionIdentity(E: Equal): Identity> { return makeIdentity(empty as Set, union_(E)) } /** * The set of elements which are in both the first and second set */ export function intersection_(E: Equal): (l: Set, r: Set) => Set { const elemE = elem_(E) return (x, y) => { if (x === empty || y === empty) { return empty } const r = new Set() x.forEach((e) => { if (elemE(y, e)) { r.add(e) } }) return r } } /** * The set of elements which are in both the first and second set */ export function intersection(E: Equal): (r: Set) => (l: Set) => Set { const i = intersection_(E) return (x) => (y) => i(x, y) } /** * Convert a mutable set to a readonly one */ export function fromMutable(s: MutableSet): Set { return new Set(s) } /** * Convert a set to a mutable one */ export function toMutable(s: Set): MutableSet { return new Set(s) } /** * get Show for set given Show for values */ export function getShow(S: Show): Show> { return { show: (s) => { let elements = "" s.forEach((a) => { elements += S.show(a) + ", " }) if (elements !== "") { elements = elements.substring(0, elements.length - 2) } return `new Set([${elements}])` } } } /** * Convert a set to an Array */ export function toArray(O: Ord): (set: Set) => ReadonlyArray { return (x) => { const r: Array = [] x.forEach((e) => r.push(e)) return r.sort(O.compare) } } /** * Convert a set to an Array */ export function toArray_(x: Set, O: Ord): ReadonlyArray { return toArray(O)(x) } /** * Get Equal for Setgiven Equal for element */ export function getEqual(E: Equal): Equal> { const subsetE = isSubset_(E) return makeEqual((x, y) => subsetE(x, y) && subsetE(y, x)) } interface Next { readonly done?: boolean readonly value: A } /** * true if one or more elements match predicate */ export function some(predicate: Predicate): (set: Set) => boolean { return (set) => { const values = set.values() let e: Next let found = false while (!found && !(e = values.next()).done) { found = predicate(e.value) } return found } } /** * true if one or more elements match predicate */ export function some_(set: Set, predicate: Predicate): boolean { return some(predicate)(set) } /** * Projects a Set through a function */ export function map(E: Equal): (f: (x: A) => B) => (set: Set) => Set { const m = map_(E) return (f) => (set) => m(set, f) } /** * Projects a Set through a function */ export function map_(E: Equal): (set: Set, f: (x: A) => B) => Set { const elemE = elem_(E) return (set, f) => { const r = new Set() set.forEach((e) => { const v = f(e) if (!elemE(r, v)) { r.add(v) } }) return r } } /** * true if all elements match predicate */ export function every(predicate: Predicate): (set: Set) => boolean { return (set) => every_(set, predicate) } /** * true if all elements match predicate */ export function every_(set: Set, predicate: Predicate): boolean { return not(some(not(predicate)))(set) } /** * Map + Flatten */ export function chain( E: Equal ): (f: (x: A) => Set) => (set: Set) => Set { const c = chain_(E) return (f) => (set) => c(set, f) } /** * Map + Flatten */ export function chain_( E: Equal ): (set: Set, f: (x: A) => Set) => Set { const elemE = elem_(E) return (set, f) => { const r = new Set() set.forEach((e) => { f(e).forEach((e) => { if (!elemE(r, e)) { r.add(e) } }) }) return r } } /** * `true` if and only if every element in the first set is an element of the second set */ export function isSubset(E: Equal): (y: Set) => (x: Set) => boolean { const i = isSubset_(E) return (y) => (x) => i(y, x) } /** * `true` if and only if every element in the first set is an element of the second set */ export function isSubset_(E: Equal): (x: Set, y: Set) => boolean { const elemE = elem_(E) return (x, y) => every((a: A) => elemE(y, a))(x) } /** * Filter set values using predicate */ export function filter( refinement: Refinement ): (set: Set) => Set export function filter(predicate: Predicate): (set: Set) => Set export function filter(predicate: Predicate): (set: Set) => Set { return (set) => filter_(set, predicate) } /** * Filter set values using predicate */ export function filter_( set: Set, refinement: Refinement ): Set export function filter_(set: Set, predicate: Predicate): Set export function filter_(set: Set, predicate: Predicate): Set { const values = set.values() let e: Next const r = new Set() while (!(e = values.next()).done) { const value = e.value if (predicate(value)) { r.add(value) } } return r } /** * Partition set values using predicate */ export function partition( refinement: Refinement ): (set: Set) => Tp.Tuple<[Set, Set]> export function partition( predicate: Predicate ): (set: Set) => Tp.Tuple<[Set, Set]> export function partition( predicate: Predicate ): (set: Set) => Tp.Tuple<[Set, Set]> { return (set) => partition_(set, predicate) } /** * Partition set values using predicate */ export function partition_( set: Set, refinement: Refinement ): Tp.Tuple<[Set, Set]> export function partition_( set: Set, predicate: Predicate ): Tp.Tuple<[Set, Set]> export function partition_( set: Set, predicate: Predicate ): Tp.Tuple<[Set, Set]> { const values = set.values() let e: Next const right = new Set() const left = new Set() while (!(e = values.next()).done) { const value = e.value if (predicate(value)) { right.add(value) } else { left.add(value) } } return Tp.tuple(left, right) } /** * Test if a value is a member of a set */ export function elem_(E: Equal): (set: Set, a: A) => boolean { return (set, a) => { const values = set.values() let e: Next let found = false while (!found && !(e = values.next()).done) { found = E.equals(a, e.value) } return found } } /** * Test if a value is a member of a set */ export function elem(E: Equal): (a: A) => (set: Set) => boolean { const e = elem_(E) return (a) => (set) => e(set, a) } /** * Partition elements according to f */ export function partitionMap( EB: Equal, EC: Equal ): (f: (a: A) => Either) => (set: Set) => Tp.Tuple<[Set, Set]> { const pm = partitionMap_(EB, EC) return (f: (a: A) => Either) => (set: Set) => pm(set, f) } /** * Partition elements according to f */ export function partitionMap_( EB: Equal, EC: Equal ): (set: Set, f: (a: A) => Either) => Tp.Tuple<[Set, Set]> { return (set: Set, f: (a: A) => Either) => { const values = set.values() let e: Next const left = new Set() const right = new Set() const hasB = elem_(EB) const hasC = elem_(EC) while (!(e = values.next()).done) { const v = f(e.value) switch (v._tag) { case "Left": if (!hasB(left, v.left)) { left.add(v.left) } break case "Right": if (!hasC(right, v.right)) { right.add(v.right) } break } } return Tp.tuple(left, right) } } /** * Form the set difference (`x` - `y`) */ export function difference_(E: Equal): (l: Set, r: Set) => Set { const elemE = elem_(E) return (x, y) => filter((a: A) => !elemE(y, a))(x) } /** * Form the set difference (`x` - `y`) */ export function difference(E: Equal): (y: Set) => (x: Set) => Set { const diff = difference_(E) return (y) => (x) => diff(x, y) } /** * Reduce over the set values */ export function reduce( O: Ord ): (b: B, f: (b: B, a: A) => B) => (fa: Set) => B { const red = reduce_(O) return (b, f) => (fa) => red(fa, b, f) } /** * Reduce over the set values */ export function reduce_( O: Ord ): (fa: Set, b: B, f: (b: B, a: A) => B) => B { const toArrayO = toArray(O) return (fa, b, f) => toArrayO(fa).reduce(f, b) } /** * Fold + Map */ export function foldMap( O: Ord, M: Identity ): (f: (a: A) => M) => (fa: Set) => M { const fm = foldMap_(O, M) return (f) => (fa) => fm(fa, f) } /** * Fold + Map */ export function foldMap_( O: Ord, M: Identity ): (fa: Set, f: (a: A) => M) => M { const toArrayO = toArray(O) return (fa, f) => toArrayO(fa).reduce((b, a) => M.combine(b, f(a)), M.identity) } /** * Create a set with one element */ export function singleton(a: A): Set { return new Set([a]) } /** * Insert a value into a set */ export function insert(E: Equal): (a: A) => (set: Set) => Set { const i = insert_(E) return (a) => (set) => i(set, a) } /** * Insert a value into a set */ export function insert_(E: Equal): (set: Set, a: A) => Set { const elemE = elem_(E) return (set, a) => { if (!elemE(set, a)) { const r = new Set(set) r.add(a) return r } else { return set } } } /** * Delete a value from a set */ export function remove(E: Equal): (a: A) => (set: Set) => Set { const rem = remove_(E) return (a) => (set) => rem(set, a) } /** * Delete a value from a set */ export function remove_(E: Equal): (set: Set, a: A) => Set { return (set, a) => filter((ax: A) => !E.equals(a, ax))(set) } /** * If element is present remove it, if not add it */ export function toggle(E: Equal): (a: A) => (set: Set) => Set { const t = toggle_(E) return (a) => (set) => t(set, a) } /** * If element is present remove it, if not add it */ export function toggle_(E: Equal): (set: Set, a: A) => Set { const elemE = elem_(E) const removeE = remove(E) const insertE = insert(E) return (set, a) => (elemE(set, a) ? removeE : insertE)(a)(set) } /** * Create a set from an array */ export function fromArray(E: Equal): (as: ReadonlyArray) => Set { return (as) => { const len = as.length const r = new Set() const has = elem_(E) for (let i = 0; i < len; i++) { const a = as[i]! if (!has(r, a)) { r.add(a) } } return r } } /** * Set compaction, remove none */ export function compact(E: Equal): (fa: Set>) => Set { return filterMap(E)(identity) } /** * Separate elements */ export function separate( EE: Equal, EA: Equal ): (fa: Set>) => Tp.Tuple<[Set, Set]> { return (fa) => { const elemEE = elem_(EE) const elemEA = elem_(EA) const left: MutableSet = new Set() const right: MutableSet = new Set() fa.forEach((e) => { switch (e._tag) { case "Left": if (!elemEE(left, e.left)) { left.add(e.left) } break case "Right": if (!elemEA(right, e.right)) { right.add(e.right) } break } }) return Tp.tuple(left, right) } } /** * Filter + Map */ export function filterMap( E: Equal ): (f: (a: A) => Option) => (fa: Set) => Set { const fm = filterMap_(E) return (f) => (fa) => fm(fa, f) } /** * Filter + Map */ export function filterMap_( E: Equal ): (fa: Set, f: (a: A) => Option) => Set { const elemE = elem_(E) return (fa, f) => { const r: MutableSet = new Set() fa.forEach((a) => { const ob = f(a) if (ob._tag === "Some" && !elemE(r, ob.value)) { r.add(ob.value) } }) return r } } /** * Form the union of two sets */ export function union_(E: Equal): (set: Set, y: Set) => Set { const elemE = elem_(E) return (x, y) => { if (x === empty) { return y } if (y === empty) { return x } const r = new Set(x) y.forEach((e) => { if (!elemE(r, e)) { r.add(e) } }) return r } } /** * Form the union of two sets */ export function union(E: Equal): (y: Set) => (set: Set) => Set { const u = union_(E) return (y) => (x) => u(x, y) }