(x, y, ...zs) -> fold (base :mult, mult (x, y), zs)
(scalar as :number, (x, y)) -> (mult (x, scalar), mult (y, scalar))
((x, y), scalar as :number) -> mult (scalar, (x, y))
}
fn div {
"Divides numbers. Panics on division by zero."
(x as :number) -> x
(_, 0) -> panic! ("Division by zero.")
(x as :number, y as :number) -> base :div (x, y)
(x, y, ...zs) -> {
let divisor = fold (mult, zs, y)
div (x, divisor)
}
}
fn div/0 {
"Divides number. Returns 0 on division by zero."
(x as :number) -> x
(_, 0) -> 0
(x as :number, y as :number) -> base :div (x, y)
(x, y, ...zs) -> {
let divisor = fold (mult, zs, y)
div/0 (x, divisor)
}
}
fn zero? {
"Returns true if a number is 0."
(0) -> true
(_) -> false
}
fn eq? {
"Returns true if all arguments have the same value."
(x) -> true
(x, y) -> base :eq (x, y)
(x, y, ...zs) -> loop (y, zs) with {
(a, [b]) -> base :eq (a, b)
(a, [b, ...cs]) -> if base :eq (a, b)
then recur (b, cs)
else false
}
}
fn gt? {
"Returns true if numbers are in decreasing order."
(x as :number) -> true
(x as :number, y as :number) -> base :gt (x, y)
(x, y, ...zs) -> loop (y, zs) with {
(a, [b]) -> base :gt (a, b)
(a, [b, ...cs]) -> if base :gt (a, b)
then recur (b, cs)
else false
}
}
fn gte? {
"Returns true if numbers are in decreasing or flat order."
(x as :number) -> true
(x as :number, y as :number) -> base :gte (x, y)
(x, y, ...zs) -> loop (y, zs) with {
(a, [b]) -> base :gte (a, b)
(a, [b, ...cs]) -> if base :gte (a, b)
then recur (b, cs)
else false
}
}
fn lt? {
"Returns true if numbers are in increasing order."
(x as :number) -> true
(x as :number, y as :number) -> base :lt (x, y)
(x, y, ...zs) -> loop (y, zs) with {
(a, [b]) -> base :lt (a, b)
(a, [b, ...cs]) -> if base :lt (a, b)
then recur (b, cs)
else false
}
}
fn lte? {
"Returns true if numbers are in increasing or flat order."
(x as :number) -> true
(x as :number, y as :number) -> base :lte (x, y)
(x, y, ...zs) -> loop (y, zs) with {
(a, [b]) -> base :lte (a, b)
(a, [b, ...cs]) -> if base :lte (a, b)
then recur (b, cs)
else false
}
}
fn neg? {
"Returns true if a value is a negative number, otherwise returns false."
(x as :number) if lt? (x, 0) -> true
(_) -> false
}
fn pos? {
"Returns true if a value is a positive number, otherwise returns false."
(x as :number) if gt? (x, 0) -> true
(_) -> false
}
fn nil? {
"Returns true if a value is nil."
(nil) -> true
(_) -> false
}
fn bool? {
"Returns true if a value is of type :boolean."
(false) -> true
(true) -> true
(_) -> false
}
fn bool {
"Returns false if a value is nil or false, otherwise returns true."
(nil) -> false
(false) -> false
(_) -> true
}
fn not {
"Returns false if a value is truthy, true if a value is falsy."
(nil) -> true
(false) -> true
(_) -> false
}
& TODO: make `and` and `or` special forms which lazily evaluate arguments
fn and {
"Returns true if all values passed in are truthy."
() -> true
(x) -> bool (x)
(x, y) -> base :and (x, y)
(x, y, ...zs) -> fold (base :and, zs, base :and (x, y))
}
fn or {
"Returns true if any value passed in is truthy."
() -> true
(x) -> bool (x)
(x, y) -> base :or (x, y)
(x, y, ...zs) -> fold (base :or, zs, base :or (x, y))
}
fn assoc {
"Takes a dict, key, and value, and returns a new dict with the key set to value."
(d as :dict) -> d
(d as :dict, key as :keyword, value) -> base :assoc (d, key, value)
(d as :dict, (key as :keyword, value)) -> base :assoc (d, key, value)
}
fn dissoc {
"Takes a dict and a key, and returns a new dict with the key and associated value omitted."
(d as :dict) -> d
(d as :dict, key as :keyword) -> base :dissoc (d, key)
}
fn coll? {
"Returns true if a value is a collection: dict, struct, list, tuple, or set."
(coll as :dict) -> true
(coll as :struct) -> true
(coll as :list) -> true
(coll as :tuple) -> true
(coll as :set) -> true
(_) -> false
}
fn ordered? {
"Returns true if a value is an indexed collection: list or tuple."
(coll as :list) -> true
(coll as :tuple) -> true
(_) -> false
}
fn assoc? {
"Returns true if a value is an associative collection: a dict, struct, or namespace."
(assoc as :dict) -> true
(assoc as :struct) -> true
(assoc as :ns) -> true
(_) -> false
}
fn get {
"Takes a dict or struct, key, and optional default value; returns the value at key. If the value is not found, returns nil or the default value. Returns nil or default if the first argument is not a dict or struct."
(key as :keyword, coll) -> base :get (key, coll)
(key as :keyword, coll, default) -> base :get (key, coll, default)
}
& TODO: make this less awkward once we have tail recursion
&&&&&&&&& TODO:
&& Fix bug here:
&& The second pattern in `each` and `foo` hangs when the first argument is a function
&& But maybe not other kinds of values (works fine if it's a keyword)
&& See interpreter.cljc line 76 for more info.
fn each {
"Takes a list and applies a function, presumably with side effects, to each element in the list. Returns nil."