List.count

This commit is contained in:
Rowan 2025-04-07 02:30:49 -05:00
parent b2d5ece8f0
commit 50f3cff3d9
2 changed files with 64 additions and 22 deletions

View file

@ -42,3 +42,10 @@ export const liftF = x => suspend(
/** @type {InferredMorphism<T>} */(pure) /** @type {InferredMorphism<T>} */(pure)
) )
/**
* @param {number} a
* @param {number} b
* @returns {number}
*/
export const sum = (a, b) => a + b

View file

@ -1,5 +1,3 @@
import { concat } from '../iter.js'
import { liftF } from './fn.js'
import { Pure, Suspend } from './free.js' import { Pure, Suspend } from './free.js'
import { AlgebraWithBase, Category, Comonad, Foldable, Monoid } from './index.js' import { AlgebraWithBase, Category, Comonad, Foldable, Monoid } from './index.js'
@ -37,6 +35,18 @@ class ListPure extends AlgebraWithBase(Pure)(Category, Foldable, Monoid) {
reduce(f, init) { reduce(f, init) {
return f(init, this._value) return f(init, this._value)
} }
count() {
return this.isEmpty() ? 0 : 1
}
/**
* @this {List<any>}
* @returns {this is Empty}
*/
isEmpty() {
return this === Empty
}
} }
/** /**
@ -45,24 +55,29 @@ class ListPure extends AlgebraWithBase(Pure)(Category, Foldable, Monoid) {
*/ */
class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Monoid, Comonad) { class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Monoid, Comonad) {
/** /**
* @param {Iterator<T>} iter * @param {T} head
* @param {() => List<T>} tail
*/ */
constructor(iter) { constructor(head, tail) {
const next = iter.next() super(
const value = /** @type {T} */ (next.value) head,
/** @type {InferredMorphism<T>} */(tail)
)
}
const fn = /** @type {InferredMorphism<T>} */ (next.done ? List.empty : () => new ListSuspend(iter))
super(value, fn) static empty() {
return List.empty()
} }
/** /**
* @template {Iterable<T>} T * @template T
* @this {ListSuspend<Iterator<T>>} * @this {ListSuspend<T>}
* @param {Iterator<T>} value * @param {T} value
* @returns {ListSuspend<T>} * @returns {ListSuspend<T>}
*/ */
cons(value) { cons(value) {
return new ListSuspend(concat(value, this._value)) return new ListSuspend(value, () => this)
} }
head() { head() {
@ -88,8 +103,13 @@ class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Monoid, Comonad) {
return this.reduce(reduceArray, []) return this.reduce(reduceArray, [])
} }
static empty() { count() {
return List.empty() return this.tail().count() + 1
}
/** @returns {this is Empty} */
isEmpty() {
return false
} }
} }
@ -99,22 +119,37 @@ class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Monoid, Comonad) {
*/ */
export class List { export class List {
/** /**
* @template {Iterable<T>} T * @template T
* @param {T} value * @param {T} value
* @returns {ListSuspend<T>} * @returns {List<T>}
*/ */
static of(value) { static of(value) {
// @ts-ignore return new ListSuspend(value, List.empty)
return new ListSuspend(liftF(value))
} }
/** /**
* @template T * @template T
* @param {Iterable<T>} iterator * @param {Iterable<T>} iterable
* @returns {ListSuspend<T>} * @returns {List<T>}
*/ */
static from(iterator) { static from(iterable) {
return new ListSuspend(Iterator.from(iterator)) const iterator = Iterator.from(iterable)
return List.fromIterator(iterator)
}
/**
* @template T
* @param {Iterator<T>} iterator
* @returns {List<T>}
*/
static fromIterator(iterator) {
const next = iterator.next()
if (next.done) {
return List.empty()
} else {
return new ListSuspend(next.value, () => List.fromIterator(iterator))
}
} }
static empty() { static empty() {