diff --git a/TODO.md b/TODO.md index dc51c32..058a5b4 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,4 @@ -用 generic 函数定义 lift -- 删除 `skipIncompleteInputs` +删除 `skipIncompleteInputs` monads/supported-monad -- 删除 `maybeUnwrapSupported` > propagator 支持 dependencies for provenance diff --git a/src/monad/index.ts b/src/monad/index.ts index 52927c5..cf90839 100644 --- a/src/monad/index.ts +++ b/src/monad/index.ts @@ -1,5 +1,27 @@ import { defineGeneric } from "../generic/index.js" -export const fmap = defineGeneric({ default: (f, mx) => f(mx) }) -export const join = defineGeneric({ default: (mmx) => mmx }) -export const bind = (mx: any, f: (x: any) => any) => join(fmap(f, mx)) +// (f: (A) -> B, ma: M(A)) -> M(B) +export const fmap = defineGeneric({ default: (f, ma) => f(ma) }) + +// (mma: M(M(A))) -> M(A) +export const join = defineGeneric({ default: (mma) => mma }) + +// (ma: M(A), f: (A) -> M(B)) -> M(B) +export const bind = (ma: any, f: (x: any) => any) => join(fmap(f, ma)) + +// (f: (A0, A1, ...) -> B) -> (M(A0), M(A1), ...) -> M(B) +export function naryFmap( + f: (...args: Array) => any, +): (...margs: Array) => any { + return (...margs) => { + function loop(margs: Array, f: (...args: Array) => any): any { + if (margs.length === 0) return f() + + return bind(margs[0], (arg) => + loop(margs.slice(1), (...restArgs) => f(arg, ...restArgs)), + ) + } + + return loop(margs, f) + } +} diff --git a/src/monads/nothing-monad.ts b/src/monads/nothing-monad.ts index 42415fd..227ba7c 100644 --- a/src/monads/nothing-monad.ts +++ b/src/monads/nothing-monad.ts @@ -3,5 +3,5 @@ import { defineHandler } from "../generic/index.js" import { fmap, join } from "../monad/index.js" import { isFunction } from "../utils/isFunction.js" -defineHandler(fmap, [isFunction, isNothing], (f, mx) => nothing) -defineHandler(join, [isNothing], (mmx) => nothing) +defineHandler(fmap, [isFunction, isNothing], (f, ma) => nothing) +defineHandler(join, [isNothing], (mma) => nothing) diff --git a/src/propagator/definePrimitive.ts b/src/propagator/definePrimitive.ts index 0035ba6..01a2939 100644 --- a/src/propagator/definePrimitive.ts +++ b/src/propagator/definePrimitive.ts @@ -1,5 +1,7 @@ import { Cell, addPropagator, isNothing, nothing, put } from "../cell/index.js" import { isSupported } from "../dependency/index.js" +import { naryFmap } from "../monad/index.js" +import "../monads/nothing-monad.js" import { schedule } from "../scheduler/index.js" import type { MaybePromise } from "../utils/MaybePromise.js" import { repeatApply } from "../utils/repeatApply.js" @@ -87,8 +89,7 @@ function watch(cells: Array>, propagator: Propagator): void { function lift( fn: (...args: Array) => MaybePromise, ): (...args: Array>) => MaybePromise { - fn = maybeUnwrapSupported(fn) - fn = skipIncompleteInputs(fn) + fn = naryFmap(fn) return (...inputs) => fn(...inputs.map((input) => input.content)) }