wip cons list

This commit is contained in:
Rowan 2025-04-06 12:50:31 -05:00
parent e213666051
commit 0336213ca9
5 changed files with 140 additions and 72 deletions

View file

@ -2,7 +2,7 @@
"compilerOptions": {
"module": "es2020",
"target": "es6",
"lib": ["es2022", "dom"],
"lib": ["esnext", "dom"],
"checkJs": true,
"paths": {
"/*": ["./*"]

View file

@ -1,5 +1,5 @@
import { curry } from '../curry.js'
import { Free, Suspend, pure } from './free.js'
import { Free, Suspend, suspend, pure } from './free.js'
/** @import {InferredMorphism, Morphism, ChainConstructor} from './types.js' */
@ -35,9 +35,9 @@ export const kleisliCompose = curry(
/**
* @template T
* @param {T} x
* @returns {Free<T>}
* @returns {Suspend<T>}
*/
export const liftF = x => new Suspend(
export const liftF = x => suspend(
x,
/** @type {InferredMorphism<T>} */(pure)
)

View file

@ -1,11 +1,15 @@
import { liftF } from './fn.js'
import { Algebra, Comonad, EitherOf, Functor, Monad } from './index.js'
import { Algebra, BaseSet, Comonad, Monad } from './index.js'
/** @import { InferredMorphism, Morphism } from './types.js' */
/** @template T */
export class Suspend extends Algebra(Functor, Monad) {
#value
/**
* @template T
* @extends BaseSet
* @mixes Monad
*/
export class Suspend extends Algebra(Monad) {
_value
#fn
/**
@ -14,7 +18,7 @@ export class Suspend extends Algebra(Functor, Monad) {
*/
constructor(value, fn) {
super()
this.#value = value
this._value = value
this.#fn = fn
}
@ -30,7 +34,7 @@ export class Suspend extends Algebra(Functor, Monad) {
* @returns {Suspend<T>}
*/
chain(f) {
return new Suspend(this.#value, x => this.#fn(x).chain(f))
return new Suspend(this._value, x => this.#fn(x).chain(f))
}
/**
@ -39,7 +43,7 @@ export class Suspend extends Algebra(Functor, Monad) {
* @returns {Suspend<T>}
*/
map(g) {
return new Suspend(this.#value, x => this.#fn(x).map(g))
return new Suspend(this._value, x => this.#fn(x).map(g))
}
/**
@ -51,19 +55,23 @@ export class Suspend extends Algebra(Functor, Monad) {
return this.map(g)
}
step() {
return this.#fn(this._value)
}
run() {
return this.#fn(this.#value)
return this.step().run()
}
}
/** @template T */
export class Pure extends Algebra(Functor, Monad, Comonad) {
#value
export class Pure extends Algebra(Monad, Comonad) {
_value
/** @param {T} value */
constructor(value) {
super()
this.#value = value
this._value = value
}
/** @returns {this is Pure<T>} */
@ -78,7 +86,7 @@ export class Pure extends Algebra(Functor, Monad, Comonad) {
* @returns {Pure<U>}
*/
chain(f) {
return f(this.#value)
return f(this._value)
}
/**
@ -100,11 +108,15 @@ export class Pure extends Algebra(Functor, Monad, Comonad) {
}
extract() {
return this.#value
return this._value
}
step() {
return this._value
}
run() {
return this.#value
return this._value
}
}

View file

@ -214,14 +214,8 @@ class Interface {
}
}
/** @template T*/
class BaseSet {
_value
/** @param {T} value */
constructor(value) {
this._value = value
}
/** @template T */
export class BaseSet {
}
/**
@ -250,13 +244,19 @@ export const apply = (methodName, f, obj) => {
}
}
/**
* @param {Function} base
* @returns {(...algebras: Interface[]) => FunctionConstructor}
*/
export const AlgebraWithBase = base => (...algebras) => {
return mix(base).with(...algebras.map(x => x.intoWrapper()))
}
/**
* @param {...Interface} algebras
* @returns {FunctionConstructor}
*/
export const Algebra = (...algebras) => {
return mix(BaseSet).with(...algebras.map(x => x.intoWrapper()))
}
export const Algebra = AlgebraWithBase(BaseSet)
export const Setoid = new Interface('Setoid')
.specifies('equals')
@ -331,7 +331,7 @@ export const Chain = new Interface('Chain')
Method.from('chain')
.implementation(function(f) {
return f(this._value)
}))
})
)
export const ChainRef = new Interface('ChainRec')

View file

@ -1,54 +1,110 @@
import { liftF } from './fn.js'
import { Free } from './free.js'
import { Algebra, Foldable, Functor, Monad } from './index.js'
import { none as None } from './option.js'
import { Pure, Suspend } from './free.js'
import { AlgebraWithBase, Comonad, Foldable } from './index.js'
/** @template T */
export class List extends Algebra(Functor, Monad, Foldable) {
/** @type {Free<T> | None<T>} */
_head
/** @import { InferredMorphism } from './types.js' */
/** @type {List<T>} */
_tail
const Nil = Symbol('Nil')
/**
* @param {T | None} [head]
* @param {List<T>} [tail=List]
*/
constructor(head = None, tail = List.of(None)) {
super()
this._head = head
this._tail = tail
/**
* @template T
* @extends {Pure<T>}
*/
class ListPure extends AlgebraWithBase(Pure)(Foldable) {
head() {
return this.head
}
tail() {
return Empty
}
/**
* @template T
* @param {T} value
* @returns {List<T>}
* @template U
* @param {(acc: U, value: T) => U} f
* @param {U} init
* @returns {U}
*/
prepend(value) {
return new List(value, this)
}
/**
* @template T
* @param {T} value
* @returns {List<T>}
*/
static of(value) {
return new List(value)
}
/**
* @template T
* @param {Iterable<T>} iterable
* @returns {List<T>}
*/
static from(iterable) {
Array.from(iterable).reduceRight((list, value))
reduce(f, init) {
return f(init, this._value)
}
}
const list = liftF(1)
console.log(list.map(_ => 2).map(_ => 3).chain(x => x).run())
/**
* @template T
* @extends {Suspend<T>}
*/
class ListSuspend extends AlgebraWithBase(Suspend)(Foldable, Comonad) {
/**
* @param {IteratorObject<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)
}
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((acc, value) => acc.concat(value), [])
}
}
/**
* @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)
const a = Array.from({ length: 100 }).map((_, i) => i)
const wawa = List.from(a)
console.log(wawa.reduce((acc, value) => acc.concat(value), []))