/**
* Represents an empty list
*/
export type Nil = {readonly _tag: 'Nil'}
/**
* Represents a non-empty list node
* @typeParam A - The type of elements in the list
*/
export type Cons = {
readonly _tag: 'Cons',
readonly head: A,
readonly tail: List,
}
/**
* A recursive list type that is either Nil (empty) or Cons (non-empty)
* @typeParam A - The type of elements in the list
*/
export type List = Nil | Cons
/**
* The singleton instance of an empty list
*/
export const nil: Nil = {_tag: 'Nil'}
/**
* Constructs a new list node
* @typeParam A - The type of elements in the list
* @param head - The first element of the list
* @param tail - The rest of the list
* @returns A new Cons node
*/
export const cons = (head: A, tail: List): List => ({
_tag: 'Cons',
head,
tail,
})
/**
* Maps a function over all elements of a list
* @typeParam A - The input element type
* @typeParam B - The output element type
* @param f - The mapping function
* @returns A function that takes a list and returns a new list
*/
type ListMap = (f: (a: A) => B) => (fa: List) => List
export const listMap: ListMap = (f) => (fa) =>
fa._tag === 'Cons' ? cons(f(fa.head), listMap(f)(fa.tail)) : nil
/**
* Reduces a list to a single value
* @typeParam A - The element type
* @typeParam B - The accumulator type
* @param f - The reducer function
* @param initial - The initial accumulator value
* @returns A function that takes a list and returns the reduced value
*/
type ListReduce = (f: (b: B, a: A) => B, initial: B) => (fa: List) => B
export const listReduce: ListReduce =
(f: (b: B, a: A) => B, initial: B) => (fa: List) => {
const reduceHelper = (list: List, acc: B): B => {
return list._tag === 'Cons'
? reduceHelper(list.tail, f(acc, list.head))
: acc
}
return reduceHelper(fa, initial)
}
/**
* Creates a list from an array
* @typeParam A - The element type
* @param arr - The source array
* @returns A list containing the same elements
*/
type FromArray = (arr: Array) => List
export const fromArray: FromArray = (arr: Array) =>
arr.reduceRight(
(acc: List, val: A) => cons(val, acc),
nil as List,
)
/**
* Converts a list to an array
* @typeParam A - The element type
* @param fa - The list to convert
* @returns An array containing the same elements
*/
type ToArray = (fa: List) => Array
export const toArray: ToArray = (fa: List) =>
listReduce>(
(acc, val) => [...acc, val],
[] as Array,
)(fa)