Special Forms

??

(?? null "fallback")
==> "fallback"
(??)
==> null
(?? 1)
==> 1
(?? null)
==> null

The ?? operator returns the first of its parameters that is not null. It evaluates the parameters on demand.

cond

(let (a 1)
 (cond (< a 0) "less than zero"
       (< a 2) "less than two"
       true "greater than or equal to two"))
==> "less than two"
(let (a 3)
 (cond (< a 0) "less than zero"
       (< a 2) "less than two"
       true "greater than or equal to two"))
==> "greater than or equal to two"
(cond false "this is not going to match")
==> null
(cond)
==> null

The cond form allows you to express a conditional with multiple branches. It uses condition-branch pairs, returning the value of the first branch that matches the preceding conditional. If no branches match, it returns null. cond requires an even number of arguments.

define

(define name "value")
==> null

The define form binds a name to a value in the current namespace. name is visible to the definition of value, which means you can define recursive functions: (define myfun (fn () (myfun)))

dynfn

(let (my-dynamic-function (dynfn [] (* 10 dynamic-value)))
   (let (dynamic-value 5)
       (my-dynamic-function)))
==> 50.0

The dynfn form defines a dynamically scoped function. Unlike fn which operates in its lexical scope — seeing the names available where it’s defined in the source file — a function defined with dynfn operates in a dynamic scope, seeing the values in its caller’s namespace.

eq

(let (a 10
      b (+ 5 5)
      c (- 12 2))
   (eq a b c))
==> true

The eq forms compares its parameters to each other and returns a boolean indicating if they’re identical.

fn

((fn [a] (* a a)) 3)
==> 9.0
(((fn [a] (fn [b] (* a b))) 3) 4)
==> 12.0

The fn form defines a function. Its first parameter is an array of parameters, and it evaluates the rest of the expressions one by one, returning the value from the last one. The functions defined with fn capture their lexical scope: you can refer to values in the containing source location when you return values from functions or pass functions as parameters. If you want to skip naming the parameters of your function, use the fna form which assigns automatic numbered names.

fna

((fna (* $0 $0)) 3)
==> 9.0

The fna form defines a function with anonymous parameters. It evaluates the expressions it is given as parameters one by one, returning the value from the last one. The functions defined with fna capture their lexical scope: you can refer to values in the containing source location when you return values from functions or pass functions as parameters. The parameters passed in to functions defined with fna have access to their parameters with the automatic names $0, $1, etc. If you want to give names to the function parameters, use the fn form.

if

(define f (fn [a] (if (not (eq a 0))
                       (/ 1 a)
                       0)))
==> null
(f 10.0)
==> 0.1

The if form evaluates takes three parameters: an expression evaluating to a boolean, a "then" expression and an "else" expression.

let

(let (a 2
      b (* a 3)
      c (* b a))
   c)
==> 12.0

The let form creates a new namespace with value bindings from the first expression and evaluates the rest of the expressions one by one, returning the value from the last one. The first expression consists of pairs of values, alternating between variable names and values. Each definition sees the ones created before it. The names defined in let are not visible when you leave the let.

Functions

%

(% 20 12 3)
==> 2.0

% is the modulo (remainder) operator. It operates on integers or doubles. It converts integers to doubles if it receives both as arguments.

*

(* 12 -13 14)
==> -2184.0

* is the multiplication operator. It operates on integers or doubles. It converts integers to doubles if it receives both as arguments.

+

(+ 12 -13 14)
==> 13

+ is the addition operator. It operates on integers or doubles. It converts integers to doubles if it receives both as arguments.

-

(- 12 -13 14)
==> 11

- is the subtraction operator. It operates on integers or doubles. It converts integers to doubles if it receives both as arguments.

/

(/ 12.0 -13.0 14.0)
==> -0.06593407
(/ 25 2)
==> 12

/ is the division operator. It operates on integers or doubles. It converts integers to doubles if it receives both as arguments. It performs integer division when operating on integers, discarding the fraction part.

> >= < <=

(> 3 2 1)
==> true
(> 3 3 2)
==> false
(>= 3 3 2)
==> true
(< 1 2 3)
==> true
(<= 1 2 1)
==> false

The basic numeric comparison operators are less than (<), less than or equal (<=), greater than (>), and greater than or equal (>=). They support any number of arguments.

apply

(apply concat ["abc", "def", "ghi"])
==> "abcdefghi"
(apply (fn [a, b, c] (+ a b c)) [10, 20, 30])
==> 60

The apply function calls a function with parameters from the array. The function can be a built-in one or one defined in SexpyJSON.

as-dict

(as-dict { "hello": "world" })

The as-dict function converts an object to a dictionary.

as-object

(as-object (merge { "k1": "v1" } { "k2": "v2" }))

The as-object function converts a dictionary to an object.

