// Joins a list into a string with an optional provided separator. // The string will be in the result field of the generated tuple // from the module. let str_join = module{ // The default separator is a single space. You can override // this when you call the module if desired. sep=" ", // The list is a required parameter. list=NULL, } => (result) { // The function used by reduce to join the list into a string. let joiner = func (acc, item) => select ((acc.out == ""), NULL) => { true = acc{ out="@@" % (acc.out,item), }, false = acc{ out="@@@" % (acc.out, acc.sep, item), }, }; // The resulting joined string. Reference the result field from the // tuple the module produces to get the joined string. let result = reduce(joiner, {sep=mod.sep, out=""}, (mod.list)).out; }; // Computes the length of the provided list. let len = func(list) => reduce(func(acc, item) => acc + 1, 0, list); // Reverses the provided list. let reverse = func(list) => reduce(func (acc, item) => [item] + acc, [], list); // head returns the first item in a list as a list of one item. // This function is safe for empty list inputs but is not safe // for NULL inputs. let head = func(list) => select (len(list) > 0, []) => { true = [list.0], }; // tail returns the tail of a list without the head. // This function is safe for empty lists but is not safe // for NULL inputs. let tail = func(list) => reduce( func (acc, item) => select (acc.count > 0, acc{count=1, tail=[]}) => { true = acc{count = acc.count + 1, tail = acc.tail + [item]}, }, {count=0}, list, ).tail; // Enumerates the provided list with optional start and step parameters for the // enumeration. Produces a list of pairs with the enumeration and the list item. // // enumerate{list=["a","b","c"]} == [[0, "a"], [1, "b"], [2, "c"]] let enumerate = module{ // Where to start the enumeration. start = 0, // The step amount for each enumeration. step = 1, // The list to enumerate. list = NULL, } => (result) { let reducer = func (acc, item) => acc{ count = acc.count + acc.step, list=acc.list + [[acc.count, item]], }; let result = reduce( reducer, {count=mod.start, list=[], step=mod.step}, (mod.list)).list; }; // slice returns a slice of a list starting at index start up to and // including index end, inclusive. let slice = module { start = 0, end = NULL, list = NULL, } => (result) { let list = mod.pkg(); let list_len = list.len(mod.list); let end = select (mod.end is "null", mod.end) => { true = list_len - 1, }; let start = mod.start; // ensure some invariants (start >= 0) || fail "Slice must be positive"; (start <= list_len) || fail "Slice start cannot be larger than the list len of @" % (list_len); (end <= list_len) || fail "Slice end cannot be larger than list len of @" % (list_len); let reducer = func(acc, item) => acc + [mod.list.(item)]; let result = reduce( reducer, [], start:end); }; // zips two lists together. // The result list is only as long as the shortest list. // // zip{list1=[0,2,4],list2=[1,3,5]}.result == [[0, 1], [2, 3], [4, 5]] let zip = module{ list1 = NULL, list2 = NULL, } => (result) { let len = mod.pkg().len; // Compute the length of each list. let len1 = len(mod.list1); let len2 = len(mod.list2); // Compute the min range of the two lists. let rng = select ((len1 >= len2), NULL) => { true = 0:(len1 - 1), false = 0:(len2 - 1), }; // The reducer function for the zip operation. let reducer = func (acc, item) => acc{ result = acc.result + [[acc.list1.(item), acc.list2.(item)]], idxs = acc.idxs + [item] }; let acc = { list1 = mod.list1, list2 = mod.list2, result = [], idxs = [], }; // The resulting zipped list. let result = reduce(reducer, acc, rng).result; }; // Wraps a list and provides a number of helpful operations. // // * len - property the length of the wrapped list. // // * str_join - function joins list into string with provided separator `sep`. // // * slice - function returns a slice of the list from `start` to `end`. // // * enumerate - function returns a list of pairs of [index, value] from the list. // The returned list is wrapped in the ops module. // // * head - function returns the head of the list as list of one item. // // * tail - function returns the tail of the list. // The returned list is wrapped in the ops module. // // * reverse - function returns the list reversed. // The returned list is wrapped in the ops module. let ops = module{ list=NULL, } => ({len=len, str_join=str_join, slice=slice, enumerate=enumerate, tail=tail, head=head, reverse=reverse, list=list, }) { let pkg = mod.pkg(); let list = mod.list; let len = pkg.len(mod.list); let str_join = func(sep) => pkg.str_join{list=mod.list, sep=sep}; let slice = func(start, end) => pkg.slice{start=start, end=end, list=mod.list}; let enumerate = func() => pkg.ops{list=pkg.enumerate{start=0, step=1, list=mod.list}}; let tail = func() => pkg.ops{list=pkg.tail(mod.list)}; let head = func() => pkg.head(mod.list); let reverse = func() => mod.this{list=pkg.reverse(mod.list)}; };