use ./common use ./num var -l~ = $common:to-list~ var -c~ = $common:cexec~ var '++~' = $'num:++~' var is-neg~ = $num:is-neg~ fn indexes {|&from=0 &step=1 @argv| var c = (count (-l $@argv)) var from = (-c (is-neg $from) (+ $from $c) $from) var to = (-c (is-neg $step) -1 $c) if (and (>= $from 0) (< $from $c)) { range &step=$step $from $to } } fn loop {|&from=0 &step=1 @argv| var l = (-l $@argv) indexes &from=$from &step=$step $l | each {|i| put [ $i $l[$i] ] } } fn foreach {|&from=0 &step=1 &end=$false cb @argv| if (not $end) { loop &from=$from &step=$step $@argv | each {|e| $cb $@e} } else { loop &from=$from &step=$step $@argv | each {|e| if ($end $@e) { break } $cb $@e } } } fn pforeach {|&from=0 &step=1 cb @argv| loop &from=$from &step=$step $@argv | peach {|e| $cb $@e} } fn reach {|cb @argv| foreach &from=-1 &step=-1 {|_ e| $cb $e} $@argv } fn reverse {|@argv| reach $put~ $@argv } fn is-empty {|@argv| num:is-zero (count (-l $@argv)) } fn is-not-empty {|@argv| not (is-empty $@argv) } fn filter {|cb @argv| each {|e| -c ($cb $e) $e $nop~ } (-l $@argv) } fn filter-not {|cb @argv| filter {|v| not ($cb $v)} $@argv } fn contains {|cb @argv| var cb2~ = (common:cond (eq (kind-of $cb) fn) $cb {|e| eq $cb $e}) each {|e| if (cb2 $e) { put $true return } } (-l $@argv) put $false } fn contains-not {|cb @argv| not (contains $cb $@argv) } fn search {|cb @argv| foreach {|i e| -c ($cb $i $e) [$i $e] $nop~ } $@argv } fn search-not {|cb @argv| search {|i e| not ($cb $i $e) } $@argv } fn exists {|cb @argv| var r = $false foreach {|i e| if ($cb $i $e) { set r = $true break } } $@argv put $r } fn exists-not {|cb @argv| not (exists $cb $@argv) } fn search-first {|&from=$nil &reverse=$false cb @argv| var step = (-c $reverse -1 1) if (not $from) { set from = (-c $reverse -1 0) } foreach &from=$from &step=$step {|i e| if ($cb $i $e) { put [$i $e] break } } $@argv } fn first {|&from=$nil &reverse=$false cb @argv| search-first &from=$from &reverse=$reverse {|_ e| $cb $e} $@argv | each {|e| put $e[1] break } } fn unzip {|cb @argv| var a1 a2 = [] [] loop $@argv | each {|e| var i v = $@e if ($cb $i $v) { set @a1 = $@a1 $v } else { set @a2 = $@a2 $v } } put $a1 $a2 } fn reduce {|acc cb @argv| each {|e| set acc = ($cb $acc $e) } (-l $@argv) put $acc } fn remove-duplicate {|@argv| var done = [&] each {|e| if (not (has-key $done $e)) { set done[$e] = $nil put $e } } (-l $@argv) } fn swap {|i j @argv| var l = (-l $@argv) var c = (count $l) if (< $i 0) { set i = (+ $i $c) } if (< $j 0) { set j = (+ $j $c) } if (or (is-neg $i) (is-neg $j) (>= $i $c) (>= $j $c)) { fail 'index out of range' } if (== $i $j) { all $l } else { if (> $i $j) { set i j = $j $i } take $i $l put $l[$j] all $l[(++ $i)..$j] put $l[$i] drop (++ $j) $l } } fn sort {|cb @argv| order &less-than=(common:less $cb) (-l $@argv) }