Skip to content

Commit 0ce4e26

Browse files
add lazy list type
1 parent c2faa0c commit 0ce4e26

File tree

1 file changed

+81
-10
lines changed

1 file changed

+81
-10
lines changed

scriptum.js

+81-10
Original file line numberDiff line numberDiff line change
@@ -1055,7 +1055,7 @@ not all:
10551055
These represent major flaws, hence expressions in WHNF should be only used with
10561056
great caution. */
10571057

1058-
export const Lazy = (thunk, tag = "Thunk") => {
1058+
export const Lazy = ({tag, cons = tag}) => thunk => {
10591059
let state = {
10601060
thunk: thunk,
10611061
evaluated: false,
@@ -1071,11 +1071,9 @@ export const Lazy = (thunk, tag = "Thunk") => {
10711071
}
10721072

10731073
const forceEval = target => {
1074-
if (target.evaluating) {
1075-
throw new LazyError("cyclic lazy evaluation detected");
1076-
}
1074+
if (target.evaluating) throw new LazyError("cyclic lazy evaluation");
10771075

1078-
if (!target.evaluated) {
1076+
else if (!target.evaluated) {
10791077
try {
10801078
target.evaluating = true;
10811079
target.value = target.thunk();
@@ -1099,6 +1097,7 @@ export const Lazy = (thunk, tag = "Thunk") => {
10991097

11001098
if (prop === $) return tag;
11011099
else if (prop === $$) return tag;
1100+
else if (prop === Lazy.thunk) return true;
11021101

11031102
const value = target.state.evaluated
11041103
? target.state.value
@@ -1127,7 +1126,7 @@ export const Lazy = (thunk, tag = "Thunk") => {
11271126

11281127
if (prop === $) return true;
11291128
else if (prop === $$) return true;
1130-
else if (prop === Lazy.thunk) return true; // reveal proxy
1129+
else if (prop === Lazy.thunk) return true;
11311130

11321131
const value = target.state.evaluated
11331132
? target.state.value
@@ -1214,13 +1213,16 @@ export const Lazy = (thunk, tag = "Thunk") => {
12141213
};
12151214

12161215

1216+
export const lazy = Lazy("Thunk");
1217+
1218+
12171219
Lazy.thunk = Symbol("thunk");
12181220

12191221

1220-
Lazy.eager = x => {
1221-
if (Object(x) !== x) return x;
1222-
while (Lazy.thunk in x) x = x();
1223-
return x;
1222+
Lazy.eager = thunk => {
1223+
if (typeof thunk !== "function") return thunk;
1224+
while (thunk[Lazy.thunk]) thunk = thunk();
1225+
return thunk;
12241226
};
12251227

12261228

@@ -3857,6 +3859,75 @@ Iit.tails = function* (ix) {
38573859
};
38583860

38593861

3862+
/*█████████████████████████████████████████████████████████████████████████████
3863+
███████████████████████████████████████████████████████████████████████████████
3864+
████████████████████████████████████ LIST █████████████████████████████████████
3865+
███████████████████████████████████████████████████████████████████████████████
3866+
███████████████████████████████████████████████████████████████████████████████*/
3867+
3868+
3869+
/* Lazy list type specifically for cases where lots of consings are required.
3870+
List consing benefits from structural sharing in lists and thus doesn't rely on
3871+
mutations. Please note that the list type is stack-safe. While lists themselves
3872+
are lazily constructed, the eliminiation of lists happens within an imperative
3873+
loop. */
3874+
3875+
3876+
export const List = {};
3877+
3878+
3879+
List.Nil = scope(() => {
3880+
const empty = [];
3881+
empty[$] = "List";
3882+
empty[$$] = "List.Nil";
3883+
return Object.freeze(empty);
3884+
});
3885+
3886+
3887+
List.Cons = x => xs => {
3888+
const pair = [x, xs];
3889+
pair[$] = "List";
3890+
pair[$$] = "List.Cons";
3891+
return pair;
3892+
};
3893+
3894+
3895+
// unconsing is redundant due to pair structure
3896+
3897+
3898+
/*█████████████████████████████████████████████████████████████████████████████
3899+
█████████████████████████████████ COMBINATORS █████████████████████████████████
3900+
███████████████████████████████████████████████████████████████████████████████*/
3901+
3902+
3903+
List.map = f => function go(xs) {
3904+
if (xs === List.Nil) return xs;
3905+
else return List.Cons(f(xs[0])) (lazy(() => go(xs[1])));
3906+
};
3907+
3908+
3909+
// a real right associative but stack-safe fold!!!
3910+
3911+
List.foldr = f => acc => xs => {
3912+
while (true) {
3913+
const ys = Lazy.eager(xs);
3914+
if (ys === List.Nil) return acc;
3915+
else acc = f(ys[0]) (acc);
3916+
xs = ys[1];
3917+
}
3918+
};
3919+
3920+
3921+
List.forEach = f => xs => {
3922+
while (true) {
3923+
const ys = Lazy.eager(xs);
3924+
if (ys === List.Nil) break;
3925+
else f(ys[0]);
3926+
xs = ys[1];
3927+
}
3928+
};
3929+
3930+
38603931
/*█████████████████████████████████████████████████████████████████████████████
38613932
███████████████████████████████████████████████████████████████████████████████
38623933
█████████████████████████████████████ MAP █████████████████████████████████████

0 commit comments

Comments
 (0)