From 50f3cff3d9146da49e037531e0790ada85bef6cd Mon Sep 17 00:00:00 2001 From: rowan Date: Mon, 7 Apr 2025 02:30:49 -0500 Subject: [PATCH] List.count --- src/algebra/fn.js | 7 ++++ src/algebra/list.js | 79 ++++++++++++++++++++++++++++++++------------- 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/algebra/fn.js b/src/algebra/fn.js index ddf626f..3a877d0 100644 --- a/src/algebra/fn.js +++ b/src/algebra/fn.js @@ -42,3 +42,10 @@ export const liftF = x => suspend( /** @type {InferredMorphism} */(pure) ) +/** + * @param {number} a + * @param {number} b + * @returns {number} + */ +export const sum = (a, b) => a + b + diff --git a/src/algebra/list.js b/src/algebra/list.js index 4b8c83c..171cbd7 100644 --- a/src/algebra/list.js +++ b/src/algebra/list.js @@ -1,5 +1,3 @@ -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' @@ -37,6 +35,18 @@ class ListPure extends AlgebraWithBase(Pure)(Category, Foldable, Monoid) { reduce(f, init) { return f(init, this._value) } + + count() { + return this.isEmpty() ? 0 : 1 + } + + /** + * @this {List} + * @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) { /** - * @param {Iterator} iter + * @param {T} head + * @param {() => List} tail */ - constructor(iter) { - const next = iter.next() - const value = /** @type {T} */ (next.value) + constructor(head, tail) { + super( + head, + /** @type {InferredMorphism} */(tail) + ) + } - const fn = /** @type {InferredMorphism} */ (next.done ? List.empty : () => new ListSuspend(iter)) - super(value, fn) + + static empty() { + return List.empty() } /** - * @template {Iterable} T - * @this {ListSuspend>} - * @param {Iterator} value + * @template T + * @this {ListSuspend} + * @param {T} value * @returns {ListSuspend} */ cons(value) { - return new ListSuspend(concat(value, this._value)) + return new ListSuspend(value, () => this) } head() { @@ -88,8 +103,13 @@ class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Monoid, Comonad) { return this.reduce(reduceArray, []) } - static empty() { - return List.empty() + count() { + 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 { /** - * @template {Iterable} T + * @template T * @param {T} value - * @returns {ListSuspend} + * @returns {List} */ static of(value) { - // @ts-ignore - return new ListSuspend(liftF(value)) + return new ListSuspend(value, List.empty) } /** * @template T - * @param {Iterable} iterator - * @returns {ListSuspend} + * @param {Iterable} iterable + * @returns {List} */ - static from(iterator) { - return new ListSuspend(Iterator.from(iterator)) + static from(iterable) { + const iterator = Iterator.from(iterable) + return List.fromIterator(iterator) + } + + /** + * @template T + * @param {Iterator} iterator + * @returns {List} + */ + static fromIterator(iterator) { + const next = iterator.next() + + if (next.done) { + return List.empty() + } else { + return new ListSuspend(next.value, () => List.fromIterator(iterator)) + } } static empty() {