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