fp-lib/src/list.ts
2025-06-07 20:52:15 -05:00

95 lines
2.5 KiB
TypeScript

/**
* 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<A> = {
readonly _tag: 'Cons',
readonly head: A,
readonly tail: List<A>,
}
/**
* 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<A> = Nil | Cons<A>
/**
* 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 = <A>(head: A, tail: List<A>): List<A> => ({
_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 = <A, B>(f: (a: A) => B) => (fa: List<A>) => List<B>
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 = <A, B>(f: (b: B, a: A) => B, initial: B) => (fa: List<A>) => B
export const listReduce: ListReduce =
<A, B>(f: (b: B, a: A) => B, initial: B) => (fa: List<A>) => {
const reduceHelper = (list: List<A>, 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 = <A>(arr: Array<A>) => List<A>
export const fromArray: FromArray = <A>(arr: Array<A>) =>
arr.reduceRight(
(acc: List<A>, val: A) => cons(val, acc),
nil as List<A>,
)
/**
* 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 = <A>(fa: List<A>) => Array<A>
export const toArray: ToArray = <A>(fa: List<A>) =>
listReduce<A, Array<A>>(
(acc, val) => [...acc, val],
[] as Array<A>,
)(fa)