ceil

(ceil 16.4)
==> 17.0
(ceil 16.5)
==> 17.0
(ceil -16.5)
==> -16.0

The ceil function rounds its parameter to the nearest larger integer. It does not change the number’s type.

concat

(concat "ab" "cd" "ef")
==> "abcdef"
(concat [1, 2] [3, 4] [5, 6])
==> [1, 2, 3, 4, 5, 6]

The concat function concatenates strings or arrays.

dict

(dict "foo" "bar" "zap" "bang")
==> { "foo": "bar", "zap": "bang" }

The dict function constructs a dictionary, using the first parameter as the first key, the second parameter as the value for the first key, the third parameter as the second key, etc.

double

(double 12)
==> 12.0
(double -12)
==> -12.0

The double function converts its number parameter to double.

filter

(filter (fn (a) (> a 2)) [0, 1, 2, 3, 2, 4, 3, 1])
==> [3, 4, 3]

The filter function filters an array with a predicate function. The return value is an array with the elements for which the function returns true.

flatmap

(flatmap (fn (a) [a, a]) [1, 2])
==> [1, 1, 2, 2]

The flatmap function maps over an array with a function that returns arrays and joins the returned arrays.

floor

(floor 18.4)
==> 18.0
(floor 18.5)
==> 18.0
(floor -18.5)
==> -19.0

The floor function rounds its parameter to the nearest smaller integer. It does not change the number’s type.

has-name

(let (a 10) (has-name "a"))
==> true
(let (a 10) (has-name "b"))
==> false

The has-name function returns true if the string given as an argument is a name of an existing value. You can access it with the name? or name function.

int

(int 12.4)
==> 12
(int 12.5)
==> 12
(int -12.5)
==> -12.0

The int function truncates its parameter to the nearest integer that’s closer to zero. Its return value is an integer.

is-null

(is-null null)
==> true
(is-null "asdf")
==> false

The is-null function returns true if its sole parameter is null.

join-string

(join-string ", " ["hello", "world"])
==> "hello, world"

The join-string function joins an array of strings into a single string using a separator. The first parameter is the separator string, the second parameter the array.

len

(len [1, 2, 3, 4])
==> 4
(len "foo")
==> 3

The len function returns the lenght of an array or a string.

map

(map len ["a", "bb", "ccc"])
==> [1, 2, 3]

The map function maps a function over an array.

merge

(merge {"a": "b"} {"c": "d"} {"e": "f"})
==> {"a": "b", "c": "d", "e": "f"}

The merge function merges the fields of two or more objects or dictionaries, returning a dictionary with the key-value pairs from all the parameters. Objects later in the parameter list take precendence in collisions.

name

(let (a 10) (name "a"))
==> 10

The name function returns the value bound to the name in the current lexical scope. If the name doesn’t exist, an error is raised. You can check for the name’s existence with has-name function or return null in case of a non-existent name with name.

name?

(let (a 10) (name? "a"))
==> 10
(let (a 10) (name? "b"))
==> null

The name? function returns the value bound to the name in the current lexical scope. If the name doesn’t exist, it returns null. You can check for the name’s existence with has-name function or cause an error to be raised in case of an nonexistent name with name?.

not

(not true)
==> false
(not false)
==> true

The not function is the boolean not operation, returning the inverse of the boolean it received as a parameter.

object

(object "foo" "bar" "zap" "bang")
==> { "foo": "bar", "zap": "bang" }

The object function constructs an object, using the first parameter as the first key, the second parameter as the value for the first key, the third parameter as the second key, etc.

round

(round 12.4)
==> 12.0
(round 12.5)
==> 13.0
(round -12.5)
==> -13.0

The round function rounds its parameter number away from zero. It does not change the number’s type.

sub

(sub ["foo", "bar", "zap", "bang"] 2)
==> "zap"
(sub {"key1": "value1", "key2": "value2"} "key2")
==> "value2"
(sub {"key1": {"nestedKey1": "nestedValue1"}} "key1" "nestedKey1")
==> "nestedValue1"

The sub function is the subscription operator. It allows you to retrieve a member of an array (with an index) or an object (with a string). See also sub?.

sub?

(sub? {"key1": {"nestedKey1": "nestedValue1"}} "key1" "nestedKey1")
==> "nestedValue1"
(sub? {"key1": {"nestedKey1": "nestedValue1"}} "key2" "nestedKey1")
==> null

The sub? function is the subscription operator with support for conditional container. It allows you to retrieve a member of an array (with an index) or an object (with a string), and returns null if the container is null. See also sub.

trunc

(trunc 14.4)
==> 14.0
(trunc 14.5)
==> 14.0
(trunc -14.5)
==> -14.0

The trunc function truncates its parameter number to the nearest integer that’s closer to zero. It does not change the number’s type.