move functions to own library

This commit is contained in:
Rowan 2025-04-09 02:18:49 -05:00
parent f79a2ca462
commit 96cc50ad34
6 changed files with 40 additions and 180 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "vendor/izuna"]
path = vendor/izuna
url = git@git.kitsu.cafe:rowan/izuna.git

View file

@ -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<U, V>} f
* @param {Morphism<T, U>} g
* @param {T} x
* @returns V
*/
(f, g, x) => f(g(x))
)
export const kleisliCompose = curry(
/**
* @template {ChainConstructor<T>} M, T, U
* @param {M} f
* @param {Morphism<T, U>} 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<T>}
*/
export const liftF = x => impure(
x,
/** @type {InferredMorphism<T>} */(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

View file

@ -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))

View file

@ -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<Tail<T>>; 1: Head<T> }[HasTail<T> 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<N, Tail<T>, Prepend<any, I>>; 1: T }[Length<I> extends N ? 1 : 0]} Drop
*/
/**
* @template X, Y
* @typedef {X extends Y ? X : Y} Cast
*/
/**
* @template {any[]} P, R
* @typedef {<T extends any[]>(...args: Cast<T, Partial<P>>) => Drop<Length<T>, P> extends [any, ...any[]] ? Curried<Cast<Drop<Length<T>, P>, any[]>, R> : R} Curried
*/
/**
* @template {any[]} P, R
* @param {(...args: P) => R} func
* @returns {Curried<P, R>}
*/
export function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args)
} else {
/** @type {Curried<P, R>} */
return function(...args2) {
return curried.apply(this, args.concat(args2))
}
}
}
}

View file

@ -1,34 +0,0 @@
/**
* @template T
* @param {T | Iterable<T> | Iterator<T>} value
* @returns {value is Iterable<T>}
*/
export function isIterable(value) {
return value[Symbol.iterator] != null
}
/**
* @template T
* @param {T | Iterable<T> | Iterator<T>} value
* @yields {T}
*/
export function* iter(value) {
if (isIterable(value)) {
yield* Iterator.from(value)
} else {
yield value
}
}
/**
* @template T
* @param {...(Iterable<T> | Iterator<T>)} iterators
* @yields {T}
*/
export const concat = function*(...iterators) {
for (const iter of iterators) {
for (const item of Iterator.from(iter)) {
yield item
}
}
}

1
vendor/izuna vendored Submodule

@ -0,0 +1 @@
Subproject commit d9daed0d0977f7b79462fb204a5d89b827dcac1b