-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: reorganize contrib, implement stream, simplify optic
This is a fairly large commit. The primary goals were to recreate the dux state management library on top of fun. This led down a rabbit whole that included: 1. Implementing and writing tests for DatumEither 2. Exploring various stream implementations, including mostjs, rxjs, most2, and callbags. 3. Implementing a Stream type in fun. 4. Implementing Dux on top of Stream and DatumEither In addition to adding Stream, Dux, and DatumEither I settled on a simpler model for "contributions". Previous external contributions lived in the contrib directory. These were anything from experimental ideas to algebraic structure wrappers around other libraries. Ultimately, the purpose of fun is to be dependency free, so external libraries were removed and "ideas" were either promoted to full fledged modules or moved into the "ideas" directory. This simplifies fun by making "ideas" non-production. There is still some overlap between ideas and modules marked as experimental. The basic idea is that modules in the ideas directoey may or may not be published, but modules in the root directory are definitely published. Experimental tagged modules indicate that the api for those modules is considered unstable. In contrib, the mostjs and fast-check modules were removed. Free was promoted to a root module, and dux was moved to ideas. There were a handful of small api additions to various modules such as promise, array, and async_iterable. Lastly, the Optic type in optic.ts was simplified. Previously, Optic was broken into an intersection of Viewer and Modifier, with Reviewer being a separate type. I found a way to properly do an optional include of reviewer in the root Optic type so the subtypes of Viewer, Modifier, and Reviewer were removed. The benefit of this is that the standard compose function in optic.ts will properly compose a review function if it exists on the optics being composed. may or may not be puli
- Loading branch information
Showing
37 changed files
with
4,545 additions
and
1,704 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import * as A from "../array.ts"; | ||
import * as N from "../number.ts"; | ||
import { pipe } from "../fn.ts"; | ||
|
||
const count = 100_000; | ||
const sorted = A.range(count); | ||
const binarySearch = A.binarySearch(N.SortableNumber); | ||
const monoSearch = A.monoSearch(N.SortableNumber); | ||
const searches = pipe(A.range(count), A.map(() => Math.random() * count)); | ||
|
||
Deno.bench("array binarySearch", { group: "binarySearch" }, () => { | ||
searches.forEach((value) => binarySearch(value, sorted)); | ||
}); | ||
|
||
Deno.bench("array monoSearch", { group: "binarySearch" }, () => { | ||
searches.forEach((value) => monoSearch(value, sorted)); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import * as S from "../stream.ts"; | ||
import * as CB from "../ideas/callbag.ts"; | ||
import * as M from "npm:@most/[email protected]"; | ||
import * as MS from "npm:@most/[email protected]"; | ||
import * as R from "npm:[email protected]"; | ||
import { pipe } from "../fn.ts"; | ||
|
||
const count = 1_000_000; | ||
const add = (a: number, b: number) => a + b; | ||
const passthrough = (_: number, value: number) => value; | ||
const runRx = <A>(obs: R.Observable<A>): Promise<void> => | ||
new Promise((resolve, reject) => { | ||
obs.subscribe({ complete: resolve, error: reject }); | ||
}); | ||
function mostRange(count: number) { | ||
return M.newStream<number>((snk) => { | ||
let ended = false; | ||
let index = -1; | ||
while (++index < count) { | ||
if (ended) { | ||
break; | ||
} | ||
snk.event(0, index); | ||
} | ||
if (!ended) { | ||
snk.end(0); | ||
} | ||
return { | ||
dispose: () => { | ||
ended = true; | ||
}, | ||
}; | ||
}); | ||
} | ||
|
||
Deno.bench("stream scan", { group: "scan" }, async () => { | ||
await pipe( | ||
S.range(count), | ||
S.scan(add, 0), | ||
S.scan(passthrough, 0), | ||
S.runPromise(S.DefaultEnv), | ||
); | ||
}); | ||
|
||
Deno.bench("callbag scan", { group: "scan" }, async () => | ||
await pipe( | ||
CB.range(count), | ||
CB.scan(add, 0), | ||
CB.scan(passthrough, 0), | ||
CB.runPromise({ queueMicrotask }), | ||
)); | ||
|
||
Deno.bench("most scan", { group: "scan" }, async () => | ||
await pipe( | ||
mostRange(count), | ||
M.scan(add, 0), | ||
M.scan(passthrough, 0), | ||
(stream) => | ||
M.runEffects( | ||
stream, | ||
MS.newDefaultScheduler(), | ||
), | ||
)); | ||
|
||
Deno.bench("rxjs scan", { group: "scan" }, async () => { | ||
await pipe( | ||
R.range(0, count), | ||
R.scan(add, 0), | ||
R.scan(passthrough, 0), | ||
runRx, | ||
); | ||
}); | ||
|
||
const JOIN_COUNT = 1_000; | ||
|
||
Deno.bench("stream join", { group: "join" }, async () => { | ||
await pipe( | ||
S.range(JOIN_COUNT), | ||
S.flatmap(() => S.range(JOIN_COUNT)), | ||
S.runPromise(S.DefaultEnv), | ||
); | ||
}); | ||
|
||
Deno.bench("most join", { group: "join" }, async () => { | ||
await pipe( | ||
mostRange(JOIN_COUNT), | ||
M.chain(() => mostRange(JOIN_COUNT)), | ||
(stream) => | ||
M.runEffects( | ||
stream, | ||
MS.newDefaultScheduler(), | ||
), | ||
); | ||
}); | ||
|
||
Deno.bench("rxjs join", { group: "join" }, async () => { | ||
await pipe( | ||
R.range(0, JOIN_COUNT), | ||
R.mergeMap(() => R.range(0, JOIN_COUNT)), | ||
runRx, | ||
); | ||
}); |
Oops, something went wrong.