js-slang
Version:
Javascript-based implementations of Source, written in Typescript
242 lines (202 loc) • 6.77 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.listPrelude = void 0;
exports.listPrelude = `
// equal computes the structural equality
// over its arguments
function equal(xs, ys) {
return is_pair(xs)
? (is_pair(ys) &&
equal(head(xs), head(ys)) &&
equal(tail(xs), tail(ys)))
: is_null(xs)
? is_null(ys)
: is_number(xs)
? (is_number(ys) && xs === ys)
: is_boolean(xs)
? (is_boolean(ys) && ((xs && ys) || (!xs && !ys)))
: is_string(xs)
? (is_string(ys) && xs === ys)
: is_undefined(xs)
? is_undefined(ys)
: is_function(xs)
// we know now that xs is a function,
// but we use an if check anyway to make use of the type predicate
? (is_function(ys) && xs === ys)
: false;
}
// returns the length of a given argument list
// assumes that the argument is a list
function $length(xs, acc) {
return is_null(xs) ? acc : $length(tail(xs), acc + 1);
}
function length(xs) {
return $length(xs, 0);
}
// map applies first arg f, assumed to be a unary function,
// to the elements of the second argument, assumed to be a list.
// f is applied element-by-element:
// map(f, list(1, 2)) results in list(f(1), f(2))
function $map(f, xs, acc) {
return is_null(xs)
? reverse(acc)
: $map(f, tail(xs), pair(f(head(xs)), acc));
}
function map(f, xs) {
return $map(f, xs, null);
}
// build_list takes a a function fun as first argument,
// and a nonnegative integer n as second argument,
// build_list returns a list of n elements, that results from
// applying fun to the numbers from 0 to n-1.
function $build_list(i, fun, already_built) {
return i < 0 ? already_built : $build_list(i - 1, fun, pair(fun(i), already_built));
}
function build_list(fun, n) {
return $build_list(n - 1, fun, null);
}
// for_each applies first arg fun, assumed to be a unary function,
// to the elements of the second argument, assumed to be a list.
// fun is applied element-by-element:
// for_each(fun, list(1, 2)) results in the calls fun(1) and fun(2).
// for_each returns true.
function for_each(fun, xs) {
if (is_null(xs)) {
return true;
} else {
fun(head(xs));
return for_each(fun, tail(xs));
}
}
// list_to_string returns a string that represents the argument list.
// It applies itself recursively on the elements of the given list.
// When it encounters a non-list, it applies to_string to it.
function $list_to_string(xs, cont) {
return is_null(xs)
? cont("null")
: is_pair(xs)
? $list_to_string(
head(xs),
x => $list_to_string(
tail(xs),
y => cont("[" + x + "," + y + "]")))
: cont(stringify(xs));
}
function list_to_string(xs) {
return $list_to_string(xs, x => x);
}
// reverse reverses the argument, assumed to be a list
function $reverse(original, reversed) {
return is_null(original)
? reversed
: $reverse(tail(original), pair(head(original), reversed));
}
function reverse(xs) {
return $reverse(xs, null);
}
// append first argument, assumed to be a list, to the second argument.
// In the result null at the end of the first argument list
// is replaced by the second argument, regardless what the second
// argument consists of.
function $append(xs, ys, cont) {
return is_null(xs)
? cont(ys)
: $append(tail(xs), ys, zs => cont(pair(head(xs), zs)));
}
function append(xs, ys) {
return $append(xs, ys, xs => xs);
}
// member looks for a given first-argument element in the
// second argument, assumed to be a list. It returns the first
// postfix sublist that starts with the given element. It returns null if the
// element does not occur in the list
function member(v, xs) {
return is_null(xs)
? null
: v === head(xs)
? xs
: member(v, tail(xs));
}
// removes the first occurrence of a given first-argument element
// in second-argument, assmed to be a list. Returns the original
// list if there is no occurrence.
function $remove(v, xs, acc) {
// Ensure that typechecking of append and reverse are done independently
const app = append;
const rev = reverse;
return is_null(xs)
? app(rev(acc), xs)
: v === head(xs)
? app(rev(acc), tail(xs))
: $remove(v, tail(xs), pair(head(xs), acc));
}
function remove(v, xs) {
return $remove(v, xs, null);
}
// Similar to remove, but removes all instances of v
// instead of just the first
function $remove_all(v, xs, acc) {
// Ensure that typechecking of append and reverse are done independently
const app = append;
const rev = reverse;
return is_null(xs)
? app(rev(acc), xs)
: v === head(xs)
? $remove_all(v, tail(xs), acc)
: $remove_all(v, tail(xs), pair(head(xs), acc));
}
function remove_all(v, xs) {
return $remove_all(v, xs, null);
}
// filter returns the sublist of elements of the second argument
// (assumed to be a list), for which the given predicate function
// returns true.
function $filter(pred, xs, acc) {
return is_null(xs)
? reverse(acc)
: pred(head(xs))
? $filter(pred, tail(xs), pair(head(xs), acc))
: $filter(pred, tail(xs), acc);
}
function filter(pred, xs) {
return $filter(pred, xs, null);
}
// enumerates numbers starting from start, assumed to be a number,
// using a step size of 1, until the number exceeds end, assumed
// to be a number
function $enum_list(start, end, acc) {
// Ensure that typechecking of reverse are done independently
const rev = reverse;
return start > end
? rev(acc)
: $enum_list(start + 1, end, pair(start, acc));
}
function enum_list(start, end) {
return $enum_list(start, end, null);
}
// Returns the item in xs (assumed to be a list) at index n,
// assumed to be a nonnegative integer.
// Note: the first item is at position 0
function list_ref(xs, n) {
return n === 0
? head(xs)
: list_ref(tail(xs), n - 1);
}
// accumulate applies an operation op (assumed to be a binary function)
// to elements of sequence (assumed to be a list) in a right-to-left order.
// first apply op to the last element and initial, resulting in r1, then to
// the second-last element and r1, resulting in r2, etc, and finally
// to the first element and r_n-1, where n is the length of the
// list.
// accumulate(op, zero, list(1, 2, 3)) results in
// op(1, op(2, op(3, zero)))
function $accumulate(f, initial, xs, cont) {
return is_null(xs)
? cont(initial)
: $accumulate(f, initial, tail(xs), x => cont(f(head(xs), x)));
}
function accumulate(f, initial, xs) {
return $accumulate(f, initial, xs, x => x);
}
`;
//# sourceMappingURL=list.prelude.js.map