types & free reduce
This commit is contained in:
parent
853601f2c5
commit
cf3fe66f73
3 changed files with 74 additions and 20 deletions
|
@ -1,7 +1,7 @@
|
|||
import { Algebra, Monad } from './interfaces.js'
|
||||
import { Algebra, Foldable, Monad, Traversable } from './interfaces.js'
|
||||
import { curry } from '../..//vendor/izuna/src/index.js'
|
||||
|
||||
/** @import { Applicative, ApplicativeTypeRef, Morphism } from './types.js' */
|
||||
/** @import { Applicative, ApplicativeTypeRef, Apply, Chain, Foldable as FoldableT, Functor, Monad as MonadT, Morphism, Traversable as TraversableT } from './types.js' */
|
||||
|
||||
|
||||
/** @import { InferredMorphism } from './types.js' */
|
||||
|
@ -12,7 +12,7 @@ const kleisli = curry((f, g, x) => f(x).chain(g))
|
|||
* @template T
|
||||
* @type {Pure<T> | Impure<T>} Free
|
||||
*/
|
||||
export class Free extends Algebra(Monad) {
|
||||
export class Free {
|
||||
/**
|
||||
* @template T
|
||||
* @param {T} value
|
||||
|
@ -23,7 +23,7 @@ export class Free extends Algebra(Monad) {
|
|||
}
|
||||
|
||||
/** @template T */
|
||||
export class Pure extends Free {
|
||||
export class Pure extends Algebra(Monad, Traversable) {
|
||||
#value
|
||||
|
||||
/**
|
||||
|
@ -48,13 +48,29 @@ export class Pure extends Free {
|
|||
return pure(f(this.#value))
|
||||
}
|
||||
|
||||
/**
|
||||
* @template U
|
||||
* @this {Pure<Morphism<U, T>>}
|
||||
* @param {Free<T>} b
|
||||
*/
|
||||
ap(b) {
|
||||
return b.map(this.#value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {FoldableT<T>['reduce']}
|
||||
*/
|
||||
reduce(f, acc) {
|
||||
return f(acc, this.#value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @template U
|
||||
* @template {Applicative<U>} M
|
||||
* @template {ApplicativeTypeRef<U, M>} TypeRef
|
||||
* @param {TypeRef} _A
|
||||
* @param {*} f
|
||||
* @returns {M}
|
||||
* @param {(value: T) => M} f
|
||||
* @returns {Applicative<Free<U>>}
|
||||
*/
|
||||
traverse(_A, f) {
|
||||
return f(this.#value).map(pure)
|
||||
|
@ -65,14 +81,19 @@ export class Pure extends Free {
|
|||
}
|
||||
}
|
||||
|
||||
/** @template T */
|
||||
export class Impure extends Free {
|
||||
/**
|
||||
* @template T, [N=any]
|
||||
* @implements Functor<T>
|
||||
* @implements Chain<T>
|
||||
* @implements TraversableT<T>
|
||||
*/
|
||||
export class Impure extends Algebra(Monad, Foldable, Traversable) {
|
||||
#value
|
||||
#next
|
||||
|
||||
/**
|
||||
* @param {T} value
|
||||
* @param {(value: T) => Free<any>} f
|
||||
* @param {(value: T) => Free<N>} f
|
||||
*/
|
||||
constructor(value, f) {
|
||||
super()
|
||||
|
@ -81,26 +102,56 @@ export class Impure extends Free {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {<U>(value: T) => Free<U>} f
|
||||
* @type {Chain<T>['chain']}
|
||||
* @template U
|
||||
* @param {(value: T) => Free<U>} f
|
||||
* @returns {Chain<T>}
|
||||
*/
|
||||
chain(f) {
|
||||
return impure(this.#value, kleisli(this.#next, f))
|
||||
}
|
||||
|
||||
/**
|
||||
* @template {Functor<T>} U
|
||||
* @type {Functor<T>['map']}
|
||||
* @param {(value: T) => U} f
|
||||
* @returns {Functor<T>}
|
||||
*/
|
||||
map(f) {
|
||||
return impure(
|
||||
this.#value,
|
||||
y => f(y).chain(f)
|
||||
y => f(y).map(f)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Apply<T>['ap']}
|
||||
*/
|
||||
ap(b) {
|
||||
return this.chain(f => 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))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {TraversableT<T>['traverse']}
|
||||
* @template U
|
||||
* @template {Applicative<U>} M
|
||||
* @template {ApplicativeTypeRef<U, M>} TypeRef
|
||||
* @this {Impure<T, N>}
|
||||
* @param {TypeRef} A
|
||||
* @param {(value: T) => M} f
|
||||
* @returns {M}
|
||||
* @param {(value: T | N) => M} f
|
||||
* @returns {Applicative<Free<U>>}
|
||||
*/
|
||||
traverse(A, f) {
|
||||
const fb = f(this.#value)
|
||||
|
@ -131,6 +182,7 @@ const pure = x => new Pure(x)
|
|||
*/
|
||||
const impure = (x, f) => new Impure(x, f)
|
||||
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {T} x
|
||||
|
|
|
@ -100,9 +100,10 @@ export default {}
|
|||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {{
|
||||
ap: <U>(f: Apply<Morphism<T, U>>) => Apply<U>
|
||||
* }} Apply
|
||||
* @typedef {
|
||||
Functor<T> &
|
||||
{ ap: <U>(f: Apply<Morphism<T, U>>) => Apply<U> }
|
||||
* } Apply
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -157,7 +158,7 @@ export default {}
|
|||
/**
|
||||
* @template T
|
||||
* @typedef {{
|
||||
filter: <U>(f: (acc: U, val: T) => U, init: U) => U
|
||||
reduce: <U>(f: (acc: U, val: T) => U, init: U) => U
|
||||
* }} Foldable
|
||||
*/
|
||||
|
||||
|
|
|
@ -77,15 +77,16 @@ function is(other) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @template {PropertyKey} const T
|
||||
* @template {string} const T
|
||||
* @template {Array<PropertyKey>} const U
|
||||
* @param {T} typeName
|
||||
* @param {...U} variantNames
|
||||
* @returns {Union<T, U>}
|
||||
*/
|
||||
export const Union = (typeName, variantNames) => {
|
||||
const tag = { [Tag]: typeName, is }
|
||||
const variants = Object.fromEntries(variantNames.map(v => [v, Variant(typeName, v)]))
|
||||
const typeTag = Symbol(typeName)
|
||||
const tag = { [Tag]: typeTag, is }
|
||||
const variants = Object.fromEntries(variantNames.map(v => [v, Variant(typeTag, v)]))
|
||||
const result = Object.assign(tag, variants)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue