@soundscript/soundscript 0.1.0
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/LICENSE +15 -0
- package/README.md +10 -0
- package/async.d.ts +81 -0
- package/async.js +214 -0
- package/async.js.map +1 -0
- package/bin/soundscript.js +54 -0
- package/codec.d.ts +31 -0
- package/codec.js +31 -0
- package/codec.js.map +1 -0
- package/compare.d.ts +28 -0
- package/compare.js +121 -0
- package/compare.js.map +1 -0
- package/decode.d.ts +84 -0
- package/decode.js +249 -0
- package/decode.js.map +1 -0
- package/encode.d.ts +98 -0
- package/encode.js +128 -0
- package/encode.js.map +1 -0
- package/experimental/component.d.ts +40 -0
- package/experimental/component.js +46 -0
- package/experimental/component.js.map +1 -0
- package/experimental/css.d.ts +16 -0
- package/experimental/css.js +10 -0
- package/experimental/css.js.map +1 -0
- package/experimental/debug.d.ts +2 -0
- package/experimental/debug.js +10 -0
- package/experimental/debug.js.map +1 -0
- package/experimental/graphql.d.ts +16 -0
- package/experimental/graphql.js +10 -0
- package/experimental/graphql.js.map +1 -0
- package/experimental/sql.d.ts +22 -0
- package/experimental/sql.js +24 -0
- package/experimental/sql.js.map +1 -0
- package/failures.d.ts +23 -0
- package/failures.js +42 -0
- package/failures.js.map +1 -0
- package/hash.d.ts +34 -0
- package/hash.js +116 -0
- package/hash.js.map +1 -0
- package/hkt.d.ts +40 -0
- package/hkt.js +4 -0
- package/hkt.js.map +1 -0
- package/index.d.ts +9 -0
- package/index.js +16 -0
- package/index.js.map +1 -0
- package/json.d.ts +98 -0
- package/json.js +638 -0
- package/json.js.map +1 -0
- package/match.d.ts +11 -0
- package/match.js +14 -0
- package/match.js.map +1 -0
- package/package.json +153 -0
- package/result.d.ts +52 -0
- package/result.js +104 -0
- package/result.js.map +1 -0
- package/soundscript/async.sts +315 -0
- package/soundscript/codec.sts +75 -0
- package/soundscript/compare.sts +159 -0
- package/soundscript/decode.sts +382 -0
- package/soundscript/encode.sts +254 -0
- package/soundscript/experimental/component.sts +69 -0
- package/soundscript/experimental/css.sts +28 -0
- package/soundscript/experimental/debug.sts +10 -0
- package/soundscript/experimental/graphql.sts +28 -0
- package/soundscript/experimental/sql.sts +53 -0
- package/soundscript/failures.sts +64 -0
- package/soundscript/hash.sts +196 -0
- package/soundscript/hkt.sts +41 -0
- package/soundscript/index.sts +23 -0
- package/soundscript/json.sts +824 -0
- package/soundscript/match.sts +26 -0
- package/soundscript/result.sts +179 -0
- package/soundscript/thunk.sts +15 -0
- package/soundscript/typeclasses.sts +167 -0
- package/thunk.d.ts +2 -0
- package/thunk.js +10 -0
- package/thunk.js.map +1 -0
- package/typeclasses.d.ts +57 -0
- package/typeclasses.js +78 -0
- package/typeclasses.js.map +1 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type MatchArm<TValue = unknown, TResult = unknown> = (value: TValue) => TResult;
|
|
2
|
+
|
|
3
|
+
// `where(...)` is an ordinary helper value so TS/Deno consumers have a concrete implementation.
|
|
4
|
+
// In the supported Soundscript pipeline, `Match(...)` consumes and strips it during macro expansion.
|
|
5
|
+
export function where<TValue, TResult>(
|
|
6
|
+
arm: (value: TValue) => TResult,
|
|
7
|
+
predicate: (value: TValue) => unknown,
|
|
8
|
+
): (value: TValue) => TResult {
|
|
9
|
+
return (value) => {
|
|
10
|
+
if (!predicate(value)) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
'where(...) is intended for Match(...) guard arms and should be removed during Soundscript expansion.',
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
return arm(value);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function Match<TArm extends MatchArm<any, any>>(
|
|
20
|
+
_value: unknown,
|
|
21
|
+
_arms: readonly [TArm, ...TArm[]],
|
|
22
|
+
): ReturnType<TArm> {
|
|
23
|
+
throw new Error(
|
|
24
|
+
'Match(...) is a Soundscript macro and should be removed during Soundscript expansion.',
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { normalizeThrown } from '@soundscript/soundscript/failures';
|
|
2
|
+
import { type Bind, type Kind, type Kind2, type TypeLambda } from '@soundscript/soundscript/hkt';
|
|
3
|
+
import { type Applicative, type Functor, type Monad } from '@soundscript/soundscript/typeclasses';
|
|
4
|
+
|
|
5
|
+
// #[variance(T: out)]
|
|
6
|
+
export type Ok<T> = { readonly tag: 'ok'; readonly value: T };
|
|
7
|
+
// #[variance(E: out)]
|
|
8
|
+
export type Err<E> = { readonly tag: 'err'; readonly error: E };
|
|
9
|
+
|
|
10
|
+
// #[variance(T: out, E: out)]
|
|
11
|
+
export type Result<T, E> = Ok<T> | Err<E>;
|
|
12
|
+
// #[variance(T: out)]
|
|
13
|
+
export type Some<T> = Ok<T>;
|
|
14
|
+
export type None = Err<void>;
|
|
15
|
+
// #[variance(T: out)]
|
|
16
|
+
export type Option<T> = Result<T, void>;
|
|
17
|
+
|
|
18
|
+
export interface OptionF extends TypeLambda {
|
|
19
|
+
readonly type: Option<this['Args'][0]>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ResultF extends TypeLambda {
|
|
23
|
+
readonly type: Result<this['Args'][1], this['Args'][0]>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type OptionKind<T> = Kind<OptionF, T>;
|
|
27
|
+
export type ResultKind<E, T> = Kind2<ResultF, E, T>;
|
|
28
|
+
|
|
29
|
+
export function ok<T>(value: T): Result<T, never> {
|
|
30
|
+
return { tag: 'ok', value };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function err(): Result<never, void>;
|
|
34
|
+
export function err<E>(error: E): Result<never, E>;
|
|
35
|
+
export function err<E>(error?: E): Result<never, E | void> {
|
|
36
|
+
return { tag: 'err', error };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function some<T>(value: T): Option<T> {
|
|
40
|
+
return ok(value);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function none(): Option<never> {
|
|
44
|
+
return err();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isOk<T, E>(value: Result<T, E>): value is Ok<T> {
|
|
48
|
+
return value.tag === 'ok';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function isErr<T, E>(value: Result<T, E>): value is Err<E> {
|
|
52
|
+
return value.tag === 'err';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function isSome<T>(value: Option<T>): value is Some<T> {
|
|
56
|
+
return isOk(value);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function isNone<T>(value: Option<T>): value is None {
|
|
60
|
+
return isErr(value);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isPromiseLike(value: unknown): value is PromiseLike<unknown> {
|
|
64
|
+
return (typeof value === 'object' || typeof value === 'function') &&
|
|
65
|
+
value !== null &&
|
|
66
|
+
'then' in value &&
|
|
67
|
+
typeof value.then === 'function';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function resultOf<T>(fn: () => Promise<T>): Promise<Result<T, Error>>;
|
|
71
|
+
export function resultOf<T, E>(
|
|
72
|
+
fn: () => Promise<T>,
|
|
73
|
+
mapError: (error: Error) => E,
|
|
74
|
+
): Promise<Result<T, E>>;
|
|
75
|
+
export function resultOf<T>(fn: () => T): Result<T, Error>;
|
|
76
|
+
export function resultOf<T, E>(fn: () => T, mapError: (error: Error) => E): Result<T, E>;
|
|
77
|
+
export function resultOf<T, E>(
|
|
78
|
+
fn: () => T | Promise<T>,
|
|
79
|
+
mapError?: (error: Error) => E,
|
|
80
|
+
): Result<T, E | Error> | Promise<Result<T, E | Error>> {
|
|
81
|
+
try {
|
|
82
|
+
const value = fn();
|
|
83
|
+
if (isPromiseLike(value)) {
|
|
84
|
+
return Promise.resolve(value as PromiseLike<T>).then(
|
|
85
|
+
(resolved) => ok(resolved),
|
|
86
|
+
(error) => {
|
|
87
|
+
const normalized = normalizeThrown(error);
|
|
88
|
+
return err(mapError ? mapError(normalized) : normalized);
|
|
89
|
+
},
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return ok(value);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
const normalized = normalizeThrown(error);
|
|
95
|
+
return err(mapError ? mapError(normalized) : normalized);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function mapOption<A, B>(value: Option<A>, f: (value: A) => B): Option<B> {
|
|
100
|
+
return isOk(value) ? ok(f(value.value)) : value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function apOption<A, B>(
|
|
104
|
+
fn: Option<(value: A) => B>,
|
|
105
|
+
value: Option<A>,
|
|
106
|
+
): Option<B> {
|
|
107
|
+
if (!isOk(fn)) {
|
|
108
|
+
return fn;
|
|
109
|
+
}
|
|
110
|
+
return isOk(value) ? ok(fn.value(value.value)) : value;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function flatMapOption<A, B>(value: Option<A>, f: (value: A) => Option<B>): Option<B> {
|
|
114
|
+
return isOk(value) ? f(value.value) : value;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const optionMonadImpl: Monad<OptionF> = {
|
|
118
|
+
ap: apOption,
|
|
119
|
+
flatMap: flatMapOption,
|
|
120
|
+
map: mapOption,
|
|
121
|
+
pure: some,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const optionFunctor: Functor<OptionF> = optionMonadImpl;
|
|
125
|
+
export const optionApplicative: Applicative<OptionF> = optionMonadImpl;
|
|
126
|
+
export const optionMonad: Monad<OptionF> = optionMonadImpl;
|
|
127
|
+
|
|
128
|
+
function mapResult<E, A, B>(value: Result<A, E>, f: (value: A) => B): Result<B, E> {
|
|
129
|
+
return isOk(value) ? ok(f(value.value)) : value;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function apResult<E, A, B>(
|
|
133
|
+
fn: Result<(value: A) => B, E>,
|
|
134
|
+
value: Result<A, E>,
|
|
135
|
+
): Result<B, E> {
|
|
136
|
+
if (!isOk(fn)) {
|
|
137
|
+
return fn;
|
|
138
|
+
}
|
|
139
|
+
return isOk(value) ? ok(fn.value(value.value)) : value;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function flatMapResult<E, A, B>(
|
|
143
|
+
value: Result<A, E>,
|
|
144
|
+
f: (value: A) => Result<B, E>,
|
|
145
|
+
): Result<B, E> {
|
|
146
|
+
return isOk(value) ? f(value.value) : value;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function createResultMonad<E>(): Monad<Bind<ResultF, [E]>> {
|
|
150
|
+
return {
|
|
151
|
+
ap: apResult,
|
|
152
|
+
flatMap: flatMapResult,
|
|
153
|
+
map: mapResult,
|
|
154
|
+
pure: ok,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function resultFunctor<E>(): Functor<Bind<ResultF, [E]>> {
|
|
159
|
+
return createResultMonad<E>();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function resultApplicative<E>(): Applicative<Bind<ResultF, [E]>> {
|
|
163
|
+
return createResultMonad<E>();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function resultMonad<E>(): Monad<Bind<ResultF, [E]>> {
|
|
167
|
+
return createResultMonad<E>();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function macroRuntimeError(name: string): never {
|
|
171
|
+
throw new Error(
|
|
172
|
+
`${name}(...) is a Soundscript macro and should be removed during Soundscript expansion.`,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function Try<T, E>(value: Result<T, E>): T;
|
|
177
|
+
export function Try(_value: unknown): never {
|
|
178
|
+
return macroRuntimeError('Try');
|
|
179
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
function macroRuntimeError(name: string): never {
|
|
2
|
+
throw new Error(
|
|
3
|
+
`${name}(...) is a Soundscript macro and should be removed during Soundscript expansion.`,
|
|
4
|
+
);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function lazy<T>(_value: T): () => T;
|
|
8
|
+
export function lazy(_value: unknown): never {
|
|
9
|
+
return macroRuntimeError('lazy');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function memo<T>(_value: T): () => T;
|
|
13
|
+
export function memo(_value: unknown): never {
|
|
14
|
+
return macroRuntimeError('memo');
|
|
15
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type { Binder, BoundEffect, Kind, MonadTypeLambda, TypeLambda } from '@soundscript/soundscript/hkt';
|
|
2
|
+
|
|
3
|
+
export interface Contravariant<F extends TypeLambda> {
|
|
4
|
+
readonly __type_lambda?: F;
|
|
5
|
+
contramap<A, B>(value: Kind<F, A>, project: (value: B) => A): Kind<F, B>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Invariant<F extends TypeLambda> {
|
|
9
|
+
readonly __type_lambda?: F;
|
|
10
|
+
imap<A, B>(
|
|
11
|
+
value: Kind<F, A>,
|
|
12
|
+
decodeMap: (value: A) => B,
|
|
13
|
+
encodeMap: (value: B) => A,
|
|
14
|
+
): Kind<F, B>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface Functor<F extends TypeLambda> {
|
|
18
|
+
readonly __type_lambda?: F;
|
|
19
|
+
map<A, B>(value: Kind<F, A>, f: (value: A) => B): Kind<F, B>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface Applicative<F extends TypeLambda> extends Functor<F> {
|
|
23
|
+
ap<A, B>(fn: Kind<F, (value: A) => B>, value: Kind<F, A>): Kind<F, B>;
|
|
24
|
+
pure<A>(value: A): Kind<F, A>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface Monad<F extends TypeLambda> extends Applicative<F> {
|
|
28
|
+
flatMap<A, B>(value: Kind<F, A>, f: (value: A) => Kind<F, B>): Kind<F, B>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface AsyncMonad<F extends TypeLambda> extends Monad<F> {
|
|
32
|
+
fromPromise<A>(promise: PromiseLike<A>): Kind<F, A>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function runGenerator<F extends TypeLambda, T>(
|
|
36
|
+
monad: Monad<F>,
|
|
37
|
+
iterator: Generator<Kind<F, unknown>, T, unknown>,
|
|
38
|
+
input?: unknown,
|
|
39
|
+
): Kind<F, T> {
|
|
40
|
+
const step = iterator.next(input as never);
|
|
41
|
+
if (step.done) {
|
|
42
|
+
return monad.pure(step.value);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return monad.flatMap(step.value, (nextInput) => runGenerator(monad, iterator, nextInput));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function monadGen<F extends TypeLambda, T>(
|
|
49
|
+
monad: Monad<F>,
|
|
50
|
+
factory: () => Generator<Kind<F, unknown>, T, unknown>,
|
|
51
|
+
): Kind<F, T> {
|
|
52
|
+
return runGenerator(monad, factory());
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function bindValue<F extends TypeLambda>(_monad: Monad<F>) {
|
|
56
|
+
return function <A>(_effect: BoundEffect<F, A>, value: unknown): A {
|
|
57
|
+
return value as A;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type DoBinder<M extends Monad<TypeLambda>> = Binder<MonadTypeLambda<M>>;
|
|
62
|
+
|
|
63
|
+
class DoBindSignal<F extends TypeLambda> {
|
|
64
|
+
constructor(readonly effect: Kind<F, unknown>) {}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function executeDoBody<F extends TypeLambda, T>(
|
|
68
|
+
body: (bind: Binder<F>) => T,
|
|
69
|
+
resolvedValues: readonly unknown[],
|
|
70
|
+
): { done: true; value: T } | { done: false; effect: Kind<F, unknown> } {
|
|
71
|
+
let index = 0;
|
|
72
|
+
const bind: Binder<F> = <A>(effect: BoundEffect<F, A>): A => {
|
|
73
|
+
if (index < resolvedValues.length) {
|
|
74
|
+
return resolvedValues[index++] as A;
|
|
75
|
+
}
|
|
76
|
+
throw new DoBindSignal(effect);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
return { done: true, value: body(bind) };
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (error instanceof DoBindSignal) {
|
|
83
|
+
return { done: false, effect: error.effect };
|
|
84
|
+
}
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function executeAsyncDoBody<F extends TypeLambda, T>(
|
|
90
|
+
body: (bind: Binder<F>) => T | PromiseLike<T>,
|
|
91
|
+
resolvedValues: readonly unknown[],
|
|
92
|
+
): Promise<{ done: true; value: T } | { done: false; effect: Kind<F, unknown> }> {
|
|
93
|
+
let index = 0;
|
|
94
|
+
const bind: Binder<F> = <A>(effect: BoundEffect<F, A>): A => {
|
|
95
|
+
if (index < resolvedValues.length) {
|
|
96
|
+
return resolvedValues[index++] as A;
|
|
97
|
+
}
|
|
98
|
+
throw new DoBindSignal(effect);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
return { done: true, value: await body(bind) };
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (error instanceof DoBindSignal) {
|
|
105
|
+
return { done: false, effect: error.effect };
|
|
106
|
+
}
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function runDo<F extends TypeLambda, T>(
|
|
112
|
+
monad: Monad<F>,
|
|
113
|
+
body: (bind: Binder<F>) => T,
|
|
114
|
+
resolvedValues: readonly unknown[] = [],
|
|
115
|
+
): Kind<F, T> {
|
|
116
|
+
const step = executeDoBody(body, resolvedValues);
|
|
117
|
+
if (step.done) {
|
|
118
|
+
return monad.pure(step.value);
|
|
119
|
+
}
|
|
120
|
+
return monad.flatMap(step.effect, (value) => runDo(monad, body, [...resolvedValues, value]));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function runAsyncDo<F extends TypeLambda, T>(
|
|
124
|
+
monad: AsyncMonad<F>,
|
|
125
|
+
body: (bind: Binder<F>) => T | PromiseLike<T>,
|
|
126
|
+
resolvedValues: readonly unknown[] = [],
|
|
127
|
+
): Kind<F, T> {
|
|
128
|
+
return monad.flatMap(
|
|
129
|
+
monad.fromPromise(executeAsyncDoBody(body, resolvedValues)),
|
|
130
|
+
(step) =>
|
|
131
|
+
step.done ? monad.pure(step.value) : monad.flatMap(
|
|
132
|
+
step.effect,
|
|
133
|
+
(value) => runAsyncDo(monad, body, [...resolvedValues, value]),
|
|
134
|
+
),
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface DoRuntime {
|
|
139
|
+
<F extends TypeLambda, T>(
|
|
140
|
+
monad: Monad<F>,
|
|
141
|
+
body: (bind: Binder<F>) => T,
|
|
142
|
+
): Kind<F, T>;
|
|
143
|
+
<F extends TypeLambda, T>(
|
|
144
|
+
monad: AsyncMonad<F>,
|
|
145
|
+
body: (bind: Binder<F>) => T | PromiseLike<T>,
|
|
146
|
+
): Kind<F, T>;
|
|
147
|
+
readonly macroBind: <F extends TypeLambda>(
|
|
148
|
+
monad: Monad<F>,
|
|
149
|
+
) => <A>(effect: BoundEffect<F, A>, value: unknown) => A;
|
|
150
|
+
readonly macroGen: typeof monadGen;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function createDoRuntime(): DoRuntime {
|
|
154
|
+
const runtime = (<F extends TypeLambda, T>(
|
|
155
|
+
monad: Monad<F>,
|
|
156
|
+
body: (bind: Binder<F>) => T | PromiseLike<T>,
|
|
157
|
+
): Kind<F, T> => {
|
|
158
|
+
return 'fromPromise' in monad
|
|
159
|
+
? runAsyncDo(monad as AsyncMonad<F>, body, [])
|
|
160
|
+
: runDo(monad, body as (bind: Binder<F>) => T, []);
|
|
161
|
+
}) as DoRuntime;
|
|
162
|
+
Object.assign(runtime, { macroBind: bindValue, macroGen: monadGen });
|
|
163
|
+
return runtime;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// The compiler lowers `Do(...)` to `Do.macroGen(...)`, but keep a callable runtime bridge.
|
|
167
|
+
export const Do = createDoRuntime();
|
package/thunk.d.ts
ADDED
package/thunk.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
function macroRuntimeError(name) {
|
|
2
|
+
throw new Error(`${name}(...) is a Soundscript macro and should be removed during Soundscript expansion.`);
|
|
3
|
+
}
|
|
4
|
+
export function lazy(_value) {
|
|
5
|
+
return macroRuntimeError('lazy');
|
|
6
|
+
}
|
|
7
|
+
export function memo(_value) {
|
|
8
|
+
return macroRuntimeError('memo');
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=thunk.js.map
|
package/thunk.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thunk.js","sourceRoot":"","sources":["./soundscript/thunk.sts"],"names":[],"mappings":"AAAA,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,kFAAkF,CAC1F,CAAC;AACJ,CAAC;AAGD,MAAM,UAAU,IAAI,CAAC,MAAe;IAClC,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC;AAGD,MAAM,UAAU,IAAI,CAAC,MAAe;IAClC,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC","sourcesContent":["function macroRuntimeError(name: string): never {\n throw new Error(\n `${name}(...) is a Soundscript macro and should be removed during Soundscript expansion.`,\n );\n}\n\nexport function lazy<T>(_value: T): () => T;\nexport function lazy(_value: unknown): never {\n return macroRuntimeError('lazy');\n}\n\nexport function memo<T>(_value: T): () => T;\nexport function memo(_value: unknown): never {\n return macroRuntimeError('memo');\n}\n"]}
|
package/typeclasses.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Binder, BoundEffect, Kind, MonadTypeLambda, TypeLambda } from '@soundscript/soundscript/hkt';
|
|
2
|
+
|
|
3
|
+
export interface Contravariant<F extends TypeLambda> {
|
|
4
|
+
readonly __type_lambda?: F;
|
|
5
|
+
contramap<A, B>(value: Kind<F, A>, project: (value: B) => A): Kind<F, B>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Invariant<F extends TypeLambda> {
|
|
9
|
+
readonly __type_lambda?: F;
|
|
10
|
+
imap<A, B>(
|
|
11
|
+
value: Kind<F, A>,
|
|
12
|
+
decodeMap: (value: A) => B,
|
|
13
|
+
encodeMap: (value: B) => A,
|
|
14
|
+
): Kind<F, B>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface Functor<F extends TypeLambda> {
|
|
18
|
+
readonly __type_lambda?: F;
|
|
19
|
+
map<A, B>(value: Kind<F, A>, f: (value: A) => B): Kind<F, B>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface Applicative<F extends TypeLambda> extends Functor<F> {
|
|
23
|
+
ap<A, B>(fn: Kind<F, (value: A) => B>, value: Kind<F, A>): Kind<F, B>;
|
|
24
|
+
pure<A>(value: A): Kind<F, A>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface Monad<F extends TypeLambda> extends Applicative<F> {
|
|
28
|
+
flatMap<A, B>(value: Kind<F, A>, f: (value: A) => Kind<F, B>): Kind<F, B>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface AsyncMonad<F extends TypeLambda> extends Monad<F> {
|
|
32
|
+
fromPromise<A>(promise: PromiseLike<A>): Kind<F, A>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function monadGen<F extends TypeLambda, T>(
|
|
36
|
+
monad: Monad<F>,
|
|
37
|
+
factory: () => Generator<Kind<F, unknown>, T, unknown>,
|
|
38
|
+
): Kind<F, T>;
|
|
39
|
+
|
|
40
|
+
export type DoBinder<M extends Monad<TypeLambda>> = Binder<MonadTypeLambda<M>>;
|
|
41
|
+
|
|
42
|
+
export interface DoRuntime {
|
|
43
|
+
<F extends TypeLambda, T>(
|
|
44
|
+
monad: Monad<F>,
|
|
45
|
+
body: (bind: Binder<F>) => T,
|
|
46
|
+
): Kind<F, T>;
|
|
47
|
+
<F extends TypeLambda, T>(
|
|
48
|
+
monad: AsyncMonad<F>,
|
|
49
|
+
body: (bind: Binder<F>) => T | PromiseLike<T>,
|
|
50
|
+
): Kind<F, T>;
|
|
51
|
+
readonly macroBind: <F extends TypeLambda>(
|
|
52
|
+
monad: Monad<F>,
|
|
53
|
+
) => <A>(effect: BoundEffect<F, A>, value: unknown) => A;
|
|
54
|
+
readonly macroGen: typeof monadGen;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const Do: DoRuntime;
|
package/typeclasses.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
function runGenerator(monad, iterator, input) {
|
|
2
|
+
const step = iterator.next(input);
|
|
3
|
+
if (step.done) {
|
|
4
|
+
return monad.pure(step.value);
|
|
5
|
+
}
|
|
6
|
+
return monad.flatMap(step.value, (nextInput) => runGenerator(monad, iterator, nextInput));
|
|
7
|
+
}
|
|
8
|
+
export function monadGen(monad, factory) {
|
|
9
|
+
return runGenerator(monad, factory());
|
|
10
|
+
}
|
|
11
|
+
function bindValue(_monad) {
|
|
12
|
+
return function (_effect, value) {
|
|
13
|
+
return value;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
class DoBindSignal {
|
|
17
|
+
constructor(effect) {
|
|
18
|
+
this.effect = effect;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function executeDoBody(body, resolvedValues) {
|
|
22
|
+
let index = 0;
|
|
23
|
+
const bind = (effect) => {
|
|
24
|
+
if (index < resolvedValues.length) {
|
|
25
|
+
return resolvedValues[index++];
|
|
26
|
+
}
|
|
27
|
+
throw new DoBindSignal(effect);
|
|
28
|
+
};
|
|
29
|
+
try {
|
|
30
|
+
return { done: true, value: body(bind) };
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error instanceof DoBindSignal) {
|
|
34
|
+
return { done: false, effect: error.effect };
|
|
35
|
+
}
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function executeAsyncDoBody(body, resolvedValues) {
|
|
40
|
+
let index = 0;
|
|
41
|
+
const bind = (effect) => {
|
|
42
|
+
if (index < resolvedValues.length) {
|
|
43
|
+
return resolvedValues[index++];
|
|
44
|
+
}
|
|
45
|
+
throw new DoBindSignal(effect);
|
|
46
|
+
};
|
|
47
|
+
try {
|
|
48
|
+
return { done: true, value: await body(bind) };
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (error instanceof DoBindSignal) {
|
|
52
|
+
return { done: false, effect: error.effect };
|
|
53
|
+
}
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function runDo(monad, body, resolvedValues = []) {
|
|
58
|
+
const step = executeDoBody(body, resolvedValues);
|
|
59
|
+
if (step.done) {
|
|
60
|
+
return monad.pure(step.value);
|
|
61
|
+
}
|
|
62
|
+
return monad.flatMap(step.effect, (value) => runDo(monad, body, [...resolvedValues, value]));
|
|
63
|
+
}
|
|
64
|
+
function runAsyncDo(monad, body, resolvedValues = []) {
|
|
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
|
+
}
|
|
67
|
+
function createDoRuntime() {
|
|
68
|
+
const runtime = ((monad, body) => {
|
|
69
|
+
return 'fromPromise' in monad
|
|
70
|
+
? runAsyncDo(monad, body, [])
|
|
71
|
+
: runDo(monad, body, []);
|
|
72
|
+
});
|
|
73
|
+
Object.assign(runtime, { macroBind: bindValue, macroGen: monadGen });
|
|
74
|
+
return runtime;
|
|
75
|
+
}
|
|
76
|
+
// The compiler lowers `Do(...)` to `Do.macroGen(...)`, but keep a callable runtime bridge.
|
|
77
|
+
export const Do = createDoRuntime();
|
|
78
|
+
//# sourceMappingURL=typeclasses.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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: PromiseLike<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 <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 constructor(readonly effect: Kind<F, unknown>) {}\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 const bind: Binder<F> = <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 | PromiseLike<T>,\n resolvedValues: readonly unknown[],\n): Promise<{ done: true; value: T } | { done: false; effect: Kind<F, unknown> }> {\n let index = 0;\n const bind: Binder<F> = <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 | PromiseLike<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 | PromiseLike<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 const runtime = (<F extends TypeLambda, T>(\n monad: Monad<F>,\n body: (bind: Binder<F>) => T | PromiseLike<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 }) as DoRuntime;\n Object.assign(runtime, { macroBind: bindValue, macroGen: monadGen });\n return runtime;\n}\n\n// The compiler lowers `Do(...)` to `Do.macroGen(...)`, but keep a callable runtime bridge.\nexport const Do = createDoRuntime();\n"]}
|