-*-org-mode-*-
Functions which are generally useful throughout the rest of the library.
Probably not very useful to users.
use ./test
functions which work on numbers.
# currently only work with integers
fn is-even {|n| == (% $n 2) 0 }
fn is-odd {|n| != (% $n 2) 0 }
fn is-zero {|n| == 0 $n }
fn is-one {|n| == 1 $n }
fn dec {|n| - $n 1 }
fn inc {|n| + $n 1 }
fn pos {|n| > $n 0 }
fn neg {|n| < $n 0 }
fn is-fn {|x| eq (kind-of $x) fn }
fn is-map {|x| eq (kind-of $x) map }
fn is-list {|x| eq (kind-of $x) list }
fn is-string {|x| eq (kind-of $x) string }
fn is-bool {|x| eq (kind-of $x) bool }
fn is-number {|x| eq (kind-of $x) number }
fn is-nil {|x| eq $x $nil }
All of these fns operate on lists.
fn prepend {|li @args| put [(put $@args (all $li))] }
fn append {|li @args| put [(put (all $li) $@args)] }
fn concat2 {|l1 l2| put [(all $l1) (all $l2)] }
fn pluck {|li n| put [(all $li[..$n]) (all $li[(inc $n)..])] }
fn get {|li n| put $li[$n] }
fn first {|li| put $li[0] }
fn ffirst {|li| first (first $li) }
fn second {|li| put $li[1] }
fn rest {|li| put $li[1..] }
fn end {|li| put $li[-1] }
fn is-empty {|li| is-zero (count $li) }
fn butlast {|li| put $li[..(dec (count $li))] }
fn swap {|coll x y| assoc (assoc $coll $x $coll[$y]) $y $coll[$x] }
More complicated list operations.
fn nth {
|li n ¬-found=$false|
if (and $not-found (> $n (count $li))) {
put $not-found
} else {
drop $n $li | take 1
}
}
fn check-pipe {
|li|
# use when taking @args
if (is-empty $li) {
all
} else {
put $@li
}
}
fn flatten {
|li|
if (eq (kind-of $li) list) {
for e $li {
flatten $e
}
} else {
put $li
}
}
var tests = [base.elv
'These functions largely assume numbers, lists, and strings. The list operations are of dubious usefulness for users, however.'
'# Math functions'
[is-zero
'works with text, nums, and inexact-nums'
(test:assert-one $true)
{ is-zero 0 }
{ is-zero (num 0) }
{ is-zero (inexact-num 0) }
(test:assert-one $false)
{ is-zero 1 }
{ is-zero (randint 1 100) }
{ is-zero (inexact-num (randint 1 100)) }]
[is-one
'works with text, nums, and inexact-nums'
(test:assert-one $true)
{ is-one 1 }
{ is-one (num 1) }
{ is-one (inexact-num 1) }
(test:assert-one $false)
{ is-one 0 }
{ is-one (num 0)}
{ is-one (inexact-num 0)}]
[evens
'only works with strings & nums'
(test:assert-each $false $true $false $true $false $true $false $true $false $true $false)
{ range -5 6 | each $is-even~ }
{ range -5 6 | each $to-string~ | each $is-even~ }
'fails with inexact-nums'
(test:assert-error)
{ is-even 5.0 }]
[odds
'only works with strings & nums'
(test:assert-each $true $false $true $false $true $false $true $false $true $false $true)
{ range -5 6 | each $is-odd~ }
{ range -5 6 | each $to-string~ | each $is-odd~ }
'fails with inexact-nums'
(test:assert-error)
{ is-odd 5.0 }]
[inc
'works with text, nums, and inexact-nums'
(test:assert-each (range -4 7))
{ range -5 6 | each $inc~ }
(test:assert-each (range -4 7))
{ range -5 6 | each $to-string~ | each $inc~ }
(test:assert-each (range -4.0 7))
{ range -5 6 | each $inexact-num~ | each $inc~ }]
[dec
'works with text, nums, and inexact-nums'
(test:assert-each (range -6 5))
{ range -5 6 | each $dec~ }
(test:assert-each (range -6 5))
{ range -5 6 | each $to-string~ | each $dec~ }
(test:assert-each (range -6.0 5))
{ range -5 6 | each $inexact-num~ | each $dec~ }]
[pos/neg
'works with text, nums, and inexact-nums'
(test:assert-each $false $true)
{ each $pos~ [-1 1] }
{ each $neg~ [1 -1] }
{ each $pos~ [(num -1) (num 1)] }
{ each $neg~ [(num 1) (num -1)] }
{ each $pos~ [(inexact-num -1) (inexact-num 1)] }
{ each $neg~ [(inexact-num 1) (inexact-num -1)] }]
'# Type predicates'
[is-functions
'predicate functions for types'
(test:assert-one $true)
{ is-fn { } }
{ is-map [&] }
{ is-list [] }
{ is-bool $true }
{ is-number (num 0) }
{ is-string "" }
'lots of things which look like other types are actually strings'
{ is-string 1 }
{ is-string {} }
'likewise, these look like a number and a function, but they are actually strings'
(test:assert-one $false)
{ is-number 1 }
{ is-fn {} }]
'# List operations'
[prepend
'prepends a scalar value to a list'
(test:assert-one [0 1 2 3])
{ prepend [2 3] 0 1 }
{ put [2 3] | prepend (all) 0 1 }
{ put 2 3 | prepend [(all)] 0 1 }
'prepend on strings implicitly transforms to list'
(test:assert-one [h e l l o])
{ prepend ello h}]
[append
'appends a scalar value to a list'
(test:assert-one [0 1 2 3])
{ append [0 1] 2 3 }
{ put [0 1] | append (all) 2 3 }
{ put 0 1 | append [(all)] 2 3 }
'append on strings implicitly transforms to list'
(test:assert-one [h e l l o])
{ append hell o}]
[concat2
'concatenate two lists'
(test:assert-one [0 1 2 3])
{ concat2 [0 1] [2 3] }
'concat2 on strings implicitly transforms to list'
(test:assert-one [h e l l o])
{ concat2 he llo }]
[pluck
'removes the element at a given index from a list.'
(test:assert-one [0 1 2 3])
{ pluck [0 1 x 2 3] 2 }
{ put [0 1 x 2 3] | pluck (all) 2 }
{ put 0 1 x 2 3 | pluck [(all)] 2 }
'corner-cases'
{ put [-1 0 1 2 3] | pluck (all) 0 }
{ put [0 1 2 3 4] | pluck (all) 4 }
'pluck on strings implicitly transforms to list'
(test:assert-one [x m e n])
{ pluck x-men 1 }]
[get
'retrieves the element at index i in a list'
(test:assert-one s)
{ get [0 1 s 2 3] 2 }
{ put [0 1 s 2 3] | get (all) 2 }
{ put 0 1 s 2 3 | get [(all)] 2 }
'works on strings, too'
{ get string 0 }]
[first
'retrieves the first element from a list'
(test:assert-one 0)
{ first [0 1 2 3] }
{ put 0 1 2 3 | first [(all)] }
'works on strings, too'
(test:assert-one h)
{ first "hello" }
{ first hello }]
[ffirst
'nested `first` on a list'
(test:assert-one a)
{ ffirst [[a b c] 1 2 3] }
{ put [a b c] 1 2 3 | ffirst [(all)] }]
[second
'retrieves the second element from a list'
(test:assert-one 1)
{ second [0 1 2 3] }
{ put 0 1 2 3 | second [(all)] }
'works on strings, too'
(test:assert-one e)
{ second "hello" }
{ second hello }]
[rest
'drops the first element from a list'
(test:assert-each [1 2 3])
{ rest [0 1 2 3] }
{ put 0 1 2 3 | rest [(all)] }
'works on strings without coercing the result to a list'
(test:assert-one ello)
{ rest "hello" }
{ rest hello }]
[end
'retrieves the last element from a list (the end of a list)'
(test:assert-one 3)
{ end [0 1 2 3] }
{ put 0 1 2 3 | end [(all)] }
'works on strings, too'
(test:assert-one o)
{ end "hello" }
{ end hello }]
[butlast
'drops the last element from a list'
(test:assert-each [0 1 2])
{ butlast [0 1 2 3] }
{ put 0 1 2 3 | butlast [(all)] }
'works on strings without coercing the result to a list'
(test:assert-one hell)
{ butlast "hello" }
{ butlast hello }]
[is-empty
'does whats on the tin'
(test:assert-one $true)
{ is-empty [] }
{ is-empty '' }]
[swap
'Works on maps'
(test:assert-one [&a=1 &b=2])
{ swap [&a=2 &b=1] a b }
'Works on lists'
(test:assert-one [a b c])
{ swap [b a c] 0 1 }
'Works on strings'
(test:assert-one stuff)
{swap tsuff 0 1}]
'# More complicated list operations'
[nth
'returns the nth item in a list'
(test:assert-one b)
{ nth [f o o b a r] 3 }
{ put f o o b a r | nth [(all)] 3 }
'and of course it works with strings'
{ nth foobar 3 }
'It returns nothing if the index is out of range'
(test:assert-nothing)
{ nth [f o o b a r] 10 }
'You can optionally specify the `not-found` value'
(test:assert-one kaboom)
{ nth [$nil $nil $nil] 10 ¬-found=kaboom}
'It uses `drop` under the hood, so negative indices just return the 0-index'
(test:assert-one f)
{ nth [f o o b a r] -10}]
[check-pipe
'this is probably the most interesting function here. it takes input, and if the input is empty, returns whats in the pipe. Otherwise it returns the input, exploded.'
(test:assert-each 1 2 3)
{ check-pipe [1 2 3] }
{ put 1 2 3 | check-pipe [] }]
[flatten
'recursive function which basically performs nested explosions on a list, ignoring lists.'
(test:assert-each (range 1 10 | each $to-string~))
{ flatten [1 [2 3] [4 [[5 [6] 7]] 8 [] [9]]]}
'anything else is just returned'
(test:assert-one foobar)
{ flatten foobar }]]