UNPKG

@chris5855/scats

Version:

A comprehensive TypeScript library bringing Scala's powerful functional programming paradigms to JavaScript/TypeScript, featuring immutable collections, monads, pattern matching, and more

1 lines 283 kB
{"version":3,"sources":["../src/index.ts","../src/Option.ts","../src/Either.ts","../src/Try.ts","../src/ExecutionContext.ts","../src/List.ts","../src/Map.ts","../src/Set.ts","../src/collections/Iterable.ts","../src/collections/AbstractSeq.ts","../src/collections/ArraySeq.ts","../src/collections/ArrayBuffer.ts","../src/lazylist/LazyList.ts","../src/vector/Vector.ts","../src/Match.ts","../src/ForComprehension.ts","../src/TypeClass.ts","../src/tuple/Tuple.ts","../src/ordering/Ordering.ts","../src/using/Using.ts","../src/monads/state/State.ts","../src/monads/writer/Writer.ts"],"sourcesContent":["/**\n * scats - Scala-like functional programming patterns for TypeScript\n *\n * This library brings Scala-inspired functional programming concepts to TypeScript,\n * providing a type-safe and ergonomic way to write functional code in TypeScript.\n */\n\n// Core data types\nexport {\n Option, Some, None,\n // We need to explicitly exclude these from Option.ts\n // as they are forward declarations that conflict with Either.ts\n} from './Option';\n\nexport {\n Either, Left, Right\n} from './Either';\n\nexport {\n Try, Success, Failure, TryAsync\n} from './Try';\n\nexport {\n ExecutionContext\n} from './ExecutionContext';\n\n// Collections\nexport { List } from './List';\nexport { Map } from './Map';\nexport { Set } from './Set';\nexport * from './collections/Iterable';\nexport type { Seq, LinearSeq, IndexedSeq, MutableIndexedSeq, Buffer } from './collections/Seq';\nexport { ArraySeq } from './collections/ArraySeq';\nexport { ArrayBuffer } from './collections/ArrayBuffer';\n\n// LazyList for infinite sequences and lazy evaluation\nexport { LazyList } from './LazyList';\n\n\n// Vector for efficient indexed sequences\nexport { Vector } from './vector';\n\n// Pattern matching\nexport {\n match, when, otherwise, extract, value, object,\n array, or, and, not, type\n} from './Match';\nexport type { Pattern } from './Match';\n\n// For-comprehensions\nexport {\n For, ForComprehension, ForComprehensionBuilder\n} from './ForComprehension';\nexport type { Monad, Env } from './ForComprehension';\n\n// Type classes\nexport type { TypeClass } from './TypeClass';\nexport {\n TypeClassRegistry, GlobalTypeClassRegistry,\n register, extension, withContext\n} from './TypeClass';\n\n// Tuples\nexport * from './tuple';\n\n// Ordering\nexport * from './ordering';\n\n// Resource management\nexport * from './using';\n\n// Monads (including new Reader monad)\nexport * from './monads';\n","/**\n * Option<A> represents an optional value that may or may not be present.\n * It's a type-safe alternative to using null or undefined.\n * \n * @example\n * ```ts\n * import { Option, Some, None } from 'scats';\n * \n * // Creating options\n * const a = Some(42);\n * const b = None;\n * const c = Option.fromNullable(maybeNull);\n * \n * // Using options\n * const result = a\n * .map(n => n * 2)\n * .flatMap(n => n > 50 ? Some(n) : None)\n * .getOrElse(0);\n * ```\n */\n\n/**\n * Option<A> interface that all option implementations must satisfy\n */\nexport interface Option<A> {\n /**\n * Returns true if the option is a Some, false otherwise\n */\n readonly isSome: boolean;\n\n /**\n * Returns true if the option is a None, false otherwise\n */\n readonly isNone: boolean;\n\n /**\n * Returns the value if this is a Some, otherwise throws an error\n * @throws Error if the option is None\n */\n get(): A;\n\n /**\n * Returns the value if this is a Some, otherwise returns the provided default value\n */\n getOrElse<B>(defaultValue: B): A | B;\n\n /**\n * Returns the value if this is a Some, otherwise returns the result of the provided function\n */\n getOrCall<B>(f: () => B): A | B;\n\n /**\n * Returns the value if this is a Some, otherwise throws the provided error\n */\n getOrThrow(error: Error): A;\n\n /**\n * Maps the value if this is a Some, otherwise returns None\n */\n map<B>(f: (a: A) => B): Option<B>;\n\n /**\n * Maps the value if this is a Some, otherwise returns the provided default value wrapped in Some\n */\n mapOr<B>(defaultValue: B, f: (a: A) => B): Option<B>;\n\n /**\n * Returns the result of applying f if this is a Some, otherwise returns None\n */\n flatMap<B>(f: (a: A) => Option<B>): Option<B>;\n\n /**\n * Returns the option if it is a Some, otherwise returns the provided option\n */\n orElse<B>(alternative: Option<B>): Option<A | B>;\n\n /**\n * Returns the option if it is a Some, otherwise returns the result of the provided function\n */\n orCall<B>(f: () => Option<B>): Option<A | B>;\n\n /**\n * Returns None if the predicate is not satisfied, otherwise returns this option\n */\n filter(predicate: (a: A) => boolean): Option<A>;\n\n /**\n * Executes the provided function if this is a Some\n */\n forEach(f: (a: A) => void): void;\n\n /**\n * Converts the option to an array with the value if it's a Some, or an empty array if it's a None\n */\n toArray(): A[];\n\n /**\n * Converts this option to an Either with the provided left value if this is a None\n */\n toEither<E>(left: E): Either<E, A>;\n\n /**\n * Returns the result of applying the appropriate function\n */\n match<B>(patterns: { Some: (value: A) => B; None: () => B }): B;\n}\n\n/**\n * Some<A> represents an optional value that is present\n */\nexport class SomeImpl<A> implements Option<A> {\n constructor(private readonly value: A) {\n if (value === null || value === undefined) {\n throw new Error(\"Cannot create Some with null or undefined value\");\n }\n }\n\n get isSome(): boolean {\n return true;\n }\n\n get isNone(): boolean {\n return false;\n }\n\n get(): A {\n return this.value;\n }\n\n getOrElse<B>(_defaultValue: B): A {\n return this.value;\n }\n\n getOrCall<B>(_f: () => B): A {\n return this.value;\n }\n\n getOrThrow(_error: Error): A {\n return this.value;\n }\n\n map<B>(f: (a: A) => B): Option<B> {\n return Some(f(this.value));\n }\n\n mapOr<B>(_defaultValue: B, f: (a: A) => B): Option<B> {\n return Some(f(this.value));\n }\n\n flatMap<B>(f: (a: A) => Option<B>): Option<B> {\n return f(this.value);\n }\n\n orElse<B>(_alternative: Option<B>): Option<A> {\n return this;\n }\n\n orCall<B>(_f: () => Option<B>): Option<A> {\n return this;\n }\n\n filter(predicate: (a: A) => boolean): Option<A> {\n return predicate(this.value) ? this : None;\n }\n\n forEach(f: (a: A) => void): void {\n f(this.value);\n }\n\n toArray(): A[] {\n return [this.value];\n }\n\n toEither<E>(_left: E): Either<E, A> {\n return Right(this.value) as any; // Forward reference to Either module\n }\n\n match<B>(patterns: { Some: (value: A) => B; None: () => B }): B {\n return patterns.Some(this.value);\n }\n\n toString(): string {\n return `Some(${this.value})`;\n }\n}\n\n/**\n * None represents an optional value that is not present\n */\nexport class NoneImpl implements Option<never> {\n get isSome(): boolean {\n return false;\n }\n\n get isNone(): boolean {\n return true;\n }\n\n get(): never {\n throw new Error(\"Cannot get value from None\");\n }\n\n getOrElse<B>(defaultValue: B): B {\n return defaultValue;\n }\n\n getOrCall<B>(f: () => B): B {\n return f();\n }\n\n getOrThrow(error: Error): never {\n throw error;\n }\n\n map<B>(_f: (a: never) => B): Option<B> {\n return this as unknown as Option<B>;\n }\n\n mapOr<B>(defaultValue: B, _f: (a: never) => B): Option<B> {\n return Some(defaultValue);\n }\n\n flatMap<B>(_f: (a: never) => Option<B>): Option<B> {\n return this as unknown as Option<B>;\n }\n\n orElse<B>(alternative: Option<B>): Option<B> {\n return alternative;\n }\n\n orCall<B>(f: () => Option<B>): Option<B> {\n return f();\n }\n\n filter(_predicate: (a: never) => boolean): Option<never> {\n return this;\n }\n\n forEach(_f: (a: never) => void): void {\n // Do nothing\n }\n\n toArray(): never[] {\n return [];\n }\n\n toEither<E>(left: E): Either<E, never> {\n return Left(left) as any; // Forward reference to Either module\n }\n\n match<B>(patterns: { Some: (value: never) => B; None: () => B }): B {\n return patterns.None();\n }\n\n toString(): string {\n return \"None\";\n }\n}\n\n// Singleton instance of None\nexport const None = new NoneImpl();\n\n// Constructor function for Some\nexport function Some<A>(value: A): Option<A> {\n if (value === null || value === undefined) {\n return None as Option<A>;\n }\n return new SomeImpl(value);\n}\n\n// Option namespace with utility functions\nexport namespace Option {\n /**\n * Creates an Option from a nullable value\n */\n export function fromNullable<A>(value: A | null | undefined): Option<A> {\n return value === null || value === undefined ? None : Some(value);\n }\n\n /**\n * Creates an Option from a function that might throw\n */\n export function tryCatch<A>(f: () => A): Option<A> {\n try {\n return Some(f());\n } catch (e) {\n return None;\n }\n }\n\n /**\n * Returns the first Some in the list, or None if all are None\n */\n export function firstSome<A>(...options: Option<A>[]): Option<A> {\n for (const option of options) {\n if (option.isSome) return option;\n }\n return None;\n }\n\n /**\n * Returns a Some containing an array of all values if all options are Some, None otherwise\n */\n export function sequence<A>(options: Option<A>[]): Option<A[]> {\n const values: A[] = [];\n for (const option of options) {\n if (option.isNone) return None;\n values.push(option.get());\n }\n return Some(values);\n }\n\n /**\n * Maps an array of values using a function that returns an Option, then sequences the result\n */\n export function traverse<A, B>(\n values: A[],\n f: (a: A) => Option<B>\n ): Option<B[]> {\n return sequence(values.map(f));\n }\n}\n\n// Forward references to Either types - removing unused type parameters\nexport interface Either<E, A> {\n isLeft: boolean;\n isRight: boolean;\n get(): A;\n getLeft(): E;\n // More definitions in Either.ts\n}\n\nexport function Left<E>(left: E): Either<E, never> {\n return {\n isLeft: true,\n isRight: false,\n get: () => { throw new Error(\"Cannot get value from Left\"); },\n getLeft: () => left\n } as any; // Simplified for forward reference\n}\n\nexport function Right<A>(right: A): Either<never, A> {\n return {\n isLeft: false,\n isRight: true,\n get: () => right,\n getLeft: () => { throw new Error(\"Cannot get left from Right\"); }\n } as any; // Simplified for forward reference\n} ","/**\n * Either<E, A> represents a value of one of two possible types: Left (E) or Right (A).\n * Left is conventionally used for errors, while Right is used for success.\n * \n * @example\n * ```ts\n * import { Either, Left, Right } from 'scats';\n * \n * // Creating eithers\n * const success = Right(42);\n * const failure = Left(new Error(\"Something went wrong\"));\n * \n * // Using eithers\n * const result = success\n * .map(n => n * 2)\n * .flatMap(n => n > 50 ? Right(n) : Left(\"Value too small\"))\n * .getOrElse(0);\n * ```\n */\n\nimport { Option, Some, None } from './Option';\n\n/**\n * Either<E, A> interface that all Either implementations must satisfy\n */\nexport interface Either<E, A> {\n /**\n * Returns true if this is a Left, false otherwise\n */\n readonly isLeft: boolean;\n\n /**\n * Returns true if this is a Right, false otherwise\n */\n readonly isRight: boolean;\n\n /**\n * Returns the value from this Right, or throws an error if this is a Left\n * @throws Error if this is a Left\n */\n get(): A;\n\n /**\n * Returns the left value if this is a Left, or throws an error if this is a Right\n * @throws Error if this is a Right\n */\n getLeft(): E;\n\n /**\n * Returns the value from this Right, or returns the provided default value if this is a Left\n */\n getOrElse<B>(defaultValue: B): A | B;\n\n /**\n * Returns the value from this Right, or returns the result of the provided function if this is a Left\n */\n getOrCall<B>(f: (e: E) => B): A | B;\n\n /**\n * Returns the value from this Right, or throws the provided error if this is a Left\n */\n getOrThrow(error: Error): A;\n\n /**\n * Maps the Right value if this is a Right, otherwise returns this Left unchanged\n */\n map<B>(f: (a: A) => B): Either<E, B>;\n\n /**\n * Maps the Left value if this is a Left, otherwise returns this Right unchanged\n */\n mapLeft<F>(f: (e: E) => F): Either<F, A>;\n\n /**\n * Returns the result of applying f if this is a Right, otherwise returns this Left unchanged\n */\n flatMap<B>(f: (a: A) => Either<E, B>): Either<E, B>;\n\n /**\n * Returns this Right if this is a Right, otherwise returns the provided alternative\n */\n orElse<F, B>(alternative: Either<F, B>): Either<E | F, A | B>;\n\n /**\n * Returns this Right if this is a Right, otherwise returns the result of the provided function\n */\n orCall<F, B>(f: (e: E) => Either<F, B>): Either<E | F, A | B>;\n\n /**\n * Executes one of the provided functions based on whether this is a Left or a Right\n */\n fold<B>(onLeft: (e: E) => B, onRight: (a: A) => B): B;\n\n /**\n * Executes the provided function if this is a Right\n */\n forEach(f: (a: A) => void): void;\n\n /**\n * Executes the provided function if this is a Left\n */\n forEachLeft(f: (e: E) => void): void;\n\n /**\n * Converts this Either to an Option, discarding the Left value if this is a Left\n */\n toOption(): Option<A>;\n\n /**\n * Swaps the Left and Right values of this Either\n */\n swap(): Either<A, E>;\n\n /**\n * Returns the result of applying the appropriate function\n */\n match<B>(patterns: { Left: (value: E) => B; Right: (value: A) => B }): B;\n}\n\n/**\n * Left<E, A> represents the Left case of an Either\n */\nexport class LeftImpl<E, A = never> implements Either<E, A> {\n constructor(private readonly value: E) {\n if (value === null || value === undefined) {\n throw new Error(\"Cannot create Left with null or undefined value\");\n }\n }\n\n get isLeft(): boolean {\n return true;\n }\n\n get isRight(): boolean {\n return false;\n }\n\n get(): A {\n throw new Error(\"Cannot get Right value from Left\");\n }\n\n getLeft(): E {\n return this.value;\n }\n\n getOrElse<B>(defaultValue: B): B {\n return defaultValue;\n }\n\n getOrCall<B>(f: (e: E) => B): B {\n return f(this.value);\n }\n\n getOrThrow(error: Error): A {\n throw error;\n }\n\n map<B>(_f: (a: A) => B): Either<E, B> {\n return this as unknown as Either<E, B>;\n }\n\n mapLeft<F>(f: (e: E) => F): Either<F, A> {\n return Left(f(this.value));\n }\n\n flatMap<B>(_f: (a: A) => Either<E, B>): Either<E, B> {\n return this as unknown as Either<E, B>;\n }\n\n orElse<F, B>(alternative: Either<F, B>): Either<F, B> {\n return alternative;\n }\n\n orCall<F, B>(f: (e: E) => Either<F, B>): Either<F, B> {\n return f(this.value);\n }\n\n fold<B>(onLeft: (e: E) => B, _onRight: (a: A) => B): B {\n return onLeft(this.value);\n }\n\n forEach(_f: (a: A) => void): void {\n // Do nothing\n }\n\n forEachLeft(f: (e: E) => void): void {\n f(this.value);\n }\n\n toOption(): Option<A> {\n return None;\n }\n\n swap(): Either<A, E> {\n return Right(this.value) as Either<A, E>;\n }\n\n match<B>(patterns: { Left: (value: E) => B; Right: (value: A) => B }): B {\n return patterns.Left(this.value);\n }\n\n toString(): string {\n return `Left(${this.value})`;\n }\n}\n\n/**\n * Right<E, A> represents the Right case of an Either\n */\nexport class RightImpl<E, A> implements Either<E, A> {\n constructor(private readonly value: A) {\n if (value === null || value === undefined) {\n throw new Error(\"Cannot create Right with null or undefined value\");\n }\n }\n\n get isLeft(): boolean {\n return false;\n }\n\n get isRight(): boolean {\n return true;\n }\n\n get(): A {\n return this.value;\n }\n\n getLeft(): E {\n throw new Error(\"Cannot get Left value from Right\");\n }\n\n getOrElse<B>(_defaultValue: B): A {\n return this.value;\n }\n\n getOrCall<B>(_f: (e: E) => B): A {\n return this.value;\n }\n\n getOrThrow(_error: Error): A {\n return this.value;\n }\n\n map<B>(f: (a: A) => B): Either<E, B> {\n return Right(f(this.value));\n }\n\n mapLeft<F>(_f: (e: E) => F): Either<F, A> {\n return this as unknown as Either<F, A>;\n }\n\n flatMap<B>(f: (a: A) => Either<E, B>): Either<E, B> {\n return f(this.value);\n }\n\n orElse<F, B>(_alternative: Either<F, B>): Either<E | F, A | B> {\n return this as unknown as Either<E | F, A | B>;\n }\n\n orCall<F, B>(_f: (e: E) => Either<F, B>): Either<E | F, A | B> {\n return this as unknown as Either<E | F, A | B>;\n }\n\n fold<B>(_onLeft: (e: E) => B, onRight: (a: A) => B): B {\n return onRight(this.value);\n }\n\n forEach(f: (a: A) => void): void {\n f(this.value);\n }\n\n forEachLeft(_f: (e: E) => void): void {\n // Do nothing\n }\n\n toOption(): Option<A> {\n return Some(this.value);\n }\n\n swap(): Either<A, E> {\n return Left(this.value) as unknown as Either<A, E>;\n }\n\n match<B>(patterns: { Left: (value: E) => B; Right: (value: A) => B }): B {\n return patterns.Right(this.value);\n }\n\n toString(): string {\n return `Right(${this.value})`;\n }\n}\n\n/**\n * Creates a Left instance\n */\nexport function Left<E, A = never>(left: E): Either<E, A> {\n if (left === null || left === undefined) {\n throw new Error(\"Cannot create Left with null or undefined value\");\n }\n return new LeftImpl(left);\n}\n\n/**\n * Creates a Right instance\n */\nexport function Right<A, E = never>(right: A): Either<E, A> {\n if (right === null || right === undefined) {\n throw new Error(\"Cannot create Right with null or undefined value\");\n }\n return new RightImpl<E, A>(right);\n}\n\n/**\n * Either namespace containing utility functions\n */\nexport namespace Either {\n /**\n * Creates an Either from a function that might throw, capturing the error in the Left\n */\n export function tryCatch<A>(f: () => A): Either<unknown, A> {\n try {\n return Right(f());\n } catch (e) {\n return Left(e);\n }\n }\n\n /**\n * Returns a Right containing an array of all values if all inputs are Right, otherwise returns the first Left\n */\n export function sequence<E, A>(eithers: Either<E, A>[]): Either<E, A[]> {\n const values: A[] = [];\n for (const either of eithers) {\n if (either.isLeft) return either as Either<E, A[]>;\n values.push(either.get());\n }\n return Right(values);\n }\n\n /**\n * Maps an array of values using a function that returns an Either, then sequences the result\n */\n export function traverse<E, A, B>(\n values: A[],\n f: (a: A) => Either<E, B>\n ): Either<E, B[]> {\n return sequence(values.map(f));\n }\n} ","/**\n * Try<A> represents a computation that may either result in a value of type A\n * or an exception. It's similar to Either<Error, A> but specifically for handling exceptions.\n * \n * @example\n * ```ts\n * import { Try, Success, Failure, TryAsync } from 'scats';\n * \n * // Creating instances\n * const a = Try.of(() => JSON.parse('{\"valid\": \"json\"}'));\n * const b = Try.of(() => JSON.parse('invalid json'));\n * \n * // Using Try\n * const result = a\n * .map(obj => obj.valid)\n * .flatMap(str => Try.of(() => str.toUpperCase()))\n * .getOrElse(\"default\");\n * \n * // Async version\n * const asyncResult = await TryAsync.of(async () => {\n * const response = await fetch('https://api.example.com');\n * return response.json();\n * }).map(data => data.value).toPromise();\n * ```\n */\n\nimport { Either, Left, Right } from './Either';\nimport { Option, Some, None } from './Option';\n\n/**\n * Try<A> interface that all Try implementations must satisfy\n */\nexport interface Try<A> {\n /**\n * Returns true if this is a Success, false otherwise\n */\n readonly isSuccess: boolean;\n\n /**\n * Returns true if this is a Failure, false otherwise\n */\n readonly isFailure: boolean;\n\n /**\n * Returns the value if this is a Success, or throws the error if this is a Failure\n * @throws Error if this is a Failure\n */\n get(): A;\n\n /**\n * Returns the value if this is a Success, or returns the provided default value if this is a Failure\n */\n getOrElse<B>(defaultValue: B): A | B;\n\n /**\n * Returns the error if this is a Failure, or throws if this is a Success\n * @throws Error if this is a Success\n */\n getError(): Error;\n\n /**\n * Returns a Try containing the exception if this is a Failure, or a Failure if this is a Success\n */\n failed(): Try<Error>;\n\n /**\n * Maps the value if this is a Success, otherwise returns this Failure unchanged\n */\n map<B>(f: (a: A) => B): Try<B>;\n\n /**\n * Returns the result of applying f if this is a Success, otherwise returns this Failure unchanged\n */\n flatMap<B>(f: (a: A) => Try<B>): Try<B>;\n\n /**\n * Recovers from a failure by returning the result of the provided function\n */\n recover<B>(f: (error: Error) => B): Try<A | B>;\n\n /**\n * Recovers from a failure by returning the result of the provided function\n */\n recoverWith<B>(f: (error: Error) => Try<B>): Try<A | B>;\n\n /**\n * Transforms this Try to another Try using the provided functions\n */\n transform<B>(s: (a: A) => Try<B>, f: (error: Error) => Try<B>): Try<B>;\n\n /**\n * Converts this Try to an Option, discarding the error if this is a Failure\n */\n toOption(): Option<A>;\n\n /**\n * Converts this Try to an Either with the error as Left and value as Right\n */\n toEither(): Either<Error, A>;\n\n /**\n * Executes one of the provided functions based on whether this is a Success or a Failure\n */\n fold<B>(onFailure: (error: Error) => B, onSuccess: (value: A) => B): B;\n\n /**\n * Returns the result of applying the appropriate function\n */\n match<B>(patterns: { Success: (value: A) => B; Failure: (error: Error) => B }): B;\n}\n\n/**\n * Success<A> represents a successful computation with a value\n */\nexport class SuccessImpl<A> implements Try<A> {\n constructor(private readonly value: A) { }\n\n get isSuccess(): boolean {\n return true;\n }\n\n get isFailure(): boolean {\n return false;\n }\n\n get(): A {\n return this.value;\n }\n\n getOrElse<B>(_defaultValue: B): A {\n return this.value;\n }\n\n getError(): Error {\n throw new Error(\"Cannot get error from Success\");\n }\n\n failed(): Try<Error> {\n return new FailureImpl(new Error(\"Success has no failure\"));\n }\n\n map<B>(f: (a: A) => B): Try<B> {\n try {\n return new SuccessImpl(f(this.value));\n } catch (e) {\n return new FailureImpl(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n flatMap<B>(f: (a: A) => Try<B>): Try<B> {\n try {\n return f(this.value);\n } catch (e) {\n return new FailureImpl(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n recover<B>(_f: (error: Error) => B): Try<A> {\n return this;\n }\n\n recoverWith<B>(_f: (error: Error) => Try<B>): Try<A> {\n return this;\n }\n\n transform<B>(s: (a: A) => Try<B>, _f: (error: Error) => Try<B>): Try<B> {\n try {\n return s(this.value);\n } catch (e) {\n return new FailureImpl(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n toOption(): Option<A> {\n return Some(this.value);\n }\n\n toEither(): Either<Error, A> {\n return Right(this.value);\n }\n\n fold<B>(_onFailure: (error: Error) => B, onSuccess: (value: A) => B): B {\n return onSuccess(this.value);\n }\n\n match<B>(patterns: { Success: (value: A) => B; Failure: (error: Error) => B }): B {\n return patterns.Success(this.value);\n }\n\n toString(): string {\n return `Success(${this.value})`;\n }\n}\n\n/**\n * Failure<A> represents a failed computation with an error\n */\nexport class FailureImpl<A> implements Try<A> {\n constructor(private readonly error: Error) { }\n\n get isSuccess(): boolean {\n return false;\n }\n\n get isFailure(): boolean {\n return true;\n }\n\n get(): A {\n throw this.error;\n }\n\n getOrElse<B>(defaultValue: B): B {\n return defaultValue;\n }\n\n getError(): Error {\n return this.error;\n }\n\n failed(): Try<Error> {\n return new SuccessImpl(this.error);\n }\n\n map<B>(_f: (a: A) => B): Try<B> {\n return this as unknown as Try<B>;\n }\n\n flatMap<B>(_f: (a: A) => Try<B>): Try<B> {\n return this as unknown as Try<B>;\n }\n\n recover<B>(f: (error: Error) => B): Try<B> {\n try {\n return new SuccessImpl(f(this.error));\n } catch (e) {\n return new FailureImpl(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n recoverWith<B>(f: (error: Error) => Try<B>): Try<B> {\n try {\n return f(this.error);\n } catch (e) {\n return new FailureImpl(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n transform<B>(_s: (a: A) => Try<B>, f: (error: Error) => Try<B>): Try<B> {\n try {\n return f(this.error);\n } catch (e) {\n return new FailureImpl(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n toOption(): Option<A> {\n return None;\n }\n\n toEither(): Either<Error, A> {\n return Left(this.error);\n }\n\n fold<B>(onFailure: (error: Error) => B, _onSuccess: (value: A) => B): B {\n return onFailure(this.error);\n }\n\n match<B>(patterns: { Success: (value: A) => B; Failure: (error: Error) => B }): B {\n return patterns.Failure(this.error);\n }\n\n toString(): string {\n return `Failure(${this.error})`;\n }\n}\n\n/**\n * Creates a Success instance\n */\nexport function Success<A>(value: A): Try<A> {\n return new SuccessImpl(value);\n}\n\n/**\n * Creates a Failure instance\n */\nexport function Failure<A>(error: Error): Try<A> {\n return new FailureImpl(error);\n}\n\n/**\n * Try namespace containing utility functions\n */\nexport namespace Try {\n /**\n * Creates a Try from a function that might throw\n */\n export function of<A>(f: () => A): Try<A> {\n try {\n return Success(f());\n } catch (e) {\n return Failure(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n /**\n * Returns a Success containing an array of all values if all tries are Success, otherwise returns the first Failure\n */\n export function sequence<A>(tries: Try<A>[]): Try<A[]> {\n const values: A[] = [];\n for (const t of tries) {\n if (t.isFailure) return t as Try<A[]>;\n values.push(t.get());\n }\n return Success(values);\n }\n\n /**\n * Maps an array of values using a function that returns a Try, then sequences the result\n */\n export function traverse<A, B>(\n values: A[],\n f: (a: A) => Try<B>\n ): Try<B[]> {\n return sequence(values.map(f));\n }\n}\n\n/**\n * TryAsync<A> represents an asynchronous computation that may either result in a value of type A\n * or an exception. It's the asynchronous counterpart to Try<A>.\n */\nexport interface TryAsync<A> {\n /**\n * Maps the value if this is a Success, otherwise returns this Failure unchanged\n */\n map<B>(f: (a: A) => B | Promise<B>): TryAsync<B>;\n\n /**\n * Returns the result of applying f if this is a Success, otherwise returns this Failure unchanged\n */\n flatMap<B>(f: (a: A) => TryAsync<B> | Promise<TryAsync<B>>): TryAsync<B>;\n\n /**\n * Recovers from a failure by returning the result of the provided function\n */\n recover<B>(f: (error: Error) => B | Promise<B>): TryAsync<A | B>;\n\n /**\n * Recovers from a failure by returning the result of the provided function\n */\n recoverWith<B>(f: (error: Error) => TryAsync<B> | Promise<TryAsync<B>>): TryAsync<A | B>;\n\n /**\n * Converts this async Try to a Promise\n */\n toPromise(): Promise<A>;\n}\n\nclass TryAsyncImpl<A> implements TryAsync<A> {\n constructor(private readonly promise: Promise<Try<A>>) { }\n\n map<B>(f: (a: A) => B | Promise<B>): TryAsync<B> {\n return new TryAsyncImpl<B>(\n this.promise.then(async (result) => {\n if (result.isFailure) return result as unknown as Try<B>;\n try {\n const value = await f(result.get());\n return Success(value);\n } catch (e) {\n return Failure(e instanceof Error ? e : new Error(String(e)));\n }\n })\n );\n }\n\n flatMap<B>(f: (a: A) => TryAsync<B> | Promise<TryAsync<B>>): TryAsync<B> {\n return new TryAsyncImpl<B>(\n this.promise.then(async (result) => {\n if (result.isFailure) return result as unknown as Try<B>;\n try {\n const tryAsync = await f(result.get());\n return await tryAsync.toPromise().then(Success).catch(e =>\n Failure(e instanceof Error ? e : new Error(String(e)))\n );\n } catch (e) {\n return Failure(e instanceof Error ? e : new Error(String(e)));\n }\n })\n );\n }\n\n recover<B>(f: (error: Error) => B | Promise<B>): TryAsync<A | B> {\n return new TryAsyncImpl<A | B>(\n this.promise.then(async (result) => {\n if (result.isSuccess) return result as Try<A | B>;\n try {\n const value = await f(result.getError());\n return Success<A | B>(value);\n } catch (e) {\n return Failure<A | B>(e instanceof Error ? e : new Error(String(e)));\n }\n })\n );\n }\n\n recoverWith<B>(f: (error: Error) => TryAsync<B> | Promise<TryAsync<B>>): TryAsync<A | B> {\n return new TryAsyncImpl<A | B>(\n this.promise.then(async (result) => {\n if (result.isSuccess) return result as Try<A | B>;\n try {\n const tryAsync = await f(result.getError());\n return await tryAsync.toPromise().then(value =>\n Success<A | B>(value)\n ).catch(e =>\n Failure<A | B>(e instanceof Error ? e : new Error(String(e)))\n );\n } catch (e) {\n return Failure<A | B>(e instanceof Error ? e : new Error(String(e)));\n }\n })\n );\n }\n\n async toPromise(): Promise<A> {\n const result = await this.promise;\n if (result.isSuccess) {\n return result.get();\n } else {\n throw result.getError();\n }\n }\n}\n\n/**\n * TryAsync namespace containing utility functions\n */\nexport namespace TryAsync {\n /**\n * Creates a TryAsync from a function that returns a Promise\n */\n export function of<A>(f: () => Promise<A>): TryAsync<A> {\n return new TryAsyncImpl(\n Promise.resolve().then(async () => {\n try {\n const value = await f();\n return Success(value);\n } catch (e) {\n return Failure(e instanceof Error ? e : new Error(String(e)));\n }\n })\n );\n }\n\n /**\n * Creates a successful TryAsync\n */\n export function success<A>(value: A): TryAsync<A> {\n return new TryAsyncImpl(Promise.resolve(Success(value)));\n }\n\n /**\n * Creates a failed TryAsync\n */\n export function failure<A>(error: Error): TryAsync<A> {\n return new TryAsyncImpl(Promise.resolve(Failure(error)));\n }\n\n /**\n * Converts a Promise to a TryAsync\n */\n export function fromPromise<A>(promise: Promise<A>): TryAsync<A> {\n return of(() => promise);\n }\n} ","/**\n * The execution context is the environment where a computation runs.\n */\nexport interface ExecutionContext {\n /**\n * Executes a task in this execution context.\n */\n execute(task: () => void): void;\n\n /**\n * Reports an exception that occurred during execution.\n */\n reportFailure(cause: Error): void;\n}\n\n/**\n * A default global execution context backed by the JavaScript event loop.\n */\nclass GlobalExecutionContext implements ExecutionContext {\n /**\n * Executes a task asynchronously.\n */\n execute(task: () => void): void {\n setTimeout(task, 0);\n }\n\n /**\n * Reports a failure to the console.\n */\n reportFailure(cause: Error): void {\n console.error(\"Execution context failure:\", cause);\n }\n}\n\n/**\n * An execution context that executes tasks synchronously in the current thread.\n * This is mainly for testing and should be avoided in production.\n */\nclass SynchronousExecutionContext implements ExecutionContext {\n /**\n * Executes a task immediately in the current thread.\n */\n execute(task: () => void): void {\n task();\n }\n\n /**\n * Reports a failure to the console.\n */\n reportFailure(cause: Error): void {\n console.error(\"Execution context failure:\", cause);\n }\n}\n\n/**\n * Execution context utility methods.\n */\nexport const ExecutionContext = {\n /**\n * The global execution context.\n */\n global: new GlobalExecutionContext(),\n\n /**\n * A synchronous execution context for testing.\n */\n synchronous: new SynchronousExecutionContext(),\n\n /**\n * Creates an execution context from a function that executes tasks.\n */\n fromExecutor(executor: (task: () => void) => void, reporter: (cause: Error) => void = console.error): ExecutionContext {\n return {\n execute: executor,\n reportFailure: reporter\n };\n }\n}; ","/**\n * List<A> represents an immutable linked list structure.\n * It's a singly-linked list that supports efficient prepend operations.\n * \n * @example\n * ```ts\n * import { List } from 'scats';\n * \n * // Creating lists\n * const a = List.of(1, 2, 3);\n * const b = List.empty<number>();\n * const c = a.prepend(0);\n * \n * // Using lists\n * const doubled = a.map(n => n * 2);\n * const summed = a.foldLeft(0, (acc, n) => acc + n);\n * const filtered = a.filter(n => n % 2 === 0);\n * ```\n */\n\nimport { Option, Some, None } from './Option';\n\n/**\n * List<A> interface that all List implementations must satisfy\n */\nexport interface List<A> extends Iterable<A> {\n /**\n * Returns true if this list is empty, false otherwise\n */\n readonly isEmpty: boolean;\n\n /**\n * Returns the number of elements in this list\n */\n readonly size: number;\n\n /**\n * Returns the first element of this list, or throws an error if the list is empty\n * @throws Error if the list is empty\n */\n head(): A;\n\n /**\n * Returns the rest of this list (all elements except the head), or throws an error if the list is empty\n * @throws Error if the list is empty\n */\n tail(): List<A>;\n\n /**\n * Returns the first element of this list as an Option, or None if the list is empty\n */\n headOption(): Option<A>;\n\n /**\n * Returns the rest of this list as an Option, or None if the list is empty\n */\n tailOption(): Option<List<A>>;\n\n /**\n * Returns a new list with the provided element prepended to this list\n */\n prepend(element: A): List<A>;\n\n /**\n * Returns a new list with the provided elements appended to this list\n */\n append(element: A): List<A>;\n\n /**\n * Returns a new list that is the result of concatenating this list with the provided list\n */\n concat(that: List<A>): List<A>;\n\n /**\n * Returns a new list that is the result of applying the provided function to each element\n */\n map<B>(f: (a: A) => B): List<B>;\n\n /**\n * Returns a new list that is the result of applying the provided function to each element\n * and flattening the results\n */\n flatMap<B>(f: (a: A) => List<B>): List<B>;\n\n /**\n * Returns a new list containing only the elements that satisfy the provided predicate\n */\n filter(predicate: (a: A) => boolean): List<A>;\n\n /**\n * Returns a tuple of two lists, where the first list contains all elements that satisfy\n * the provided predicate, and the second list contains all elements that don't satisfy the predicate\n */\n partition(predicate: (a: A) => boolean): [List<A>, List<A>];\n\n /**\n * Returns true if any element in this list satisfies the provided predicate, false otherwise\n */\n exists(predicate: (a: A) => boolean): boolean;\n\n /**\n * Returns true if all elements in this list satisfy the provided predicate, false otherwise\n */\n forAll(predicate: (a: A) => boolean): boolean;\n\n /**\n * Returns the result of applying the provided function to each element, starting with the provided initial value\n */\n foldLeft<B>(initial: B, f: (acc: B, a: A) => B): B;\n\n /**\n * Returns the result of applying the provided function to each element, starting with the provided initial value,\n * working from right to left\n */\n foldRight<B>(initial: B, f: (a: A, acc: B) => B): B;\n\n /**\n * Executes the provided function for each element in this list\n */\n forEach(f: (a: A) => void): void;\n\n /**\n * Returns a new list containing the elements at the specified indices\n */\n slice(start: number, end?: number): List<A>;\n\n /**\n * Returns a new list with the first n elements\n */\n take(n: number): List<A>;\n\n /**\n * Returns a new list with all elements except the first n\n */\n drop(n: number): List<A>;\n\n /**\n * Returns a new list with elements while the predicate is satisfied\n */\n takeWhile(predicate: (a: A) => boolean): List<A>;\n\n /**\n * Returns a new list without elements while the predicate is satisfied\n */\n dropWhile(predicate: (a: A) => boolean): List<A>;\n\n /**\n * Returns the element at the specified index, or throws an error if the index is out of bounds\n * @throws Error if the index is out of bounds\n */\n get(index: number): A;\n\n /**\n * Returns the element at the specified index as an Option, or None if the index is out of bounds\n */\n getOption(index: number): Option<A>;\n\n /**\n * Returns a new list with the element at the specified index replaced with the provided element,\n * or the same list if the index is out of bounds\n */\n updateAt(index: number, element: A): List<A>;\n\n /**\n * Returns the index of the first occurrence of the specified element, or -1 if the element is not found\n */\n indexOf(element: A): number;\n\n /**\n * Returns true if this list contains the specified element, false otherwise\n */\n contains(element: A): boolean;\n\n /**\n * Returns a new list with distinct elements (removes duplicates)\n */\n distinct(): List<A>;\n\n /**\n * Returns a new list with the elements in reverse order\n */\n reverse(): List<A>;\n\n /**\n * Returns a new list sorted according to the natural ordering of the elements\n */\n sorted(compareFn?: (a: A, b: A) => number): List<A>;\n\n /**\n * Converts this list to an array\n */\n toArray(): A[];\n\n /**\n * Returns a string representation of this list\n */\n toString(): string;\n}\n\n/**\n * Empty list implementation\n */\nclass EmptyList<A> implements List<A> {\n get isEmpty(): boolean {\n return true;\n }\n\n get size(): number {\n return 0;\n }\n\n head(): never {\n throw new Error(\"Cannot get head of empty list\");\n }\n\n tail(): never {\n throw new Error(\"Cannot get tail of empty list\");\n }\n\n headOption(): Option<A> {\n return None;\n }\n\n tailOption(): Option<List<A>> {\n return None;\n }\n\n prepend(element: A): List<A> {\n return new ConsImpl(element, this);\n }\n\n append(element: A): List<A> {\n return new ConsImpl(element, this);\n }\n\n concat(that: List<A>): List<A> {\n return that;\n }\n\n map<B>(_f: (a: A) => B): List<B> {\n return empty<B>();\n }\n\n flatMap<B>(_f: (a: A) => List<B>): List<B> {\n return empty<B>();\n }\n\n filter(_predicate: (a: A) => boolean): List<A> {\n return this;\n }\n\n partition(_predicate: (a: A) => boolean): [List<A>, List<A>] {\n return [this, this];\n }\n\n exists(_predicate: (a: A) => boolean): boolean {\n return false;\n }\n\n forAll(_predicate: (a: A) => boolean): boolean {\n return true;\n }\n\n foldLeft<B>(initial: B, _f: (acc: B, a: A) => B): B {\n return initial;\n }\n\n foldRight<B>(initial: B, _f: (a: A, acc: B) => B): B {\n return initial;\n }\n\n forEach(_f: (a: A) => void): void {\n // Do nothing for empty list\n }\n\n slice(_start: number, _end?: number): List<A> {\n return this;\n }\n\n take(_n: number): List<A> {\n return this;\n }\n\n drop(_n: number): List<A> {\n return this;\n }\n\n takeWhile(_predicate: (a: A) => boolean): List<A> {\n return this;\n }\n\n dropWhile(_predicate: (a: A) => boolean): List<A> {\n return this;\n }\n\n get(_index: number): never {\n throw new Error(\"Index out of bounds\");\n }\n\n getOption(_index: number): Option<A> {\n return None;\n }\n\n updateAt(_index: number, _element: A): List<A> {\n return this;\n }\n\n indexOf(_element: A): number {\n return -1;\n }\n\n contains(_element: A): boolean {\n return false;\n }\n\n distinct(): List<A> {\n return this;\n }\n\n reverse(): List<A> {\n return this;\n }\n\n sorted(_compareFn?: (a: A, b: A) => number): List<A> {\n return this;\n }\n\n toArray(): A[] {\n return [];\n }\n\n toString(): string {\n return \"List()\";\n }\n\n *[Symbol.iterator](): Iterator<A> {\n // Empty iterator\n }\n}\n\n/**\n * Non-empty list implementation\n */\nclass ConsImpl<A> implements List<A> {\n constructor(private readonly _head: A, private readonly _tail: List<A>) { }\n\n get isEmpty(): boolean {\n return false;\n }\n\n get size(): number {\n let size = 1;\n let current: List<A> = this._tail;\n while (!current.isEmpty) {\n size += 1;\n current = current.tail();\n }\n return size;\n }\n\n head(): A {\n return this._head;\n }\n\n tail(): List<A> {\n return this._tail;\n }\n\n headOption(): Option<A> {\n return Some(this._head);\n }\n\n tailOption(): Option<List<A>> {\n return Some(this._tail);\n }\n\n prepend(element: A): List<A> {\n return new ConsImpl(element, this);\n }\n\n append(element: A): List<A> {\n // Inefficient for large lists, but we're keeping the API\n return this.concat(List.of(element));\n }\n\n concat(that: List<A>): List<A> {\n // Using a more efficient implementation than naively recursing\n if (that.isEmpty) return this;\n\n // Build up a reversed version of this list\n let reversed = empty<A>();\n let current: List<A> = this;\n while (!current.isEmpty) {\n reversed = reversed.prepend(current.head());\n current = current.tail();\n }\n\n // Build the result by prepending the reversed elements onto 'that'\n let result = that;\n current = reversed;\n while (!current.isEmpty) {\n result = result.prepend(current.head());\n current = current.tail();\n }\n\n return result;\n }\n\n map<B>(f: (a: A) => B): List<B> {\n // Avoid stack overflow by iterative implementation\n const result: B[] = [];\n let current: List<A> = this;\n\n while (!current.isEmpty) {\n result.push(f(current.head()));\n current = current.tail();\n }\n\n // Build the list in reverse\n let listResult = empty<B>();\n for (let i = result.length - 1; i >= 0; i--) {\n listResult = listResult.prepend(result[i]);\n }\n\n return listResult;\n }\n\n flatMap<B>(f: (a: A) => List<B>): List<B> {\n // Iterative to avoid stack overflow\n let result = empty<B>();\n const elements: List<B>[] = [];\n let current: List<A> = this;\n\n // Collect all mapped lists\n while (!current.isEmpty) {\n elements.push(f(current.head()));\n current = current.tail();\n }\n\n // Concatenate in reverse order\n for (let i = elements.length - 1; i >= 0; i--) {\n result = elements[i].concat(result);\n }\n\n return result;\n }\n\n filter(predicate: (a: A) => boolean): List<A> {\n // Iterative to avoid stack overflow\n const result: A[] = [];\n let current: List<A> = this;\n\n while (!current.isEmpty) {\n const head = current.head();\n if (predicate(head)) {\n result.push(head);\n }\n current = current.tail();\n }\n\n // Build the list in reverse\n let listResult = empty<A>();\n for (let i = result.length - 1; i >= 0; i--) {\n listResult = listResult.prepend(result[i]);\n }\n\n return listResult;\n }\n\n partition(predicate: (a: A) => boolean): [List<A>, List<A>] {\n // Iterative to avoid stack overflow\n const trueResults: A[] = [];\n const falseResults: A[] = [];\n let current: List<A> = this;\n\n while (!current.isEmpty) {\n const head = current.head();\n if (predicate(head)) {\n trueResults.push(head);\n } else {\n falseResults.push(head);\n }\n current = current.tail();\n }\n\n // Build the lists in reverse\n let trueList = empty<A>();\n for (let i = trueResults.length - 1; i >= 0; i--) {\n trueList = trueList.prepend(trueResults[i]);\n }\n\n let falseList = empty<A>();\n for (let i = falseResults.length - 1; i >= 0; i--) {\n falseList = falseList.prepend(falseResults[i]);\n }\n\n return [trueList, falseList];\n }\n\n exists(predicate: (a: A) => boolean): boolean {\n let current: List<A> = this;\n while (!current.isEmpty) {\n if (predicate(current.head())) {\n return true;\n }\n current = current.tail();\n }\n return false;\n }\n\n forAll(predicate: (a: A) => boolean): boolean {\n let current: List<A> = this;\n while (!current.isEmpty) {\n if (!predicate(current.head())) {\n return false;\n }\n current = current.tail();\n }\n return true;\n }\n\n foldLeft<B>(initial: B, f: (acc: B, a: A) => B): B {\n let result = initial;\n let current: List<A> = this;\n while (!current.isEmpty) {\n result = f(result, current.head());\n current = current.tail();\n }\n return result;\n }\n\n foldRight<B>(initial: B, f: (a: A, acc: B) => B): B {\n // To avoid stack overflow, we reverse the list and then do foldLeft\n const reversed = this.reverse();\n return reversed.foldLeft(initial, (acc, a) => f(a, acc));\n }\n\n forEach(f: (a: A) => void): void {\n let current: List<A> = this;\n while (!current.isEmpty) {\n f(current.head());\n current = current.tail();\n }\n }\n\n slice(start: number, end?: number): List<A> {\n const endIndex = end === undefined ? this.size : end;\n return this.take(endIndex).drop(start);\n }\n\n take(n: number): List<A> {\n if (n <= 0) return empty<A>();\n\n const result: A[] = [];\n let current: List<A> = this;\n let count = 0;\n\n while (!current.isEmpty && count < n) {\n result.push(current.head());\n current = current.tail();\n count += 1;\n }\n\n // Build the list in reverse\n let listResult = empty<A>();\n for (let i = result.length - 1; i >= 0; i--) {\n listResult = listResult.prepend(result[i]);\n }\n\n return listResult;\n }\n\n drop(n: number): List<A> {\n if (n <= 0) return this;\n\n let current: List<A> = this;\n let count = 0;\n\n while (!current.isEmpty && count < n) {\n current = current.tail();\n count += 1;\n }\n\n return current;\n }\n\n takeWhile(predicate: (a: A) => boolean): List<A> {\n const result: A[] = [];\n let current: List<A> = this;\n\n while (!current.isEmpty) {\n const head = current.head();\n if (!predicate(head)) break;\n result.push(head);\n current = current.tail();\n }\n\n // Build the list in reverse\n let listResult = empty<A>();\n for (let i = result.length - 1; i >= 0; i--) {\n listResult = listResult.prepend(result[i]);\n }\n\n return listResult;\n }\n\n dropWhile(predicate: (a: A) => boolean): List<A> {\n let current: List<A> = this;\n\n while (!current.isEmpty) {\n if (!predicate(current.head())) {\n return current;\n }\n current = current.tail();\n }\n\n return empty<A>();\n }\n\n get(index: number): A {\n if (index < 0) {\n throw new Error(\"Index out of bounds\");\n }\n\n let current: List<A> = this;\n let currentIndex = 0;\n\n while (!current.isEmpty) {\n if (currentIndex === index) {\n return current.head();\n }\n current = current.tail();\n currentIndex += 1;\n }\n\n throw new Error(\"Index out of bounds\");\n }\n\n getOption(index: number): Option<A> {\n if (index < 0) {\n return None;\n }\n\n let current: List<A> = this;\n let currentIndex = 0;\n\n while (!current.isEmpty) {\n if (currentIndex === index) {\n return Some(current.head());\n }\n current = current.tail();\n currentIndex += 1;\n }\n\n return None;\n }\n\n updateAt(index: number, element: A): List<A> {\n if (index < 0) {\n return this;\n }\n\n const result: A[] = [];\n let current: List<A> = this;\n let currentIndex = 0;\n let found = false;\n\n while (!current.isEmpty) {\n if (currentIndex === index) {\n result.push(element);\n found = true;\n } else {\n result.push(current.head());\n }\n current = current.tail();\n currentIndex += 1;\n }\n\n if (!found) {\n return this;\n }\n\n // Build the list in reverse\n let listResult = empty<A>();\n for (let i = result.length - 1; i >= 0; i--) {\n listResult = listResult.prepend(result[i]);\n }\n\n return listResult;\n }\n\n indexOf(element: A): number {\n let current: List<A> = this;\n let currentIndex = 0;\n\n while (!current.isEmpty) {\n if (current.head() === element) {\n return currentIndex;\n }\n current = curren