# Tuple utilities local { include 'skin/cop' oper $ tuplen prefix 30 oper > tail prefix 50 def __pnt{t} = tupsel{0,t} def tail{tup} = slice{tup, 1} include 'util/kind' def sl{l, start, len} = slice{l, start, start + len} } # Tuple is empty def empty{tup} = 0 == $tup # Constant-time evaluation returning a list def collect{vars,begin,end,block & begin<=end} = { def c{i,l} = { def r = exec{i, vars, block} merge{tup{r}, c{i+1, l}} } def c{l,l} = tup{} c{begin,end} } # Integers [0,n) def iota{n & knum{n}} = @collect (i to n) i # All indices into tuple t def inds{t} = iota{$t} # Tuple of n copies of v def copy{n, v & knum{n}} = @collect (n) v # Merge a tuple of tuples def join{l} = merge{...l} # Shift l into r, retaining length of r, or vice-versa def shiftright{l, r} = slice{merge{l, r}, 0, $r} def shiftleft {l, r} = slice{merge{l, r}, - $l} # Reversed tuple def reverse{t} = tupsel{($t-1) - inds{t}, t} # Tuple of length n made from t repeated cyclically def cycle{n, t & knum{n}} = { def l = $t def m = n % l; def e = slice{t, 0, m} if (m == n) e else join{merge{copy{(n-m)/l, t}, tup{e}}} } # Split into groups of length n, possibly less for the last def split{n, list & knum{n}} = { def l = $list def d = (l + (-l)%n) / n @collect (i to d) sl{list, i*n, n} } def split{n, list & ktup{n}} = { def start = shiftright{0, scan{+,n}} each{bind{sl, list}, start, n} } # Transpose tuple of tuples, assuming each has the same length def flip{tup} = table{tupsel, inds{*tup}, tup} # Function table mapping over all combinations def table{f, ...tups} = { if (empty{tups}) f{} else if (1 == $tups) each{f, *tups} else each{{e} => table{bind{f,e}, ...>tups}, *tups} } # Left fold, with or without initial element def fold{f, init, list} = { if (empty{list}) init else fold{f, f{init, *list}, >list} } def fold{f, list} = fold{f, *list, >list} # Inclusive left scan def scan{f, init, list} = scan_sub{f, {e} => f{init, e}, list} def scan{f, list} = scan_sub{f, {e} => e, list} local def scan_sub{f, get, list} = { if (empty{list}) list else { def r = get{*list} merge{tup{r}, scan{f, r, >list}} } } # Copy list elements based on list, constant, or generator (like filter) def replicate{reps, list} = join{each{copy, reps, list}} def replicate{r, list & knum{r}} = join{each{bind{copy, r}, list}} def replicate{f, list & kgen{f}} = replicate{each{f,list}, list} # For boolean i, return indices of 1s def indices{i} = replicate{i, inds{i}}