@soundscript/soundscript 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/async.d.ts +3 -3
- package/async.js +2 -2
- package/async.js.map +1 -1
- package/codec.d.ts +3 -2
- package/codec.js +2 -2
- package/codec.js.map +1 -1
- package/compare.js +5 -10
- package/compare.js.map +1 -1
- package/decode.d.ts +6 -4
- package/decode.js +5 -5
- package/decode.js.map +1 -1
- package/derive.d.ts +6 -0
- package/derive.js +8 -0
- package/derive.js.map +1 -0
- package/encode.d.ts +11 -9
- package/encode.js +5 -5
- package/encode.js.map +1 -1
- package/experimental/thunk.js.map +1 -0
- package/fetch.d.ts +1 -1
- package/hash.js +9 -14
- package/hash.js.map +1 -1
- package/json.d.ts +29 -2
- package/json.js +124 -1
- package/json.js.map +1 -1
- package/numerics.d.ts +523 -0
- package/numerics.js +1357 -0
- package/numerics.js.map +1 -0
- package/package.json +94 -35
- package/result.d.ts +21 -5
- package/result.js +55 -19
- package/result.js.map +1 -1
- package/soundscript/async.sts +7 -7
- package/soundscript/codec.sts +8 -7
- package/soundscript/compare.sts +5 -13
- package/soundscript/decode.sts +15 -13
- package/soundscript/derive.sts +7 -0
- package/soundscript/encode.sts +18 -16
- package/soundscript/hash.sts +9 -17
- package/soundscript/json.sts +209 -3
- package/soundscript/numerics.sts +1937 -0
- package/soundscript/result.sts +93 -24
- package/soundscript/typeclasses.sts +22 -16
- package/soundscript/value.sts +133 -0
- package/typeclasses.d.ts +2 -2
- package/typeclasses.js +10 -9
- package/typeclasses.js.map +1 -1
- package/value.d.ts +9 -0
- package/value.js +105 -0
- package/value.js.map +1 -0
- package/experimental/component.d.ts +0 -40
- package/experimental/component.js +0 -46
- package/experimental/component.js.map +0 -1
- package/soundscript/experimental/component.sts +0 -69
- package/thunk.js.map +0 -1
- /package/{thunk.d.ts → experimental/thunk.d.ts} +0 -0
- /package/{thunk.js → experimental/thunk.js} +0 -0
- /package/soundscript/{thunk.sts → experimental/thunk.sts} +0 -0
package/soundscript/result.sts
CHANGED
|
@@ -1,19 +1,91 @@
|
|
|
1
1
|
import { normalizeThrown } from '@soundscript/soundscript/failures';
|
|
2
2
|
import { type Bind, type Kind, type Kind2, type TypeLambda } from '@soundscript/soundscript/hkt';
|
|
3
3
|
import { type Applicative, type Functor, type Monad } from '@soundscript/soundscript/typeclasses';
|
|
4
|
+
import {
|
|
5
|
+
__valueFactory,
|
|
6
|
+
__valueKey,
|
|
7
|
+
__valueReadonly,
|
|
8
|
+
__valueShallowToken,
|
|
9
|
+
} from '@soundscript/soundscript/value';
|
|
10
|
+
|
|
11
|
+
const makeOk = __valueFactory<Ok<unknown>, [unknown]>(
|
|
12
|
+
(value) => __valueKey('ok', __valueShallowToken(value)),
|
|
13
|
+
() => Object.create(Ok.prototype) as Ok<unknown>,
|
|
14
|
+
(instance, value) => {
|
|
15
|
+
__valueReadonly(instance, 'tag', 'ok');
|
|
16
|
+
__valueReadonly(instance, 'value', value);
|
|
17
|
+
},
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const makeErr = __valueFactory<Err<unknown>, [unknown]>(
|
|
21
|
+
(error) => __valueKey('err', __valueShallowToken(error)),
|
|
22
|
+
() => Object.create(Err.prototype) as Err<unknown>,
|
|
23
|
+
(instance, error) => {
|
|
24
|
+
__valueReadonly(instance, 'tag', 'err');
|
|
25
|
+
__valueReadonly(instance, 'error', error);
|
|
26
|
+
},
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const makeSome = __valueFactory<Some<unknown>, [unknown]>(
|
|
30
|
+
(value) => __valueKey('some', __valueShallowToken(value)),
|
|
31
|
+
() => Object.create(Some.prototype) as Some<unknown>,
|
|
32
|
+
(instance, value) => {
|
|
33
|
+
__valueReadonly(instance, 'tag', 'some');
|
|
34
|
+
__valueReadonly(instance, 'value', value);
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const makeNone = __valueFactory<None, []>(
|
|
39
|
+
() => __valueKey('none'),
|
|
40
|
+
() => Object.create(None.prototype) as None,
|
|
41
|
+
(instance) => {
|
|
42
|
+
__valueReadonly(instance, 'tag', 'none');
|
|
43
|
+
},
|
|
44
|
+
);
|
|
4
45
|
|
|
5
46
|
// #[variance(T: out)]
|
|
6
|
-
export
|
|
47
|
+
export class Ok<T> {
|
|
48
|
+
readonly tag!: 'ok';
|
|
49
|
+
readonly value!: T;
|
|
50
|
+
|
|
51
|
+
constructor(value: T) {
|
|
52
|
+
return makeOk(value) as Ok<T>;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
7
56
|
// #[variance(E: out)]
|
|
8
|
-
export
|
|
57
|
+
export class Err<E> {
|
|
58
|
+
readonly tag!: 'err';
|
|
59
|
+
readonly error!: E;
|
|
60
|
+
|
|
61
|
+
constructor(error: E) {
|
|
62
|
+
return makeErr(error) as Err<E>;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
9
65
|
|
|
10
66
|
// #[variance(T: out, E: out)]
|
|
11
67
|
export type Result<T, E> = Ok<T> | Err<E>;
|
|
68
|
+
|
|
12
69
|
// #[variance(T: out)]
|
|
13
|
-
export
|
|
14
|
-
|
|
70
|
+
export class Some<T> {
|
|
71
|
+
readonly tag!: 'some';
|
|
72
|
+
readonly value!: T;
|
|
73
|
+
|
|
74
|
+
constructor(value: T) {
|
|
75
|
+
return makeSome(value) as Some<T>;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export class None {
|
|
80
|
+
readonly tag!: 'none';
|
|
81
|
+
|
|
82
|
+
constructor() {
|
|
83
|
+
return makeNone();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
15
87
|
// #[variance(T: out)]
|
|
16
|
-
export type Option<T> =
|
|
88
|
+
export type Option<T> = Some<T> | None;
|
|
17
89
|
|
|
18
90
|
export interface OptionF extends TypeLambda {
|
|
19
91
|
readonly type: Option<this['Args'][0]>;
|
|
@@ -27,44 +99,41 @@ export type OptionKind<T> = Kind<OptionF, T>;
|
|
|
27
99
|
export type ResultKind<E, T> = Kind2<ResultF, E, T>;
|
|
28
100
|
|
|
29
101
|
export function ok<T>(value: T): Result<T, never> {
|
|
30
|
-
return
|
|
102
|
+
return new Ok(value);
|
|
31
103
|
}
|
|
32
104
|
|
|
33
105
|
export function err(): Result<never, void>;
|
|
34
106
|
export function err<E>(error: E): Result<never, E>;
|
|
35
107
|
export function err<E>(error?: E): Result<never, E | void> {
|
|
36
|
-
return
|
|
108
|
+
return new Err(error);
|
|
37
109
|
}
|
|
38
110
|
|
|
39
111
|
export function some<T>(value: T): Option<T> {
|
|
40
|
-
return
|
|
112
|
+
return new Some(value);
|
|
41
113
|
}
|
|
42
114
|
|
|
43
115
|
export function none(): Option<never> {
|
|
44
|
-
return
|
|
116
|
+
return new None();
|
|
45
117
|
}
|
|
46
118
|
|
|
47
119
|
export function isOk<T, E>(value: Result<T, E>): value is Ok<T> {
|
|
48
|
-
return value
|
|
120
|
+
return value instanceof Ok;
|
|
49
121
|
}
|
|
50
122
|
|
|
51
123
|
export function isErr<T, E>(value: Result<T, E>): value is Err<E> {
|
|
52
|
-
return value
|
|
124
|
+
return value instanceof Err;
|
|
53
125
|
}
|
|
54
126
|
|
|
55
127
|
export function isSome<T>(value: Option<T>): value is Some<T> {
|
|
56
|
-
return
|
|
128
|
+
return value instanceof Some;
|
|
57
129
|
}
|
|
58
130
|
|
|
59
131
|
export function isNone<T>(value: Option<T>): value is None {
|
|
60
|
-
return
|
|
132
|
+
return value instanceof None;
|
|
61
133
|
}
|
|
62
134
|
|
|
63
|
-
function
|
|
64
|
-
return
|
|
65
|
-
value !== null &&
|
|
66
|
-
'then' in value &&
|
|
67
|
-
typeof value.then === 'function';
|
|
135
|
+
function isPromiseInstance<T>(value: unknown): value is Promise<T> {
|
|
136
|
+
return value instanceof Promise;
|
|
68
137
|
}
|
|
69
138
|
|
|
70
139
|
export function resultOf<T>(fn: () => Promise<T>): Promise<Result<T, Error>>;
|
|
@@ -80,8 +149,8 @@ export function resultOf<T, E>(
|
|
|
80
149
|
): Result<T, E | Error> | Promise<Result<T, E | Error>> {
|
|
81
150
|
try {
|
|
82
151
|
const value = fn();
|
|
83
|
-
if (
|
|
84
|
-
return
|
|
152
|
+
if (isPromiseInstance<T>(value)) {
|
|
153
|
+
return value.then(
|
|
85
154
|
(resolved) => ok(resolved),
|
|
86
155
|
(error) => {
|
|
87
156
|
const normalized = normalizeThrown(error);
|
|
@@ -97,21 +166,21 @@ export function resultOf<T, E>(
|
|
|
97
166
|
}
|
|
98
167
|
|
|
99
168
|
function mapOption<A, B>(value: Option<A>, f: (value: A) => B): Option<B> {
|
|
100
|
-
return
|
|
169
|
+
return isSome(value) ? some(f(value.value)) : value;
|
|
101
170
|
}
|
|
102
171
|
|
|
103
172
|
function apOption<A, B>(
|
|
104
173
|
fn: Option<(value: A) => B>,
|
|
105
174
|
value: Option<A>,
|
|
106
175
|
): Option<B> {
|
|
107
|
-
if (!
|
|
176
|
+
if (!isSome(fn)) {
|
|
108
177
|
return fn;
|
|
109
178
|
}
|
|
110
|
-
return
|
|
179
|
+
return isSome(value) ? some(fn.value(value.value)) : value;
|
|
111
180
|
}
|
|
112
181
|
|
|
113
182
|
function flatMapOption<A, B>(value: Option<A>, f: (value: A) => Option<B>): Option<B> {
|
|
114
|
-
return
|
|
183
|
+
return isSome(value) ? f(value.value) : value;
|
|
115
184
|
}
|
|
116
185
|
|
|
117
186
|
const optionMonadImpl: Monad<OptionF> = {
|
|
@@ -29,7 +29,7 @@ export interface Monad<F extends TypeLambda> extends Applicative<F> {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export interface AsyncMonad<F extends TypeLambda> extends Monad<F> {
|
|
32
|
-
fromPromise<A>(promise:
|
|
32
|
+
fromPromise<A>(promise: Promise<A>): Kind<F, A>;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function runGenerator<F extends TypeLambda, T>(
|
|
@@ -53,7 +53,7 @@ export function monadGen<F extends TypeLambda, T>(
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
function bindValue<F extends TypeLambda>(_monad: Monad<F>) {
|
|
56
|
-
return function <A>(_effect: BoundEffect<F, A>, value: unknown): A {
|
|
56
|
+
return function bindRuntimeValue<A>(_effect: BoundEffect<F, A>, value: unknown): A {
|
|
57
57
|
return value as A;
|
|
58
58
|
};
|
|
59
59
|
}
|
|
@@ -61,7 +61,11 @@ function bindValue<F extends TypeLambda>(_monad: Monad<F>) {
|
|
|
61
61
|
export type DoBinder<M extends Monad<TypeLambda>> = Binder<MonadTypeLambda<M>>;
|
|
62
62
|
|
|
63
63
|
class DoBindSignal<F extends TypeLambda> {
|
|
64
|
-
|
|
64
|
+
readonly effect: Kind<F, unknown>;
|
|
65
|
+
|
|
66
|
+
constructor(effect: Kind<F, unknown>) {
|
|
67
|
+
this.effect = effect;
|
|
68
|
+
}
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
function executeDoBody<F extends TypeLambda, T>(
|
|
@@ -69,12 +73,12 @@ function executeDoBody<F extends TypeLambda, T>(
|
|
|
69
73
|
resolvedValues: readonly unknown[],
|
|
70
74
|
): { done: true; value: T } | { done: false; effect: Kind<F, unknown> } {
|
|
71
75
|
let index = 0;
|
|
72
|
-
|
|
76
|
+
function bind<A>(effect: BoundEffect<F, A>): A {
|
|
73
77
|
if (index < resolvedValues.length) {
|
|
74
78
|
return resolvedValues[index++] as A;
|
|
75
79
|
}
|
|
76
80
|
throw new DoBindSignal(effect);
|
|
77
|
-
}
|
|
81
|
+
}
|
|
78
82
|
|
|
79
83
|
try {
|
|
80
84
|
return { done: true, value: body(bind) };
|
|
@@ -87,16 +91,16 @@ function executeDoBody<F extends TypeLambda, T>(
|
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
async function executeAsyncDoBody<F extends TypeLambda, T>(
|
|
90
|
-
body: (bind: Binder<F>) => T |
|
|
94
|
+
body: (bind: Binder<F>) => T | Promise<T>,
|
|
91
95
|
resolvedValues: readonly unknown[],
|
|
92
96
|
): Promise<{ done: true; value: T } | { done: false; effect: Kind<F, unknown> }> {
|
|
93
97
|
let index = 0;
|
|
94
|
-
|
|
98
|
+
function bind<A>(effect: BoundEffect<F, A>): A {
|
|
95
99
|
if (index < resolvedValues.length) {
|
|
96
100
|
return resolvedValues[index++] as A;
|
|
97
101
|
}
|
|
98
102
|
throw new DoBindSignal(effect);
|
|
99
|
-
}
|
|
103
|
+
}
|
|
100
104
|
|
|
101
105
|
try {
|
|
102
106
|
return { done: true, value: await body(bind) };
|
|
@@ -122,7 +126,7 @@ function runDo<F extends TypeLambda, T>(
|
|
|
122
126
|
|
|
123
127
|
function runAsyncDo<F extends TypeLambda, T>(
|
|
124
128
|
monad: AsyncMonad<F>,
|
|
125
|
-
body: (bind: Binder<F>) => T |
|
|
129
|
+
body: (bind: Binder<F>) => T | Promise<T>,
|
|
126
130
|
resolvedValues: readonly unknown[] = [],
|
|
127
131
|
): Kind<F, T> {
|
|
128
132
|
return monad.flatMap(
|
|
@@ -142,7 +146,7 @@ export interface DoRuntime {
|
|
|
142
146
|
): Kind<F, T>;
|
|
143
147
|
<F extends TypeLambda, T>(
|
|
144
148
|
monad: AsyncMonad<F>,
|
|
145
|
-
body: (bind: Binder<F>) => T |
|
|
149
|
+
body: (bind: Binder<F>) => T | Promise<T>,
|
|
146
150
|
): Kind<F, T>;
|
|
147
151
|
readonly macroBind: <F extends TypeLambda>(
|
|
148
152
|
monad: Monad<F>,
|
|
@@ -151,16 +155,18 @@ export interface DoRuntime {
|
|
|
151
155
|
}
|
|
152
156
|
|
|
153
157
|
function createDoRuntime(): DoRuntime {
|
|
154
|
-
|
|
158
|
+
function runtime<F extends TypeLambda, T>(
|
|
155
159
|
monad: Monad<F>,
|
|
156
|
-
body: (bind: Binder<F>) => T |
|
|
157
|
-
): Kind<F, T>
|
|
160
|
+
body: (bind: Binder<F>) => T | Promise<T>,
|
|
161
|
+
): Kind<F, T> {
|
|
158
162
|
return 'fromPromise' in monad
|
|
159
163
|
? runAsyncDo(monad as AsyncMonad<F>, body, [])
|
|
160
164
|
: runDo(monad, body as (bind: Binder<F>) => T, []);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const doRuntime = runtime as DoRuntime;
|
|
168
|
+
Object.assign(doRuntime, { macroBind: bindValue, macroGen: monadGen });
|
|
169
|
+
return doRuntime;
|
|
164
170
|
}
|
|
165
171
|
|
|
166
172
|
// The compiler lowers `Do(...)` to `Do.macroGen(...)`, but keep a callable runtime bridge.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
type ValueFactoryArgs<TArgs extends readonly unknown[]> = TArgs;
|
|
2
|
+
|
|
3
|
+
const REFERENCE_IDS = new WeakMap<object, number>();
|
|
4
|
+
const SYMBOL_IDS = new Map<symbol, number>();
|
|
5
|
+
const VALUE_IDS = new WeakMap<object, number>();
|
|
6
|
+
|
|
7
|
+
let nextValueIdentity = 1;
|
|
8
|
+
|
|
9
|
+
function nextIdentityId(): number {
|
|
10
|
+
const id = nextValueIdentity;
|
|
11
|
+
nextValueIdentity += 1;
|
|
12
|
+
return id;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function normalizeNumberToken(value: number): string {
|
|
16
|
+
if (Number.isNaN(value)) {
|
|
17
|
+
return 'NaN';
|
|
18
|
+
}
|
|
19
|
+
if (value === 0) {
|
|
20
|
+
return '0';
|
|
21
|
+
}
|
|
22
|
+
return String(value);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function referenceIdentity(value: object): number {
|
|
26
|
+
const existing = REFERENCE_IDS.get(value);
|
|
27
|
+
if (existing !== undefined) {
|
|
28
|
+
return existing;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const created = nextIdentityId();
|
|
32
|
+
REFERENCE_IDS.set(value, created);
|
|
33
|
+
return created;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function symbolIdentity(value: symbol): number {
|
|
37
|
+
const existing = SYMBOL_IDS.get(value);
|
|
38
|
+
if (existing !== undefined) {
|
|
39
|
+
return existing;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const created = nextIdentityId();
|
|
43
|
+
SYMBOL_IDS.set(value, created);
|
|
44
|
+
return created;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function tryValueIdentity(value: object): number | undefined {
|
|
48
|
+
return VALUE_IDS.get(value);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function tokenFor(value: unknown, deep: boolean): string {
|
|
52
|
+
switch (typeof value) {
|
|
53
|
+
case 'undefined':
|
|
54
|
+
return 'undefined';
|
|
55
|
+
case 'boolean':
|
|
56
|
+
return value ? 'boolean:true' : 'boolean:false';
|
|
57
|
+
case 'number':
|
|
58
|
+
return `number:${normalizeNumberToken(value)}`;
|
|
59
|
+
case 'bigint':
|
|
60
|
+
return `bigint:${value.toString()}`;
|
|
61
|
+
case 'string':
|
|
62
|
+
return `string:${JSON.stringify(value)}`;
|
|
63
|
+
case 'symbol':
|
|
64
|
+
return `symbol:${symbolIdentity(value)}`;
|
|
65
|
+
case 'function':
|
|
66
|
+
return `ref:${referenceIdentity(value)}`;
|
|
67
|
+
case 'object':
|
|
68
|
+
if (value === null) {
|
|
69
|
+
return 'null';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
{
|
|
73
|
+
const identity = tryValueIdentity(value);
|
|
74
|
+
if (identity !== undefined) {
|
|
75
|
+
return `value:${identity}`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (deep) {
|
|
80
|
+
throw new TypeError('Deep value fields must be recursively deep-safe.');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return `ref:${referenceIdentity(value)}`;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function __valueShallowToken(value: unknown): string {
|
|
88
|
+
return tokenFor(value, false);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function __valueDeepToken(value: unknown): string {
|
|
92
|
+
return tokenFor(value, true);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function __valueKey(...tokens: readonly string[]): string {
|
|
96
|
+
return JSON.stringify(tokens);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function __valueReadonly(
|
|
100
|
+
target: object,
|
|
101
|
+
key: PropertyKey,
|
|
102
|
+
value: unknown,
|
|
103
|
+
): void {
|
|
104
|
+
Object.defineProperty(target, key, {
|
|
105
|
+
value,
|
|
106
|
+
enumerable: true,
|
|
107
|
+
writable: false,
|
|
108
|
+
configurable: false,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function __valueFactory<T extends object, TArgs extends readonly unknown[]>(
|
|
113
|
+
keyOf: (...args: ValueFactoryArgs<TArgs>) => string,
|
|
114
|
+
allocate: () => T,
|
|
115
|
+
init: (instance: T, ...args: ValueFactoryArgs<TArgs>) => void,
|
|
116
|
+
): (...args: ValueFactoryArgs<TArgs>) => T {
|
|
117
|
+
const cache = new Map<string, T>();
|
|
118
|
+
|
|
119
|
+
return (...args: ValueFactoryArgs<TArgs>): T => {
|
|
120
|
+
const key = keyOf(...args);
|
|
121
|
+
const existing = cache.get(key);
|
|
122
|
+
if (existing !== undefined) {
|
|
123
|
+
return existing;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const instance = allocate();
|
|
127
|
+
init(instance, ...args);
|
|
128
|
+
VALUE_IDS.set(instance, nextIdentityId());
|
|
129
|
+
Object.freeze(instance);
|
|
130
|
+
cache.set(key, instance);
|
|
131
|
+
return instance;
|
|
132
|
+
};
|
|
133
|
+
}
|
package/typeclasses.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export interface Monad<F extends TypeLambda> extends Applicative<F> {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export interface AsyncMonad<F extends TypeLambda> extends Monad<F> {
|
|
32
|
-
fromPromise<A>(promise:
|
|
32
|
+
fromPromise<A>(promise: Promise<A>): Kind<F, A>;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export function monadGen<F extends TypeLambda, T>(
|
|
@@ -46,7 +46,7 @@ export interface DoRuntime {
|
|
|
46
46
|
): Kind<F, T>;
|
|
47
47
|
<F extends TypeLambda, T>(
|
|
48
48
|
monad: AsyncMonad<F>,
|
|
49
|
-
body: (bind: Binder<F>) => T |
|
|
49
|
+
body: (bind: Binder<F>) => T | Promise<T>,
|
|
50
50
|
): Kind<F, T>;
|
|
51
51
|
readonly macroBind: <F extends TypeLambda>(
|
|
52
52
|
monad: Monad<F>,
|
package/typeclasses.js
CHANGED
|
@@ -9,7 +9,7 @@ export function monadGen(monad, factory) {
|
|
|
9
9
|
return runGenerator(monad, factory());
|
|
10
10
|
}
|
|
11
11
|
function bindValue(_monad) {
|
|
12
|
-
return function (_effect, value) {
|
|
12
|
+
return function bindRuntimeValue(_effect, value) {
|
|
13
13
|
return value;
|
|
14
14
|
};
|
|
15
15
|
}
|
|
@@ -20,12 +20,12 @@ class DoBindSignal {
|
|
|
20
20
|
}
|
|
21
21
|
function executeDoBody(body, resolvedValues) {
|
|
22
22
|
let index = 0;
|
|
23
|
-
|
|
23
|
+
function bind(effect) {
|
|
24
24
|
if (index < resolvedValues.length) {
|
|
25
25
|
return resolvedValues[index++];
|
|
26
26
|
}
|
|
27
27
|
throw new DoBindSignal(effect);
|
|
28
|
-
}
|
|
28
|
+
}
|
|
29
29
|
try {
|
|
30
30
|
return { done: true, value: body(bind) };
|
|
31
31
|
}
|
|
@@ -38,12 +38,12 @@ function executeDoBody(body, resolvedValues) {
|
|
|
38
38
|
}
|
|
39
39
|
async function executeAsyncDoBody(body, resolvedValues) {
|
|
40
40
|
let index = 0;
|
|
41
|
-
|
|
41
|
+
function bind(effect) {
|
|
42
42
|
if (index < resolvedValues.length) {
|
|
43
43
|
return resolvedValues[index++];
|
|
44
44
|
}
|
|
45
45
|
throw new DoBindSignal(effect);
|
|
46
|
-
}
|
|
46
|
+
}
|
|
47
47
|
try {
|
|
48
48
|
return { done: true, value: await body(bind) };
|
|
49
49
|
}
|
|
@@ -65,13 +65,14 @@ function runAsyncDo(monad, body, resolvedValues = []) {
|
|
|
65
65
|
return monad.flatMap(monad.fromPromise(executeAsyncDoBody(body, resolvedValues)), (step) => step.done ? monad.pure(step.value) : monad.flatMap(step.effect, (value) => runAsyncDo(monad, body, [...resolvedValues, value])));
|
|
66
66
|
}
|
|
67
67
|
function createDoRuntime() {
|
|
68
|
-
|
|
68
|
+
function runtime(monad, body) {
|
|
69
69
|
return 'fromPromise' in monad
|
|
70
70
|
? runAsyncDo(monad, body, [])
|
|
71
71
|
: runDo(monad, body, []);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
}
|
|
73
|
+
const doRuntime = runtime;
|
|
74
|
+
Object.assign(doRuntime, { macroBind: bindValue, macroGen: monadGen });
|
|
75
|
+
return doRuntime;
|
|
75
76
|
}
|
|
76
77
|
// The compiler lowers `Do(...)` to `Do.macroGen(...)`, but keep a callable runtime bridge.
|
|
77
78
|
export const Do = createDoRuntime();
|
package/typeclasses.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typeclasses.js","sourceRoot":"","sources":["./soundscript/typeclasses.sts"],"names":[],"mappings":"AAkCA,SAAS,YAAY,CACnB,KAAe,EACf,QAAiD,EACjD,KAAe;IAEf,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAc,CAAC,CAAC;IAC3C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,KAAe,EACf,OAAsD;IAEtD,OAAO,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,SAAS,CAAuB,MAAgB;IACvD,OAAO,
|
|
1
|
+
{"version":3,"file":"typeclasses.js","sourceRoot":"","sources":["./soundscript/typeclasses.sts"],"names":[],"mappings":"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","sourcesContent":["import type { Binder, BoundEffect, Kind, MonadTypeLambda, TypeLambda } from '@soundscript/soundscript/hkt';\n\nexport interface Contravariant<F extends TypeLambda> {\n readonly __type_lambda?: F;\n contramap<A, B>(value: Kind<F, A>, project: (value: B) => A): Kind<F, B>;\n}\n\nexport interface Invariant<F extends TypeLambda> {\n readonly __type_lambda?: F;\n imap<A, B>(\n value: Kind<F, A>,\n decodeMap: (value: A) => B,\n encodeMap: (value: B) => A,\n ): Kind<F, B>;\n}\n\nexport interface Functor<F extends TypeLambda> {\n readonly __type_lambda?: F;\n map<A, B>(value: Kind<F, A>, f: (value: A) => B): Kind<F, B>;\n}\n\nexport interface Applicative<F extends TypeLambda> extends Functor<F> {\n ap<A, B>(fn: Kind<F, (value: A) => B>, value: Kind<F, A>): Kind<F, B>;\n pure<A>(value: A): Kind<F, A>;\n}\n\nexport interface Monad<F extends TypeLambda> extends Applicative<F> {\n flatMap<A, B>(value: Kind<F, A>, f: (value: A) => Kind<F, B>): Kind<F, B>;\n}\n\nexport interface AsyncMonad<F extends TypeLambda> extends Monad<F> {\n fromPromise<A>(promise: Promise<A>): Kind<F, A>;\n}\n\nfunction runGenerator<F extends TypeLambda, T>(\n monad: Monad<F>,\n iterator: Generator<Kind<F, unknown>, T, unknown>,\n input?: unknown,\n): Kind<F, T> {\n const step = iterator.next(input as never);\n if (step.done) {\n return monad.pure(step.value);\n }\n\n return monad.flatMap(step.value, (nextInput) => runGenerator(monad, iterator, nextInput));\n}\n\nexport function monadGen<F extends TypeLambda, T>(\n monad: Monad<F>,\n factory: () => Generator<Kind<F, unknown>, T, unknown>,\n): Kind<F, T> {\n return runGenerator(monad, factory());\n}\n\nfunction bindValue<F extends TypeLambda>(_monad: Monad<F>) {\n return function bindRuntimeValue<A>(_effect: BoundEffect<F, A>, value: unknown): A {\n return value as A;\n };\n}\n\nexport type DoBinder<M extends Monad<TypeLambda>> = Binder<MonadTypeLambda<M>>;\n\nclass DoBindSignal<F extends TypeLambda> {\n readonly effect: Kind<F, unknown>;\n\n constructor(effect: Kind<F, unknown>) {\n this.effect = effect;\n }\n}\n\nfunction executeDoBody<F extends TypeLambda, T>(\n body: (bind: Binder<F>) => T,\n resolvedValues: readonly unknown[],\n): { done: true; value: T } | { done: false; effect: Kind<F, unknown> } {\n let index = 0;\n function bind<A>(effect: BoundEffect<F, A>): A {\n if (index < resolvedValues.length) {\n return resolvedValues[index++] as A;\n }\n throw new DoBindSignal(effect);\n }\n\n try {\n return { done: true, value: body(bind) };\n } catch (error) {\n if (error instanceof DoBindSignal) {\n return { done: false, effect: error.effect };\n }\n throw error;\n }\n}\n\nasync function executeAsyncDoBody<F extends TypeLambda, T>(\n body: (bind: Binder<F>) => T | Promise<T>,\n resolvedValues: readonly unknown[],\n): Promise<{ done: true; value: T } | { done: false; effect: Kind<F, unknown> }> {\n let index = 0;\n function bind<A>(effect: BoundEffect<F, A>): A {\n if (index < resolvedValues.length) {\n return resolvedValues[index++] as A;\n }\n throw new DoBindSignal(effect);\n }\n\n try {\n return { done: true, value: await body(bind) };\n } catch (error) {\n if (error instanceof DoBindSignal) {\n return { done: false, effect: error.effect };\n }\n throw error;\n }\n}\n\nfunction runDo<F extends TypeLambda, T>(\n monad: Monad<F>,\n body: (bind: Binder<F>) => T,\n resolvedValues: readonly unknown[] = [],\n): Kind<F, T> {\n const step = executeDoBody(body, resolvedValues);\n if (step.done) {\n return monad.pure(step.value);\n }\n return monad.flatMap(step.effect, (value) => runDo(monad, body, [...resolvedValues, value]));\n}\n\nfunction runAsyncDo<F extends TypeLambda, T>(\n monad: AsyncMonad<F>,\n body: (bind: Binder<F>) => T | Promise<T>,\n resolvedValues: readonly unknown[] = [],\n): Kind<F, T> {\n return monad.flatMap(\n monad.fromPromise(executeAsyncDoBody(body, resolvedValues)),\n (step) =>\n step.done ? monad.pure(step.value) : monad.flatMap(\n step.effect,\n (value) => runAsyncDo(monad, body, [...resolvedValues, value]),\n ),\n );\n}\n\nexport interface DoRuntime {\n <F extends TypeLambda, T>(\n monad: Monad<F>,\n body: (bind: Binder<F>) => T,\n ): Kind<F, T>;\n <F extends TypeLambda, T>(\n monad: AsyncMonad<F>,\n body: (bind: Binder<F>) => T | Promise<T>,\n ): Kind<F, T>;\n readonly macroBind: <F extends TypeLambda>(\n monad: Monad<F>,\n ) => <A>(effect: BoundEffect<F, A>, value: unknown) => A;\n readonly macroGen: typeof monadGen;\n}\n\nfunction createDoRuntime(): DoRuntime {\n function runtime<F extends TypeLambda, T>(\n monad: Monad<F>,\n body: (bind: Binder<F>) => T | Promise<T>,\n ): Kind<F, T> {\n return 'fromPromise' in monad\n ? runAsyncDo(monad as AsyncMonad<F>, body, [])\n : runDo(monad, body as (bind: Binder<F>) => T, []);\n }\n\n const doRuntime = runtime as DoRuntime;\n Object.assign(doRuntime, { macroBind: bindValue, macroGen: monadGen });\n return doRuntime;\n}\n\n// The compiler lowers `Do(...)` to `Do.macroGen(...)`, but keep a callable runtime bridge.\nexport const Do = createDoRuntime();\n"]}
|
package/value.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function __valueShallowToken(value: unknown): string;
|
|
2
|
+
export function __valueDeepToken(value: unknown): string;
|
|
3
|
+
export function __valueKey(...tokens: readonly string[]): string;
|
|
4
|
+
export function __valueReadonly(target: object, key: PropertyKey, value: unknown): void;
|
|
5
|
+
export function __valueFactory<T extends object, TArgs extends readonly unknown[]>(
|
|
6
|
+
keyOf: (...args: TArgs) => string,
|
|
7
|
+
allocate: () => T,
|
|
8
|
+
init: (instance: T, ...args: TArgs) => void,
|
|
9
|
+
): (...args: TArgs) => T;
|
package/value.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const REFERENCE_IDS = new WeakMap();
|
|
2
|
+
const SYMBOL_IDS = new Map();
|
|
3
|
+
const VALUE_IDS = new WeakMap();
|
|
4
|
+
let nextValueIdentity = 1;
|
|
5
|
+
function nextIdentityId() {
|
|
6
|
+
const id = nextValueIdentity;
|
|
7
|
+
nextValueIdentity += 1;
|
|
8
|
+
return id;
|
|
9
|
+
}
|
|
10
|
+
function normalizeNumberToken(value) {
|
|
11
|
+
if (Number.isNaN(value)) {
|
|
12
|
+
return 'NaN';
|
|
13
|
+
}
|
|
14
|
+
if (value === 0) {
|
|
15
|
+
return '0';
|
|
16
|
+
}
|
|
17
|
+
return String(value);
|
|
18
|
+
}
|
|
19
|
+
function referenceIdentity(value) {
|
|
20
|
+
const existing = REFERENCE_IDS.get(value);
|
|
21
|
+
if (existing !== undefined) {
|
|
22
|
+
return existing;
|
|
23
|
+
}
|
|
24
|
+
const created = nextIdentityId();
|
|
25
|
+
REFERENCE_IDS.set(value, created);
|
|
26
|
+
return created;
|
|
27
|
+
}
|
|
28
|
+
function symbolIdentity(value) {
|
|
29
|
+
const existing = SYMBOL_IDS.get(value);
|
|
30
|
+
if (existing !== undefined) {
|
|
31
|
+
return existing;
|
|
32
|
+
}
|
|
33
|
+
const created = nextIdentityId();
|
|
34
|
+
SYMBOL_IDS.set(value, created);
|
|
35
|
+
return created;
|
|
36
|
+
}
|
|
37
|
+
function tryValueIdentity(value) {
|
|
38
|
+
return VALUE_IDS.get(value);
|
|
39
|
+
}
|
|
40
|
+
function tokenFor(value, deep) {
|
|
41
|
+
switch (typeof value) {
|
|
42
|
+
case 'undefined':
|
|
43
|
+
return 'undefined';
|
|
44
|
+
case 'boolean':
|
|
45
|
+
return value ? 'boolean:true' : 'boolean:false';
|
|
46
|
+
case 'number':
|
|
47
|
+
return `number:${normalizeNumberToken(value)}`;
|
|
48
|
+
case 'bigint':
|
|
49
|
+
return `bigint:${value.toString()}`;
|
|
50
|
+
case 'string':
|
|
51
|
+
return `string:${JSON.stringify(value)}`;
|
|
52
|
+
case 'symbol':
|
|
53
|
+
return `symbol:${symbolIdentity(value)}`;
|
|
54
|
+
case 'function':
|
|
55
|
+
return `ref:${referenceIdentity(value)}`;
|
|
56
|
+
case 'object':
|
|
57
|
+
if (value === null) {
|
|
58
|
+
return 'null';
|
|
59
|
+
}
|
|
60
|
+
{
|
|
61
|
+
const identity = tryValueIdentity(value);
|
|
62
|
+
if (identity !== undefined) {
|
|
63
|
+
return `value:${identity}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (deep) {
|
|
67
|
+
throw new TypeError('Deep value fields must be recursively deep-safe.');
|
|
68
|
+
}
|
|
69
|
+
return `ref:${referenceIdentity(value)}`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export function __valueShallowToken(value) {
|
|
73
|
+
return tokenFor(value, false);
|
|
74
|
+
}
|
|
75
|
+
export function __valueDeepToken(value) {
|
|
76
|
+
return tokenFor(value, true);
|
|
77
|
+
}
|
|
78
|
+
export function __valueKey(...tokens) {
|
|
79
|
+
return JSON.stringify(tokens);
|
|
80
|
+
}
|
|
81
|
+
export function __valueReadonly(target, key, value) {
|
|
82
|
+
Object.defineProperty(target, key, {
|
|
83
|
+
value,
|
|
84
|
+
enumerable: true,
|
|
85
|
+
writable: false,
|
|
86
|
+
configurable: false,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export function __valueFactory(keyOf, allocate, init) {
|
|
90
|
+
const cache = new Map();
|
|
91
|
+
return (...args) => {
|
|
92
|
+
const key = keyOf(...args);
|
|
93
|
+
const existing = cache.get(key);
|
|
94
|
+
if (existing !== undefined) {
|
|
95
|
+
return existing;
|
|
96
|
+
}
|
|
97
|
+
const instance = allocate();
|
|
98
|
+
init(instance, ...args);
|
|
99
|
+
VALUE_IDS.set(instance, nextIdentityId());
|
|
100
|
+
Object.freeze(instance);
|
|
101
|
+
cache.set(key, instance);
|
|
102
|
+
return instance;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=value.js.map
|