add reduce derivation; add reduce to Free; fix traverse
This commit is contained in:
parent
cf3fe66f73
commit
619f24c7dc
3 changed files with 75 additions and 38 deletions
|
@ -1,7 +1,8 @@
|
|||
import { Algebra, Foldable, Monad, Traversable } from './interfaces.js'
|
||||
import { curry } from '../..//vendor/izuna/src/index.js'
|
||||
import { Reducer } from './utilities.js'
|
||||
|
||||
/** @import { Applicative, ApplicativeTypeRef, Apply, Chain, Foldable as FoldableT, Functor, Monad as MonadT, Morphism, Traversable as TraversableT } from './types.js' */
|
||||
/** @import { Applicative, ApplicativeTypeRef, Apply, Chain, Comonad, Foldable as FoldableT, Functor, Monad as MonadT, Morphism, Traversable as TraversableT } from './types.js' */
|
||||
|
||||
|
||||
/** @import { InferredMorphism } from './types.js' */
|
||||
|
@ -10,17 +11,9 @@ const kleisli = curry((f, g, x) => f(x).chain(g))
|
|||
|
||||
/**
|
||||
* @template T
|
||||
* @type {Pure<T> | Impure<T>} Free
|
||||
* @typedef {Pure<T> | Impure<T>} Free
|
||||
*/
|
||||
export class Free {
|
||||
/**
|
||||
* @template T
|
||||
* @param {T} value
|
||||
*/
|
||||
static of(value) {
|
||||
return new Pure(value)
|
||||
}
|
||||
}
|
||||
const Free = {}
|
||||
|
||||
/** @template T */
|
||||
export class Pure extends Algebra(Monad, Traversable) {
|
||||
|
@ -35,14 +28,14 @@ export class Pure extends Algebra(Monad, Traversable) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {InferredMorphism<T>} f
|
||||
* @type {Chain<T>['chain']}
|
||||
*/
|
||||
chain(f) {
|
||||
return f(this.#value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {InferredMorphism<T>} f
|
||||
* @type {Functor<T>['map']}
|
||||
*/
|
||||
map(f) {
|
||||
return pure(f(this.#value))
|
||||
|
@ -50,11 +43,13 @@ export class Pure extends Algebra(Monad, Traversable) {
|
|||
|
||||
/**
|
||||
* @template U
|
||||
* @type {Apply<T>['ap']}
|
||||
* @this {Pure<Morphism<U, T>>}
|
||||
* @param {Free<T>} b
|
||||
* @param {Pure<U>} b
|
||||
* @returns {Free<T>}
|
||||
*/
|
||||
ap(b) {
|
||||
return b.map(this.#value)
|
||||
return /** @type {Free<T>} */ (b.map(this.#value))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,7 +100,7 @@ export class Impure extends Algebra(Monad, Foldable, Traversable) {
|
|||
* @type {Chain<T>['chain']}
|
||||
* @template U
|
||||
* @param {(value: T) => Free<U>} f
|
||||
* @returns {Chain<T>}
|
||||
* @returns {Free<T>}
|
||||
*/
|
||||
chain(f) {
|
||||
return impure(this.#value, kleisli(this.#next, f))
|
||||
|
@ -114,33 +109,36 @@ export class Impure extends Algebra(Monad, Foldable, Traversable) {
|
|||
/**
|
||||
* @template {Functor<T>} U
|
||||
* @type {Functor<T>['map']}
|
||||
* @param {(value: T) => U} f
|
||||
* @returns {Functor<T>}
|
||||
* @param {Morphism<T, U>} f
|
||||
* @returns {Free<T>}
|
||||
*/
|
||||
map(f) {
|
||||
return impure(
|
||||
this.#value,
|
||||
y => f(y).map(f)
|
||||
y => /** @type {Free<U>} */(f(y).map(f))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @template U
|
||||
* @type {Apply<T>['ap']}
|
||||
* @this {Free<Morphism<U, T>>}
|
||||
* @param {Free<U>} b
|
||||
* @returns {Free<T>}
|
||||
*/
|
||||
ap(b) {
|
||||
return this.chain(f => b.map(f))
|
||||
return /** @type {Free<T>} */ (this.chain(f =>
|
||||
/** @type {Free<T>} */(b.map(f))
|
||||
))
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {FoldableT<T>['reduce']}
|
||||
*/
|
||||
reduce(f, acc) {
|
||||
const fb = f(acc, this.#value)
|
||||
const rest = this.#next(this.#value).reduce(f, acc)
|
||||
|
||||
return rest.ap(
|
||||
fb.map(b => next => impure(b, () => next))
|
||||
)
|
||||
const Const = Reducer(f, acc)
|
||||
// @ts-ignore
|
||||
return this.traverse(Const, x => new Const(x)).value
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,12 +152,20 @@ export class Impure extends Algebra(Monad, Foldable, Traversable) {
|
|||
* @returns {Applicative<Free<U>>}
|
||||
*/
|
||||
traverse(A, f) {
|
||||
const fb = f(this.#value)
|
||||
const rest = this.#next(this.#value).traverse(A, f)
|
||||
const next = this.#next(this.#value)
|
||||
|
||||
return rest.ap(
|
||||
fb.map(b => next => impure(b, () => next))
|
||||
)
|
||||
if (next instanceof Pure) {
|
||||
return next.traverse(A, f)
|
||||
} else {
|
||||
const fb = f(this.#value)
|
||||
const rest = next.traverse(A, f)
|
||||
|
||||
return /** @type {Applicative<Free<U>>} */ (rest.ap(
|
||||
fb.map(b => next => impure(b, () =>
|
||||
/** @type {Free<U>} */(next)
|
||||
))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
run() {
|
||||
|
@ -192,6 +198,6 @@ export const liftF = x => impure(x, pure)
|
|||
import { id, Identity } from './identity.js'
|
||||
import { Option, some } from './option.js'
|
||||
|
||||
const a = liftF(1).chain(() => liftF(2)).traverse(Option, x => some(1))
|
||||
console.log(a.chain(x => x).run())
|
||||
const a = liftF(1).chain(() => liftF(2)).reduce((acc, x) => acc + x, 0)
|
||||
console.log(a)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Algebra, Comonad, Monad } from './interfaces.js'
|
||||
|
||||
/** @import { Morphism } from './types.js' */
|
||||
/** @import { Apply, Morphism } from './types.js' */
|
||||
|
||||
/** @template T */
|
||||
export class Identity extends Algebra(Monad, Comonad) {
|
||||
|
@ -28,17 +28,18 @@ export class Identity extends Algebra(Monad, Comonad) {
|
|||
* @param {Morphism<T, U>} f
|
||||
*/
|
||||
map(f) {
|
||||
console.log(this.toString(), f.toString())
|
||||
return id(f(this.#value))
|
||||
}
|
||||
|
||||
/**
|
||||
* @template U
|
||||
* @this {Identity<Morphism<U, T>>}
|
||||
* @param {Identity<U>} b
|
||||
* @returns {Identity<T>}
|
||||
* @type {Apply<T>['ap']}
|
||||
* @param {Apply<Morphism<T, U>>} b
|
||||
* @returns {Apply<U>}
|
||||
*/
|
||||
ap(b) {
|
||||
return b.map(this.#value)
|
||||
return /** @type {Apply<U>} */ (b.map(f => f(this.#value)))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,6 +60,10 @@ export class Identity extends Algebra(Monad, Comonad) {
|
|||
extract() {
|
||||
return this.#value
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `Identity(${this.#value})`
|
||||
}
|
||||
}
|
||||
|
||||
export const id = value => new Identity(value)
|
||||
|
|
26
src/algebra/utilities.js
Normal file
26
src/algebra/utilities.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* @template T, U
|
||||
* @param {(acc: U, value: T) => U} f
|
||||
* @param {U} acc
|
||||
*/
|
||||
export const Reducer = (f, acc) => {
|
||||
/** @template A */
|
||||
return class Const {
|
||||
/** @param {A} value */
|
||||
constructor(value) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
static of() { return new Const(acc) }
|
||||
|
||||
map() { return this }
|
||||
|
||||
/**
|
||||
* @this {Const<T>}
|
||||
* @param {Const<U>} b
|
||||
*/
|
||||
ap(b) {
|
||||
return new Const(f(b.value, this.value))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue