134 lines
2.3 KiB
JavaScript
134 lines
2.3 KiB
JavaScript
import { concat } from '../iter.js'
|
|
import { liftF } from './fn.js'
|
|
import { Pure, Suspend } from './free.js'
|
|
import { AlgebraWithBase, Category, Comonad, Foldable, Monoid } from './index.js'
|
|
|
|
/** @import { InferredMorphism } from './types.js' */
|
|
|
|
const Nil = Symbol('Nil')
|
|
|
|
/**
|
|
* @template T
|
|
* @extends {Pure<T>}
|
|
*/
|
|
class ListPure extends AlgebraWithBase(Pure)(Category, Foldable, Monoid) {
|
|
static empty() {
|
|
return List.empty()
|
|
}
|
|
|
|
static id() {
|
|
return List.empty()
|
|
}
|
|
|
|
head() {
|
|
return this._value
|
|
}
|
|
|
|
tail() {
|
|
return Empty
|
|
}
|
|
|
|
/**
|
|
* @template U
|
|
* @param {(acc: U, value: T) => U} f
|
|
* @param {U} init
|
|
* @returns {U}
|
|
*/
|
|
reduce(f, init) {
|
|
return f(init, this._value)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @template T
|
|
* @extends {Suspend<T>}
|
|
*/
|
|
class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Monoid, Comonad) {
|
|
/**
|
|
* @param {Iterator<T>} iter
|
|
*/
|
|
constructor(iter) {
|
|
const next = iter.next()
|
|
const value = /** @type {T} */ (next.value)
|
|
|
|
const fn = /** @type {InferredMorphism<T>} */ (next.done ? List.empty : () => new ListSuspend(iter))
|
|
super(value, fn)
|
|
}
|
|
|
|
/**
|
|
* @template {Iterable<T>} T
|
|
* @this {ListSuspend<Iterator<T>>}
|
|
* @param {Iterator<T>} value
|
|
* @returns {ListSuspend<T>}
|
|
*/
|
|
cons(value) {
|
|
return new ListSuspend(concat(value, this._value))
|
|
}
|
|
|
|
head() {
|
|
return this._value
|
|
}
|
|
|
|
tail() {
|
|
return this.step()
|
|
}
|
|
|
|
/**
|
|
* @template U
|
|
* @param {(acc: U, value: T) => U} f
|
|
* @param {U} init
|
|
* @returns {U}
|
|
*/
|
|
reduce(f, init) {
|
|
const acc = f(init, this._value)
|
|
return this.tail().reduce(f, acc)
|
|
}
|
|
|
|
extract() {
|
|
return this.reduce(reduceArray, [])
|
|
}
|
|
|
|
static empty() {
|
|
return List.empty()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @template T
|
|
* @type {ListPure<T> | ListSuspend<T>} List
|
|
*/
|
|
export class List {
|
|
/**
|
|
* @template {Iterable<T>} T
|
|
* @param {T} value
|
|
* @returns {ListSuspend<T>}
|
|
*/
|
|
static of(value) {
|
|
// @ts-ignore
|
|
return new ListSuspend(liftF(value))
|
|
}
|
|
|
|
/**
|
|
* @template T
|
|
* @param {Iterable<T>} iterator
|
|
* @returns {ListSuspend<T>}
|
|
*/
|
|
static from(iterator) {
|
|
return new ListSuspend(Iterator.from(iterator))
|
|
}
|
|
|
|
static empty() {
|
|
return Empty
|
|
}
|
|
}
|
|
|
|
const Empty = new ListPure(Nil)
|
|
|
|
/**
|
|
* @template T
|
|
* @param {T[]} acc
|
|
* @param {T} value
|
|
* @returns {T[]}
|
|
*/
|
|
const reduceArray = (acc, value) => acc.concat(value)
|
|
|