Extensive collection operations supporting both functional and imperative programming paradigms, with immutable and mutable collection types providing comprehensive data manipulation capabilities.
Comprehensive sequence/enumerable operations matching the F# Seq module, providing lazy evaluation and functional programming patterns.
// Iterator interface
interface IEnumerator<T> {
Current: T;
MoveNext(): boolean;
}
// Enumerable interface
interface IEnumerable<T> {
GetEnumerator(): IEnumerator<T>;
}// Enumerator wrapper around JavaScript iterators
class Enumerator<T> implements IEnumerator<T> {
constructor(iter: Iterator<T>);
MoveNext(): boolean;
readonly Current: T;
Reset(): void;
Dispose(): void;
}
// Conversion functions
function getEnumerator<T>(o: any): IEnumerator<T>;
function toIterator<T>(en: IEnumerator<T>): Iterator<T>;
// Usage
import { getEnumerator, toIterator, Enumerator } from "fable-library/Seq.js";
const array = [1, 2, 3, 4, 5];
const enumerator = getEnumerator(array);
// Iterate using enumerator
while (enumerator.MoveNext()) {
console.log(enumerator.Current);
}
// Convert back to iterator
const iterator = toIterator(enumerator);Create sequences from various sources and patterns.
// Basic creation
function ofArray<T>(xs: ArrayLike<T>): Iterable<T>;
function empty<T>(): Iterable<T>;
function singleton<T>(x: T): Iterable<T>;
// Delayed evaluation
function delay<T>(f: () => Iterable<T>): Iterable<T>;
// Generation patterns
function unfold<T, State>(generator: (state: State) => [T, State] | null, state: State): Iterable<T>;
function range(start: number, count: number): Iterable<number>;
function rangeStep(start: number, step: number, count: number): Iterable<number>;
// Long ranges
function rangeLong(start: Long, count: Long): Iterable<Long>;
function rangeStepLong(start: Long, step: Long, count: Long): Iterable<Long>;
// Usage
import {
ofArray, empty, singleton, delay, unfold,
range, rangeStep
} from "fable-library/Seq.js";
// Create from array
const fromArray = ofArray([1, 2, 3, 4]);
// Empty and singleton
const emptySeq = empty<number>();
const singleItem = singleton(42);
// Delayed computation
const delayedSeq = delay(() => range(1, 5));
// Generate Fibonacci sequence
const fibonacci = unfold(([a, b]) => [[a, [b, a + b]], [a, b]], [0, 1]);
const first10Fib = take(10, fibonacci);
console.log(toArray(first10Fib)); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
// Numeric ranges
const numbers = range(1, 10); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const evens = rangeStep(0, 2, 10); // [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]Transform sequences using functional operations.
// Combining sequences
function append<T>(xs: Iterable<T>, ys: Iterable<T>): Iterable<T>;
function concat<T>(xs: Iterable<Iterable<T>>): Iterable<T>;
// Mapping operations
function map<T, U>(f: (x: T) => U, xs: Iterable<T>): Iterable<U>;
function mapIndexed<T, U>(f: (i: number, x: T) => U, xs: Iterable<T>): Iterable<U>;
function map2<T1, T2, U>(f: (x: T1, y: T2) => U, xs: Iterable<T1>, ys: Iterable<T2>): Iterable<U>;
function map3<T1, T2, T3, U>(f: (x: T1, y: T2, z: T3) => U, xs: Iterable<T1>, ys: Iterable<T2>, zs: Iterable<T3>): Iterable<U>;
// Choose and collect (map + filter)
function choose<T, U>(f: (x: T) => U, xs: Iterable<T>): Iterable<U>;
function collect<T, U>(f: (x: T) => Iterable<U>, xs: Iterable<T>): Iterable<U>;
// Usage
import {
append, concat, map, mapIndexed, map2,
choose, collect, range
} from "fable-library/Seq.js";
const seq1 = range(1, 3); // [1, 2, 3]
const seq2 = range(4, 3); // [4, 5, 6]
// Combine sequences
const combined = append(seq1, seq2); // [1, 2, 3, 4, 5, 6]
const nested = [[1, 2], [3, 4], [5, 6]];
const flattened = concat(nested); // [1, 2, 3, 4, 5, 6]
// Mapping
const doubled = map(x => x * 2, seq1); // [2, 4, 6]
const indexed = mapIndexed((i, x) => `${i}: ${x}`, seq1); // ["0: 1", "1: 2", "2: 3"]
const pairs = map2((x, y) => x + y, seq1, seq2); // [5, 7, 9]
// Choose (map + filter in one step)
const evenDoubled = choose(x => x % 2 === 0 ? x * 2 : null, range(1, 5));
// [4, 8] (only even numbers doubled)
// Collect (flatMap)
const digits = collect(x => x.toString().split(''), [12, 34, 56]);
// ['1', '2', '3', '4', '5', '6']Filter and select sequence elements.
// Basic filtering
function filter<T>(f: (x: T) => boolean, xs: Iterable<T>): Iterable<T>;
function where<T>(f: (x: T) => boolean, xs: Iterable<T>): Iterable<T>; // Alias for filter
function filterIndexed<T>(f: (i: number, x: T) => boolean, xs: Iterable<T>): Iterable<T>;
// Uniqueness
function distinct<T>(xs: Iterable<T>): Iterable<T>;
function distinctBy<T, U>(f: (x: T) => U, xs: Iterable<T>): Iterable<T>;
// Set operations
function except<T>(itemsToExclude: Iterable<T>, source: Iterable<T>): Iterable<T>;
// Usage
import {
filter, filterIndexed, distinct,
distinctBy, except, range
} from "fable-library/Seq.js";
const numbers = range(1, 10); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// Basic filtering
const evens = filter(x => x % 2 === 0, numbers); // [2, 4, 6, 8, 10]
const evenIndices = filterIndexed((i, x) => i % 2 === 0, numbers); // [1, 3, 5, 7, 9]
// Remove duplicates
const withDuplicates = [1, 2, 2, 3, 3, 3, 4];
const unique = distinct(withDuplicates); // [1, 2, 3, 4]
// Distinct by property
const people = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 25 }
];
const uniqueAges = distinctBy(p => p.age, people); // Alice and Bob only
// Exclude items
const excluded = except([2, 4], numbers); // [1, 3, 5, 6, 7, 8, 9, 10]Reduce sequences to single values using various aggregation strategies.
// Folding (reduce)
function fold<T, State>(f: (acc: State, x: T) => State, seed: State, xs: Iterable<T>): State;
function foldBack<T, State>(f: (x: T, acc: State) => State, xs: Iterable<T>, seed: State): State;
function fold2<T1, T2, State>(f: (acc: State, x: T1, y: T2) => State, seed: State, xs: Iterable<T1>, ys: Iterable<T2>): State;
function reduce<T>(f: (acc: T, x: T) => T, xs: Iterable<T>): T;
function reduceBack<T>(f: (x: T, acc: T) => T, xs: Iterable<T>): T;
// Mathematical aggregations
function sum<T>(xs: Iterable<T>, adder: IGenericAdder<T>): T;
function sumBy<T, U>(f: (x: T) => U, xs: Iterable<T>, adder: IGenericAdder<U>): U;
function max<T>(xs: Iterable<T>): T;
function maxBy<T, U>(f: (x: T) => U, xs: Iterable<T>): T;
function min<T>(xs: Iterable<T>): T;
function minBy<T, U>(f: (x: T) => U, xs: Iterable<T>): T;
function average<T>(xs: Iterable<T>, averager: IGenericAverager<T>): T;
function averageBy<T, T2>(f: (a: T) => T2, xs: Iterable<T>, averager: IGenericAverager<T2>): T2;
// Usage
import {
fold, reduce, sum, max, min,
sumBy, maxBy, range
} from "fable-library/Seq.js";
const numbers = range(1, 5); // [1, 2, 3, 4, 5]
// Folding
const sum1 = fold((acc, x) => acc + x, 0, numbers); // 15
const product = reduce((acc, x) => acc * x, numbers); // 120
// Mathematical operations (with appropriate adders)
const total = sum(numbers, { Add: (x, y) => x + y, Zero: 0 }); // 15
const maximum = max(numbers); // 5
const minimum = min(numbers); // 1
// By projection
const people = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 35 }
];
const totalAge = sumBy(p => p.age, people, { Add: (x, y) => x + y, Zero: 0 }); // 90
const oldest = maxBy(p => p.age, people); // CharlieFind elements and positions within sequences.
// Finding elements
function find<T>(f: (x: T) => boolean, xs: Iterable<T>): T;
function findBack<T>(f: (x: T) => boolean, xs: Iterable<T>): T;
function tryFind<T>(f: (x: T) => boolean, xs: Iterable<T>): T | null;
function tryFindBack<T>(f: (x: T) => boolean, xs: Iterable<T>): T | null;
// Finding indices
function findIndex<T>(f: (x: T) => boolean, xs: Iterable<T>): number;
function findIndexBack<T>(f: (x: T) => boolean, xs: Iterable<T>): number;
function tryFindIndex<T>(f: (x: T) => boolean, xs: Iterable<T>): number | null;
function tryFindIndexBack<T>(f: (x: T) => boolean, xs: Iterable<T>): number | null;
// Pick (find and transform)
function pick<T, U>(f: (x: T) => U, xs: Iterable<T>): U;
function tryPick<T, U>(f: (x: T) => U, xs: Iterable<T>): U | null;
// Usage
import {
find, tryFind, findIndex, tryFindIndex,
pick, tryPick
} from "fable-library/Seq.js";
const numbers = [1, 3, 5, 8, 10, 12];
// Find elements
const firstEven = find(x => x % 2 === 0, numbers); // 8
const maybeNegative = tryFind(x => x < 0, numbers); // null
// Find indices
const evenIndex = findIndex(x => x % 2 === 0, numbers); // 3
const negativeIndex = tryFindIndex(x => x < 0, numbers); // null
// Pick with transformation
const people = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 35 }
];
const firstAdult = pick(p => p.age >= 30 ? p.name : null, people); // "Bob"
const firstSenior = tryPick(p => p.age >= 65 ? p.name : null, people); // nullTest conditions across sequence elements.
// Element existence
function contains<T>(x: T, xs: Iterable<T>): boolean;
// Condition testing
function exists<T>(f: (x: T) => boolean, xs: Iterable<T>): boolean;
function exists2<T1, T2>(f: (x: T1, y: T2) => boolean, xs: Iterable<T1>, ys: Iterable<T2>): boolean;
function forAll<T>(f: (x: T) => boolean, xs: Iterable<T>): boolean;
function forAll2<T1, T2>(f: (x: T1, y: T2) => boolean, xs: Iterable<T1>, ys: Iterable<T2>): boolean;
// Usage
import { contains, exists, forAll, range } from "fable-library/Seq.js";
const numbers = range(1, 5); // [1, 2, 3, 4, 5]
// Element existence
console.log(contains(3, numbers)); // true
console.log(contains(7, numbers)); // false
// Condition testing
console.log(exists(x => x > 3, numbers)); // true (4 and 5)
console.log(exists(x => x > 10, numbers)); // false
console.log(forAll(x => x > 0, numbers)); // true (all positive)
console.log(forAll(x => x < 3, numbers)); // false (not all < 3)
// Pairs testing
const evens = [2, 4, 6];
const odds = [1, 3, 5];
console.log(forAll2((x, y) => (x + y) % 2 === 1, evens, odds)); // true (even + odd = odd)Access individual elements by position or condition.
// Head/tail access
function head<T>(xs: Iterable<T>): T;
function tryHead<T>(xs: Iterable<T>): T | null;
function last<T>(xs: Iterable<T>): T;
function tryLast<T>(xs: Iterable<T>): T | null;
// Single element
function exactlyOne<T>(xs: Iterable<T>): T;
// Indexed access
function item<T>(i: number, xs: Iterable<T>): T;
function tryItem<T>(i: number, xs: Iterable<T>): T | null;
function nth<T>(i: number, xs: Iterable<T>): T; // Alias for item
// Usage
import {
head, tryHead, last, tryLast, exactlyOne,
item, tryItem, range
} from "fable-library/Seq.js";
const numbers = range(1, 5); // [1, 2, 3, 4, 5]
const empty = [];
const single = [42];
// Head/tail
console.log(head(numbers)); // 1
console.log(tryHead(empty)); // null
console.log(last(numbers)); // 5
console.log(tryLast(empty)); // null
// Single element validation
console.log(exactlyOne(single)); // 42
// exactlyOne(numbers); // Would throw (more than one element)
// exactlyOne(empty); // Would throw (no elements)
// Indexed access
console.log(item(2, numbers)); // 3 (0-based indexing)
console.log(tryItem(10, numbers)); // null (out of bounds)Extract portions of sequences.
// Take/skip operations
function take<T>(n: number, xs: Iterable<T>): Iterable<T>;
function takeWhile<T>(f: (x: T) => boolean, xs: Iterable<T>): Iterable<T>;
function skip<T>(n: number, xs: Iterable<T>): Iterable<T>;
function skipWhile<T>(f: (x: T) => boolean, xs: Iterable<T>): Iterable<T>;
// Tail operations
function tail<T>(xs: Iterable<T>): Iterable<T>;
// Windowing
function windowed<T>(n: number, xs: Iterable<T>): Iterable<T[]>;
function pairwise<T>(xs: Iterable<T>): Iterable<[T, T]>;
// Usage
import {
take, takeWhile, skip, skipWhile,
tail, windowed, pairwise, range
} from "fable-library/Seq.js";
const numbers = range(1, 10); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// Take/skip
const first5 = take(5, numbers); // [1, 2, 3, 4, 5]
const whileLessThan5 = takeWhile(x => x < 5, numbers); // [1, 2, 3, 4]
const after3 = skip(3, numbers); // [4, 5, 6, 7, 8, 9, 10]
const afterFirstFive = skipWhile(x => x <= 5, numbers); // [6, 7, 8, 9, 10]
// Tail (all but first)
const allButFirst = tail(numbers); // [2, 3, 4, 5, 6, 7, 8, 9, 10]
// Windowing (sliding windows)
const windows3 = windowed(3, take(5, numbers));
// [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
// Pairwise (consecutive pairs)
const pairs = pairwise(take(4, numbers));
// [[1, 2], [2, 3], [3, 4]]Execute side effects for each element.
// Basic iteration
function iterate<T>(f: (x: T) => void, xs: Iterable<T>): void;
function iterateIndexed<T>(f: (i: number, x: T) => void, xs: Iterable<T>): void;
// Paired iteration
function iterate2<T1, T2>(f: (x: T1, y: T2) => void, xs: Iterable<T1>, ys: Iterable<T2>): void;
function iterateIndexed2<T1, T2>(f: (i: number, x: T1, y: T2) => void, xs: Iterable<T1>, ys: Iterable<T2>): void;
// Usage
import { iterate, iterateIndexed, iterate2, range } from "fable-library/Seq.js";
const numbers = range(1, 5); // [1, 2, 3, 4, 5]
// Simple iteration
iterate(x => console.log(`Value: ${x}`), numbers);
// Output: Value: 1, Value: 2, Value: 3, Value: 4, Value: 5
// Indexed iteration
iterateIndexed((i, x) => console.log(`[${i}] = ${x}`), numbers);
// Output: [0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5
// Paired iteration
const letters = ['a', 'b', 'c', 'd', 'e'];
iterate2((num, letter) => console.log(`${num}${letter}`), numbers, letters);
// Output: 1a, 2b, 3c, 4d, 5e// Comparison
function compareWith<T>(f: (x: T, y: T) => number, xs: Iterable<T>, ys: Iterable<T>): number;
function equals<T>(xs: Iterable<T>, ys: Iterable<T>): boolean;
// Conversion
function toArray<T>(xs: Iterable<T>): T[];
function toList<T>(xs: Iterable<T>): any; // Returns F# List
function ofList<T>(xs: any): Iterable<T>; // From F# List
// Usage
import { compareWith, equals, toArray, range } from "fable-library/Seq.js";
const seq1 = range(1, 3); // [1, 2, 3]
const seq2 = range(1, 3); // [1, 2, 3]
const seq3 = range(1, 4); // [1, 2, 3, 4]
// Comparison
console.log(equals(seq1, seq2)); // true
console.log(equals(seq1, seq3)); // false
const comparison = compareWith((x, y) => x - y, seq1, seq3);
console.log(comparison); // -1 (seq1 < seq3)
// Convert to array
const array = toArray(seq1); // [1, 2, 3]
console.log(Array.isArray(array)); // true// Caching and utility
function cache<T>(xs: Iterable<T>): Iterable<T>;
function length<T>(xs: Iterable<T>): number;
function isEmpty<T>(xs: Iterable<T>): boolean;
// Resource management
function enumerateUsing<T extends IDisposable, U>(disp: T, work: (x: T) => Iterable<U>): Iterable<U>;
function enumerateThenFinally<T>(xs: Iterable<T>, finalFn: () => void): Iterable<T>;
function enumerateWhile<T>(cond: () => boolean, xs: Iterable<T>): Iterable<T>;
// Usage
import { cache, length, isEmpty, enumerateThenFinally } from "fable-library/Seq.js";
const expensiveSeq = map(x => {
console.log(`Computing ${x}`);
return x * x;
}, range(1, 5));
// Cache results to avoid recomputation
const cachedSeq = cache(expensiveSeq);
// These won't recompute
console.log(length(cachedSeq)); // 5 (computed once)
console.log(toArray(cachedSeq)); // [1, 4, 9, 16, 25] (uses cached results)
// Resource management with cleanup
const withCleanup = enumerateThenFinally(
range(1, 3),
() => console.log("Cleanup performed")
);
toArray(withCleanup); // Processes sequence, then calls cleanup// Grouping operations
function groupBy<T, K>(f: (x: T) => K, xs: Iterable<T>): Iterable<[K, Iterable<T>]>;
function countBy<T, K>(f: (x: T) => K, xs: Iterable<T>): Iterable<[K, number]>;
// Sorting operations
function sort<T>(xs: Iterable<T>): Iterable<T>;
function sortBy<T, U>(f: (x: T) => U, xs: Iterable<T>): Iterable<T>;
function sortWith<T>(f: (x: T, y: T) => number, xs: Iterable<T>): Iterable<T>;
function sortDescending<T>(xs: Iterable<T>): Iterable<T>;
function sortByDescending<T, U>(f: (x: T) => U, xs: Iterable<T>): Iterable<T>;
// Usage
import { groupBy, countBy, sort, sortBy, sortWith } from "fable-library/Seq.js";
const words = ["apple", "banana", "apricot", "blueberry", "avocado"];
// Group by first letter
const grouped = groupBy(word => word[0], words);
// [['a', ['apple', 'apricot', 'avocado']], ['b', ['banana', 'blueberry']]]
// Count by length
const lengthCounts = countBy(word => word.length, words);
// [[5, 2], [6, 2], [7, 1]] (2 words of length 5, etc.)
// Sorting
const sorted = sort(words); // Alphabetical order
const byLength = sortBy(word => word.length, words); // By length
const customSort = sortWith((a, b) => b.length - a.length, words); // By length descending
console.log(toArray(sorted)); // ['apple', 'apricot', 'avocado', 'banana', 'blueberry']
console.log(toArray(byLength)); // ['apple', 'banana', 'apricot', 'avocado', 'blueberry']F# Array module providing JavaScript-native array operations with F# semantics, optimized for performance while maintaining functional programming patterns.
The Array module provides both functional operations and imperative helpers for efficient array manipulation.
// Core array creation and manipulation (internal helpers)
function createArrayFromImpl<T>(_: T[]): T[];
function newDynamicArrayImpl<T>(len: number): T[];
function isTypedArrayImpl(arr: any): boolean;
function typedArraySetImpl(target: any, source: any, offset: number): void;
// Array operations
function appendImpl<T>(array1: T[], array2: T[]): T[];
function concatImpl<T>(array1: T[], arrays: T[][]): T[];
function fillImpl<T>(array: T[], value: T, start: number, count: number): void;
// Usage (these are typically used internally by higher-level functions)
import { appendImpl, concatImpl, fillImpl } from "fable-library/Array.js";
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = appendImpl(arr1, arr2); // [1, 2, 3, 4, 5, 6]
const arrays = [[7, 8], [9, 10]];
const concatenated = concatImpl(combined, arrays); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const filled = new Array(5);
fillImpl(filled, 42, 0, 5); // [42, 42, 42, 42, 42]// Folding operations
function foldImpl<T, State>(folder: (acc: State, x: T) => State, state: State, array: T[]): State;
function foldIndexedImpl<T, State>(folder: (i: number, acc: State, x: T) => State, state: State, array: T[]): State;
function foldBackImpl<T, State>(folder: (x: T, acc: State) => State, state: State, array: T[]): State;
// Iteration
function iterImpl<T>(action: (x: T) => void, array: T[]): void;
function iterIndexedImpl<T>(action: (i: number, x: T) => void, array: T[]): void;
// Mapping
function mapImpl<T, U>(mapping: (x: T) => U, array: T[]): U[];
function mapIndexedImpl<T, U>(mapping: (i: number, x: T) => U, array: T[]): U[];
// Usage
import {
foldImpl, foldIndexedImpl, iterImpl,
mapImpl, mapIndexedImpl
} from "fable-library/Array.js";
const numbers = [1, 2, 3, 4, 5];
// Folding
const sum = foldImpl((acc, x) => acc + x, 0, numbers); // 15
const indexedSum = foldIndexedImpl((i, acc, x) => acc + (i * x), 0, numbers); // 40
// Iteration with side effects
iterImpl(x => console.log(`Value: ${x}`), numbers);
iterIndexedImpl((i, x) => console.log(`[${i}] = ${x}`), numbers);
// Mapping
const doubled = mapImpl(x => x * 2, numbers); // [2, 4, 6, 8, 10]
const indexed = mapIndexedImpl((i, x) => `${i}:${x}`, numbers); // ["0:1", "1:2", "2:3", "3:4", "4:5"]// Array manipulation
function reverseImpl<T>(array: T[]): T[];
function copyImpl<T>(array: T[]): T[];
function subArrayImpl<T>(array: T[], start: number, count: number): T[];
// Search operations
function indexOfImpl<T>(array: T[], item: T): number;
function findImpl<T>(predicate: (x: T) => boolean, array: T[]): T | null;
function findIndexImpl<T>(predicate: (x: T) => boolean, array: T[]): number;
// Collection operations
function collectImpl<T, U>(mapping: (x: T) => U[], array: T[]): U[];
// Usage
import {
reverseImpl, copyImpl, subArrayImpl,
findImpl, findIndexImpl, collectImpl
} from "fable-library/Array.js";
const original = [1, 2, 3, 4, 5];
// Array manipulation
const reversed = reverseImpl(original); // [5, 4, 3, 2, 1]
const copied = copyImpl(original); // [1, 2, 3, 4, 5] (new array)
const sub = subArrayImpl(original, 1, 3); // [2, 3, 4]
// Search
const found = findImpl(x => x > 3, original); // 4
const foundIndex = findIndexImpl(x => x > 3, original); // 3
// Collect (flatMap)
const words = ["hello", "world"];
const chars = collectImpl(word => word.split(''), words);
// ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']F# List module providing immutable linked list operations with structural sharing for efficient functional programming.
// Head and tail operations
function head<T>(list: List<T>): T;
function tryHead<T>(list: List<T>): T | null;
function tail<T>(list: List<T>): List<T>;
function last<T>(list: List<T>): T;
function tryLast<T>(list: List<T>): T | null;
// Usage
import { head, tryHead, tail, last } from "fable-library/List.js";
import { List } from "fable-library/Types.js";
// Create list: [1, 2, 3, 4]
const list = new List(1, new List(2, new List(3, new List(4, null))));
console.log(head(list)); // 1
console.log(tail(list)); // List containing [2, 3, 4]
console.log(last(list)); // 4
// Safe operations
const empty = null;
console.log(tryHead(empty)); // null
console.log(tryLast(empty)); // null// Compare lists element by element
function compareWith<T>(comparer: (x: T, y: T) => number, list1: List<T>, list2: List<T>): number;
// Usage
import { compareWith } from "fable-library/List.js";
const list1 = new List(1, new List(2, new List(3, null)));
const list2 = new List(1, new List(2, new List(4, null)));
const comparison = compareWith((x, y) => x - y, list1, list2);
console.log(comparison); // -1 (list1 < list2 because 3 < 4)// Internal indexed folding operations
function foldIndexedAux<T, State>(
folder: (i: number, acc: State, x: T) => State,
index: number,
acc: State,
list: List<T>
): State;
function foldIndexed<T, State>(
folder: (i: number, acc: State, x: T) => State,
acc: State,
list: List<T>
): State;
// Usage
import { foldIndexed } from "fable-library/List.js";
const list = new List(10, new List(20, new List(30, null)));
// Sum with index weights
const weightedSum = foldIndexed(
(i, acc, x) => acc + (i * x),
0,
list
);
// (0 * 10) + (1 * 20) + (2 * 30) = 0 + 20 + 60 = 80
console.log(weightedSum); // 80F# Set module providing immutable set operations with comparison support for custom equality and ordering.
Sets in F# are immutable and ordered, typically implemented as balanced trees for efficient operations.
// Set creation from sequences
val ofSeq : seq<'T> -> Set<'T> when 'T : comparison
val ofList : 'T list -> Set<'T> when 'T : comparison
val ofArray : 'T[] -> Set<'T> when 'T : comparison
// Basic set operations
val add : 'T -> Set<'T> -> Set<'T> when 'T : comparison
val remove : 'T -> Set<'T> -> Set<'T> when 'T : comparison
val contains : 'T -> Set<'T> -> bool when 'T : comparison
// Set properties
val isEmpty : Set<'T> -> bool when 'T : comparison
val count : Set<'T> -> int when 'T : comparison
// Usage in F#
let numbers = Set.ofList [1; 3; 5; 7; 9]
let withTwo = Set.add 2 numbers
let withoutFive = Set.remove 5 numbers
let hasThree = Set.contains 3 numbers // true// Set algebra
val union : Set<'T> -> Set<'T> -> Set<'T> when 'T : comparison
val intersect : Set<'T> -> Set<'T> -> Set<'T> when 'T : comparison
val difference : Set<'T> -> Set<'T> -> Set<'T> when 'T : comparison
// Set relationships
val isSubset : Set<'T> -> Set<'T> -> bool when 'T : comparison
val isSuperset : Set<'T> -> Set<'T> -> bool when 'T : comparison
val isProperSubset : Set<'T> -> Set<'T> -> bool when 'T : comparison
val isProperSuperset : Set<'T> -> Set<'T> -> bool when 'T : comparison
// Usage
let evens = Set.ofList [2; 4; 6; 8]
let odds = Set.ofList [1; 3; 5; 7]
let smallNumbers = Set.ofList [1; 2; 3; 4]
let all = Set.union evens odds
let none = Set.intersect evens odds // empty set
let evenMinusSmall = Set.difference evens smallNumbers
let smallIsSubset = Set.isSubset smallNumbers all // trueF# Map module providing immutable dictionary/map operations with key comparison for efficient lookups and updates.
// Map creation
val empty<'Key, 'Value> : Map<'Key, 'Value> when 'Key : comparison
val ofSeq : seq<'Key * 'Value> -> Map<'Key, 'Value> when 'Key : comparison
val ofList : ('Key * 'Value) list -> Map<'Key, 'Value> when 'Key : comparison
val ofArray : ('Key * 'Value)[] -> Map<'Key, 'Value> when 'Key : comparison
// Access operations
val find : 'Key -> Map<'Key, 'Value> -> 'Value when 'Key : comparison
val tryFind : 'Key -> Map<'Key, 'Value> -> 'Value option when 'Key : comparison
val containsKey : 'Key -> Map<'Key, 'Value> -> bool when 'Key : comparison
// Usage in F#
let phoneBook = Map.ofList [
("Alice", "555-1234")
("Bob", "555-5678")
("Charlie", "555-9012")
]
let aliceNumber = Map.find "Alice" phoneBook
let maybeEve = Map.tryFind "Eve" phoneBook // None
let hasBob = Map.containsKey "Bob" phoneBook // true// Add/update/remove
val add : 'Key -> 'Value -> Map<'Key, 'Value> -> Map<'Key, 'Value> when 'Key : comparison
val remove : 'Key -> Map<'Key, 'Value> -> Map<'Key, 'Value> when 'Key : comparison
val change : 'Key -> ('Value option -> 'Value option) -> Map<'Key, 'Value> -> Map<'Key, 'Value> when 'Key : comparison
// Map properties
val isEmpty : Map<'Key, 'Value> -> bool when 'Key : comparison
val count : Map<'Key, 'Value> -> int when 'Key : comparison
// Usage
let updated = Map.add "Dave" "555-3456" phoneBook
let withoutAlice = Map.remove "Alice" phoneBook
let incrementOrAdd key amount map =
Map.change key (function
| Some existing -> Some (existing + amount)
| None -> Some amount) map
let counters = Map.empty |> incrementOrAdd "clicks" 1 |> incrementOrAdd "views" 5// Transform values
val map : ('Key -> 'Value1 -> 'Value2) -> Map<'Key, 'Value1> -> Map<'Key, 'Value2> when 'Key : comparison
// Filter operations
val filter : ('Key -> 'Value -> bool) -> Map<'Key, 'Value> -> Map<'Key, 'Value> when 'Key : comparison
// Folding
val fold : ('State -> 'Key -> 'Value -> 'State) -> 'State -> Map<'Key, 'Value> -> 'State when 'Key : comparison
val foldBack : ('Key -> 'Value -> 'State -> 'State) -> Map<'Key, 'Value> -> 'State -> 'State when 'Key : comparison
// Usage
let scores = Map.ofList [("Alice", 85); ("Bob", 92); ("Charlie", 78)]
// Transform all values
let percentages = Map.map (fun name score -> float score / 100.0) scores
// Filter high scores
let highScores = Map.filter (fun name score -> score >= 90) scores
// Calculate statistics
let (total, count) = Map.fold (fun (sum, cnt) name score -> (sum + score, cnt + 1)) (0, 0) scores
let average = float total / float countMutable collection wrappers providing .NET Dictionary and HashSet interfaces over JavaScript Map and Set.
Mutable dictionary implementation wrapping JavaScript Map.
class Dictionary<K, V> {
constructor(source?: Iterable<[K, V]>, comparer?: IEqualityComparer<K>);
// Properties
readonly size: number;
// Basic operations
clear(): void;
delete(k: K): boolean;
get(k: K): V | undefined;
has(k: K): boolean;
set(k: K, v: V): Dictionary<K, V>;
// Iteration
entries(): Iterator<[K, V]>;
keys(): Iterator<K>;
values(): Iterator<V>;
// Implements Symbol.iterator
[Symbol.iterator](): Iterator<[K, V]>;
}
// Usage
import { Dictionary } from "fable-library/DictTypes.js";
// Create dictionary
const dict = new Dictionary<string, number>();
// Add entries
dict.set("apple", 5);
dict.set("banana", 3);
dict.set("cherry", 8);
console.log(dict.size); // 3
console.log(dict.get("apple")); // 5
console.log(dict.has("grape")); // false
// Iterate
for (const [key, value] of dict) {
console.log(`${key}: ${value}`);
}
// Clear all entries
dict.clear();
console.log(dict.size); // 0Mutable set implementation wrapping JavaScript Set.
class HashSet<T> {
constructor(source?: Iterable<T>, comparer?: IEqualityComparer<T>);
// Properties
readonly size: number;
// Basic operations
add(v: T): HashSet<T>;
clear(): void;
delete(k: T): boolean;
has(k: T): boolean;
// Iteration
values(): Iterator<T>;
// Implements Symbol.iterator
[Symbol.iterator](): Iterator<T>;
}
// Usage
import { HashSet } from "fable-library/DictTypes.js";
// Create hash set
const set = new HashSet<string>();
// Add values
set.add("red");
set.add("green");
set.add("blue");
set.add("red"); // Duplicate ignored
console.log(set.size); // 3
console.log(set.has("green")); // true
console.log(set.has("yellow")); // false
// Iterate
for (const color of set) {
console.log(color);
}
// Remove value
set.delete("green");
console.log(set.size); // 2import { Dictionary, HashSet } from "fable-library/DictTypes.js";
import { equals } from "fable-library/Util.js";
// Custom equality comparer for complex objects
const personComparer = {
Equals: (x: Person, y: Person) => x.id === y.id,
GetHashCode: (x: Person) => x.id.length // Simple hash
};
interface Person {
id: string;
name: string;
age: number;
}
// Dictionary with custom comparer
const people = new Dictionary<Person, string[]>([], personComparer);
const alice: Person = { id: "001", name: "Alice", age: 30 };
const bob: Person = { id: "002", name: "Bob", age: 25 };
people.set(alice, ["Programming", "Reading"]);
people.set(bob, ["Sports", "Gaming"]);
// Lookup by equivalent object
const aliceClone: Person = { id: "001", name: "Alice Smith", age: 31 };
console.log(people.has(aliceClone)); // true (same ID)
console.log(people.get(aliceClone)); // ["Programming", "Reading"]
// HashSet with custom comparer
const uniquePeople = new HashSet<Person>([], personComparer);
uniquePeople.add(alice);
uniquePeople.add(aliceClone); // Not added (same ID)
console.log(uniquePeople.size); // 1// Dictionary operations are O(1) average case for:
// - get/set/has/delete operations
// - Based on JavaScript Map performance
const performanceTest = () => {
const dict = new Dictionary<number, string>();
// Insertion performance
console.time("Dictionary insertion");
for (let i = 0; i < 100000; i++) {
dict.set(i, `value_${i}`);
}
console.timeEnd("Dictionary insertion");
// Lookup performance
console.time("Dictionary lookup");
for (let i = 0; i < 100000; i++) {
dict.get(i);
}
console.timeEnd("Dictionary lookup");
// Deletion performance
console.time("Dictionary deletion");
for (let i = 0; i < 50000; i++) {
dict.delete(i);
}
console.timeEnd("Dictionary deletion");
};// HashSet operations are O(1) average case
// Excellent for membership testing and uniqueness
const setPerformanceTest = () => {
const set = new HashSet<number>();
// Addition performance
console.time("HashSet addition");
for (let i = 0; i < 100000; i++) {
set.add(i);
set.add(i); // Duplicates are handled efficiently
}
console.timeEnd("HashSet addition");
// Membership testing
console.time("HashSet membership");
for (let i = 0; i < 100000; i++) {
set.has(i);
}
console.timeEnd("HashSet membership");
console.log(`Final set size: ${set.size}`); // 100000
};