diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9b84117 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/izuna"] + path = vendor/izuna + url = git@git.kitsu.cafe:rowan/izuna.git diff --git a/src/algebra/fn.js b/src/algebra/fn.js deleted file mode 100644 index 75e3f0d..0000000 --- a/src/algebra/fn.js +++ /dev/null @@ -1,67 +0,0 @@ -import { curry } from '../curry.js' -import { concat } from '../iter.js' -import { Impure, pure, impure } from './free.js' - -/** @import {InferredMorphism, Morphism, ChainConstructor} from './types.js' */ - -/** - * @template T - * @param {T} x - * @returns {x} - */ -export const id = x => x - -export const compose = curry( - /** - * @template T, U, V - * @param {Morphism} f - * @param {Morphism} g - * @param {T} x - * @returns V - */ - (f, g, x) => f(g(x)) -) - -export const kleisliCompose = curry( - /** - * @template {ChainConstructor} M, T, U - * @param {M} f - * @param {Morphism} g - * @param {T} x - * @returns U - */ - (f, g, x) => f(x).chain(g) -) - -export const lift = (...args) => args - -/** - * @template T - * @param {T} x - * @returns {Impure} - */ -export const liftF = x => impure( - x, - /** @type {InferredMorphism} */(pure) -) - -/** - * @param {number} a - * @param {number} b - * @returns {number} - */ -export const add = (a, b) => a + b - -/** - * @template T - * @param {T} x - * @returns {() => T} - */ -export const thunk = x => () => x - -export const prepend = (x, xs) => concat([x], xs) - -export const type = x => typeof x -export const is = (ctr, x) => x.constructor === ctr - - diff --git a/src/algebra/free.js b/src/algebra/free.js index 002ab0b..6c04605 100644 --- a/src/algebra/free.js +++ b/src/algebra/free.js @@ -1,5 +1,4 @@ -import { Option } from './option.js' -import { thunk } from './fn.js' +import { id, map, ap, prepend, reduce, thunk } from './fn.js' /** @import { Morphism } from './types.js' */ @@ -50,8 +49,8 @@ export class Pure { return b.map(this.#value) } - traverse(f, A) { - return A.of(this.map(f)) + traverse(f, of) { + return of(this.map(f)) } /** @@ -131,9 +130,9 @@ export class Impure { ) } - traverse(f, A) { - return A.of(liftF( - this.#next().traverse(f, A) + traverse(f, of) { + return of(liftF( + this.#next().traverse(f, of) )) } @@ -144,9 +143,36 @@ export class Impure { * @returns {B} */ reduce(f, acc) { + } } +const sequence = (of, iter) => { + console.log(ap(of([]), 1)) + return reduce((acc, x) => { + ap(acc, map(prepend, x)) + }, of([]), iter) +} + + +class Reducer { + constructor(v) { + this.value = v + } + + static of(v) { + return new Reducer(v) + } + + ap(other) { + console.log(this, other) + return this.value(other.value) + } +} + +const r = Reducer.of +console.log(sequence(r, [r(1), r(2), r(3)])) + /** * @template A * @param {A} x @@ -161,3 +187,6 @@ export const pure = x => new Pure(x) export const impure = f => new Impure(f) export const liftF = effect => impure(thunk(effect)) +const xs = liftF(pure(1)).map(thunk(2)).map(thunk(3)) +console.log(xs.traverse(id, id)) + diff --git a/src/curry.js b/src/curry.js deleted file mode 100644 index a6ac077..0000000 --- a/src/curry.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @template {(...args: any[]) => any} F - * @typedef {F extends ((...args: infer A) => any) ? A : never} Params - */ - -/** - * @template {any[]} T - * @typedef {T extends [any, ...any[]] ? T[0] : never} Head - */ - -/** - * @template {any[]} T - * @typedef {((...t: T) => any) extends ((_: any, ...tail: infer TT) => any) ? TT : []} Tail - */ - -/** - * @template {any[]} T - * @typedef {T extends ([] | [any]) ? false : true} HasTail - */ - -/** - * @template {any[]} T - * @typedef {{ 0: Last>; 1: Head }[HasTail extends true ? 0 : 1]} Last - */ - -/** - * @template {any[]} T - * @typedef {T['length']} Length - */ - -/** - * @template E - * @template {any[]} T - * @typedef {((head: E, ...args: T) => any) extends ((...args: infer U) => any) ? U : T} Prepend - */ - -/** - * @template {number} N - * @template {any[]} T - * @template {any[]} [I = []] - * @typedef {{ 0: Drop, Prepend>; 1: T }[Length extends N ? 1 : 0]} Drop - */ - -/** - * @template X, Y - * @typedef {X extends Y ? X : Y} Cast - */ - -/** - * @template {any[]} P, R - * @typedef {(...args: Cast>) => Drop, P> extends [any, ...any[]] ? Curried, P>, any[]>, R> : R} Curried - */ - -/** - * @template {any[]} P, R - * @param {(...args: P) => R} func - * @returns {Curried} - */ -export function curry(func) { - return function curried(...args) { - if (args.length >= func.length) { - return func.apply(this, args) - } else { - /** @type {Curried} */ - return function(...args2) { - return curried.apply(this, args.concat(args2)) - } - } - } -} - - diff --git a/src/iter.js b/src/iter.js deleted file mode 100644 index eadd2b2..0000000 --- a/src/iter.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @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 - } - } -} - diff --git a/vendor/izuna b/vendor/izuna new file mode 160000 index 0000000..d9daed0 --- /dev/null +++ b/vendor/izuna @@ -0,0 +1 @@ +Subproject commit d9daed0d0977f7b79462fb204a5d89b827dcac1b