or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

async-programming.mdcharacter-operations.mdcollections.mdconfiguration.mdcore-infrastructure.mddata-encoding.mddate-time.mdexternal-integration.mdindex.mdnumeric-types.mdreactive-programming.mdstring-operations.mdtype-system.md
tile.json

collections.mddocs/

Collections

Extensive collection operations supporting both functional and imperative programming paradigms, with immutable and mutable collection types providing comprehensive data manipulation capabilities.

Seq Module - Sequence Operations

Comprehensive sequence/enumerable operations matching the F# Seq module, providing lazy evaluation and functional programming patterns.

Core Interfaces

// Iterator interface
interface IEnumerator<T> {
    Current: T;
    MoveNext(): boolean;
}

// Enumerable interface
interface IEnumerable<T> {
    GetEnumerator(): IEnumerator<T>;
}

Enumerator Implementation

// 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);

Creation Functions

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]

Transformation Functions

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']

Filtering Functions

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]

Aggregation Functions

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); // Charlie

Search Functions

Find 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); // null

Existence and Quantification

Test 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)

Element Access

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)

Slicing Functions

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]]

Iteration Functions

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 and Conversion

// 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

Utility and Resource Management

// 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 and Sorting

// 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']

Array Module - Array Operations

F# Array module providing JavaScript-native array operations with F# semantics, optimized for performance while maintaining functional programming patterns.

Core Array Operations

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]

Functional Array Operations

// 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 Utilities

// 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']

List Module - List Operations

F# List module providing immutable linked list operations with structural sharing for efficient functional programming.

Basic List Operations

// 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

List Comparison

// 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)

Indexed Operations

// 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); // 80

Set Module - Set Operations

F# Set module providing immutable set operations with comparison support for custom equality and ordering.

Set Creation and Basic Operations

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 Operations

// 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  // true

Map Module - Map Operations

F# Map module providing immutable dictionary/map operations with key comparison for efficient lookups and updates.

Map Creation and Access

// 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

Map Modification

// 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

Map Transformations

// 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 count

DictTypes Module - Mutable Collections

Mutable collection wrappers providing .NET Dictionary and HashSet interfaces over JavaScript Map and Set.

Dictionary Class

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); // 0

HashSet Class

Mutable 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); // 2

Integration with F# Collections

import { 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

Performance Characteristics

Dictionary Performance

// 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 Performance

// 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
};