UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

243 lines (221 loc) 7.68 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.streamPrelude = void 0; exports.streamPrelude = ` // Supporting streams in the Scheme style, following // "stream discipline" // stream_tail returns the second component of the given pair // throws an error if the argument is not a pair function stream_tail(xs) { if (is_pair(xs)) { const the_tail = tail(xs); if (is_function(the_tail)) { return the_tail(); } else { error(the_tail, 'stream_tail(xs) expects a function as ' + 'the tail of the argument pair xs, ' + 'but encountered '); } } else { error(xs, 'stream_tail(xs) expects a pair as ' + 'argument xs, but encountered '); } } // is_stream recurses down the stream and checks that it ends with the // empty list null function is_stream(xs) { return is_null(xs) || (is_pair(xs) && is_function(tail(xs)) && arity(tail(xs)) === 0 && is_stream(stream_tail(xs))); } // A stream is either null or a pair whose tail is // a nullary function that returns a stream. function list_to_stream(xs) { return is_null(xs) ? null : pair(head(xs), () => list_to_stream(tail(xs))); } // stream_to_list transforms a given stream to a list // Lazy? No: stream_to_list needs to force the whole stream function stream_to_list(xs) { return is_null(xs) ? null : pair(head(xs), stream_to_list(stream_tail(xs))); } // stream_length returns the length of a given argument stream // throws an exception if the argument is not a stream // Lazy? No: The function needs to explore the whole stream function stream_length(xs) { return is_null(xs) ? 0 : 1 + stream_length(stream_tail(xs)); } // stream_map applies first arg f to the elements of the second // argument, assumed to be a stream. // f is applied element-by-element: // stream_map(f,list_to_stream(list(1,2)) results in // the same as list_to_stream(list(f(1),f(2))) // stream_map throws an exception if the second argument is not a // stream, and if the second argument is a nonempty stream and the // first argument is not a function. // Lazy? Yes: The argument stream is only explored as forced by // the result stream. function stream_map(f, s) { return is_null(s) ? null : pair(f(head(s)), () => stream_map(f, stream_tail(s))); } // build_stream takes a function fun as first argument, // and a nonnegative integer n as second argument, // build_stream returns a stream of n elements, that results from // applying fun to the numbers from 0 to n-1. // Lazy? Yes: The result stream forces the applications of fun // for the next element function build_stream(fun, n) { function build(i) { return i >= n ? null : pair(fun(i), () => build(i + 1)); } return build(0); } // stream_for_each applies first arg fun to the elements of the stream // passed as second argument. fun is applied element-by-element: // for_each(fun,list_to_stream(list(1, 2,null))) results in the calls fun(1) // and fun(2). // stream_for_each returns true. // stream_for_each throws an exception if the second argument is not a // stream, and if the second argument is a nonempty stream and the // first argument is not a function. // Lazy? No: stream_for_each forces the exploration of the entire stream function stream_for_each(fun, xs) { if (is_null(xs)) { return true; } else { fun(head(xs)); return stream_for_each(fun, stream_tail(xs)); } } // stream_reverse reverses the argument stream // stream_reverse throws an exception if the argument is not a stream. // Lazy? No: stream_reverse forces the exploration of the entire stream function stream_reverse(xs) { function rev(original, reversed) { return is_null(original) ? reversed : rev(stream_tail(original), pair(head(original), () => reversed)); } return rev(xs, null); } // stream_append appends first argument stream and second argument stream. // In the result, null at the end of the first argument stream // is replaced by the second argument stream // stream_append throws an exception if the first argument is not a // stream. // Lazy? Yes: the result stream forces the actual append operation function stream_append(xs, ys) { return is_null(xs) ? ys : pair(head(xs), () => stream_append(stream_tail(xs), ys)); } // stream_member looks for a given first-argument element in a given // second argument stream. It returns the first postfix substream // that starts with the given element. It returns null if the // element does not occur in the stream // Lazy? Sort-of: stream_member forces the stream only until the element is found. function stream_member(x, s) { return is_null(s) ? null : head(s) === x ? s : stream_member(x, stream_tail(s)); } // stream_remove removes the first occurrence of a given first-argument element // in a given second-argument list. Returns the original list // if there is no occurrence. // Lazy? Yes: the result stream forces the construction of each next element function stream_remove(v, xs) { return is_null(xs) ? null : v === head(xs) ? stream_tail(xs) : pair(head(xs), () => stream_remove(v, stream_tail(xs))); } // stream_remove_all removes all instances of v instead of just the first. // Lazy? Yes: the result stream forces the construction of each next element function stream_remove_all(v, xs) { return is_null(xs) ? null : v === head(xs) ? stream_remove_all(v, stream_tail(xs)) : pair(head(xs), () => stream_remove_all(v, stream_tail(xs))); } // filter returns the substream of elements of given stream s // for which the given predicate function p returns true. // Lazy? Yes: The result stream forces the construction of // each next element. Of course, the construction // of the next element needs to go down the stream // until an element is found for which p holds. function stream_filter(p, s) { return is_null(s) ? null : p(head(s)) ? pair(head(s), () => stream_filter(p, stream_tail(s))) : stream_filter(p, stream_tail(s)); } // enumerates numbers starting from start, // using a step size of 1, until the number // exceeds end. // Lazy? Yes: The result stream forces the construction of // each next element function enum_stream(start, end) { return start > end ? null : pair(start, () => enum_stream(start + 1, end)); } // integers_from constructs an infinite stream of integers // starting at a given number n // Lazy? Yes: The result stream forces the construction of // each next element function integers_from(n) { return pair(n, () => integers_from(n + 1)); } // eval_stream constructs the list of the first n elements // of a given stream s // Lazy? Sort-of: eval_stream only forces the computation of // the first n elements, and leaves the rest of // the stream untouched. function eval_stream(s, n) { function es(s, n) { return n === 1 ? list(head(s)) : pair(head(s), es(stream_tail(s), n - 1)); } return n === 0 ? null : es(s, n); } // Returns the item in stream s at index n (the first item is at position 0) // Lazy? Sort-of: stream_ref only forces the computation of // the first n elements, and leaves the rest of // the stream untouched. function stream_ref(s, n) { return n === 0 ? head(s) : stream_ref(stream_tail(s), n - 1); } `; //# sourceMappingURL=stream.prelude.js.map