diff --git a/src/algebra/fn.js b/src/algebra/fn.js index a3c894b..ddf626f 100644 --- a/src/algebra/fn.js +++ b/src/algebra/fn.js @@ -1,5 +1,5 @@ import { curry } from '../curry.js' -import { Free, Suspend, suspend, pure } from './free.js' +import { Suspend, suspend, pure } from './free.js' /** @import {InferredMorphism, Morphism, ChainConstructor} from './types.js' */ @@ -42,4 +42,3 @@ export const liftF = x => suspend( /** @type {InferredMorphism} */(pure) ) - diff --git a/src/algebra/list.js b/src/algebra/list.js index ddb9078..e23dd0a 100644 --- a/src/algebra/list.js +++ b/src/algebra/list.js @@ -1,3 +1,4 @@ +import { concat } from '../iter.js' import { liftF } from './fn.js' import { Pure, Suspend } from './free.js' import { AlgebraWithBase, Comonad, Foldable } from './index.js' @@ -12,7 +13,7 @@ const Nil = Symbol('Nil') */ class ListPure extends AlgebraWithBase(Pure)(Foldable) { head() { - return this.head + return this._value } tail() { @@ -21,8 +22,8 @@ class ListPure extends AlgebraWithBase(Pure)(Foldable) { /** * @template U - * @param {(acc: U, value: T) => U} f - * @param {U} init + * @param {(acc: U, value: T) => U} f + * @param {U} init * @returns {U} */ reduce(f, init) { @@ -30,14 +31,13 @@ class ListPure extends AlgebraWithBase(Pure)(Foldable) { } } - /** * @template T * @extends {Suspend} */ class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Comonad) { /** - * @param {IteratorObject} iter + * @param {Iterator} iter */ constructor(iter) { const next = iter.next() @@ -47,6 +47,16 @@ class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Comonad) { super(value, fn) } + /** + * @template {Iterable} T + * @this {ListSuspend>} + * @param {Iterator} value + * @returns {ListSuspend} + */ + cons(value) { + return new ListSuspend(concat(value, this._value)) + } + head() { return this._value } @@ -57,8 +67,8 @@ class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Comonad) { /** * @template U - * @param {(acc: U, value: T) => U} f - * @param {U} init + * @param {(acc: U, value: T) => U} f + * @param {U} init * @returns {U} */ reduce(f, init) { @@ -67,7 +77,7 @@ class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Comonad) { } extract() { - return this.reduce((acc, value) => acc.concat(value), []) + return this.reduce(reduceArray, []) } } @@ -78,7 +88,7 @@ class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Comonad) { export class List { /** * @template {Iterable} T - * @param {T} value + * @param {T} value * @returns {ListSuspend} */ static of(value) { @@ -88,7 +98,7 @@ export class List { /** * @template T - * @param {Iterable} iterator + * @param {Iterable} iterator * @returns {ListSuspend} */ static from(iterator) { @@ -102,8 +112,16 @@ export class List { const Empty = new ListPure(Nil) +/** + * @template T + * @param {T[]} acc + * @param {T} value + * @returns {T[]} + */ +const reduceArray = (acc, value) => acc.concat(value) -const a = Array.from({ length: 100 }).map((_, i) => i) + +const a = Array.from({ length: 10 }).map((_, i) => i) const wawa = List.from(a) console.log(wawa.reduce((acc, value) => acc.concat(value), [])) diff --git a/src/iter.js b/src/iter.js new file mode 100644 index 0000000..eadd2b2 --- /dev/null +++ b/src/iter.js @@ -0,0 +1,34 @@ +/** + * @template T + * @param {T | Iterable | Iterator} value + * @returns {value is Iterable} + */ +export function isIterable(value) { + return value[Symbol.iterator] != null +} +/** + * @template T + * @param {T | Iterable | Iterator} value + * @yields {T} + */ +export function* iter(value) { + if (isIterable(value)) { + yield* Iterator.from(value) + } else { + yield value + } +} + +/** + * @template T + * @param {...(Iterable | Iterator)} iterators + * @yields {T} + */ +export const concat = function*(...iterators) { + for (const iter of iterators) { + for (const item of Iterator.from(iter)) { + yield item + } + } +} +