Janet 1.4.0-655d4b3 Documentation
(Other Versions:
1.4.0
1.3.1)
Functions
Janet is a functional language - that means that one of the basic building blocks of your program will be defining functions (the other is using data structures). Because janet is a Lisp, functions are values just like numbers or strings - they can be passed around and created as needed.
Functions can be defined with the defn
macro, like so:
(defn triangle-area
"Calculates the area of a triangle."
[base height]
(print "calculating area of a triangle...")
(* base height 0.5))
A function defined with defn
consists of a name, a number of optional flags for def, and
finally a function body. The example above is named triangle-area and takes two parameters named
base and height. The body of the function will print a message and then evaluate to the area of the triangle.
Once a function like the above one is defined, the programmer can use the triangle-area
function just like any other, say print
or +
.
# Prints "calculating area of a triangle..." and then "25"
(print (triangle-area 5 10))
Note that when nesting function calls in other function calls like above (a call to triangle-area is nested inside a call to print), the inner function calls are evaluated first. Also, arguments to a function call are evaluated in order, from first argument to last argument).
Because functions are first-class values like numbers or strings, they can be passed as arguments to other functions as well.
(print triangle-area)
This prints the location in memory of the function triangle area.
Functions don't need to have names. The fn
keyword can be used to introduce function
literals without binding them to a symbol.
# Evaluates to 40
((fn [x y] (+ x x y)) 10 20)
# Also evaluates to 40
((fn [x y &] (+ x x y)) 10 20)
# Will throw an error about the wrong arity
((fn [x] x) 1 2)
# Will not throw an error about the wrong arity
((fn [x &] x) 1 2)
The first expression creates an anonymous function that adds twice the first argument to the second, and then calls that function with arguments 10 and 20. This will return (10 + 10 + 20) = 40.
There is a common macro defn
that can be used for creating functions and immediately binding
them to a name. defn
works as expected at both the top level and inside another form. There is also
the corresponding macro defmacro
that does the same kind of wrapping for macros.
(defn myfun [x y]
(+ x x y))
# You can think of defn as a shorthand for def and fn together
(def myfun-same (fn [x y]
(+ x x Y)))
(myfun 3 4) # -> 10
Janet has many macros provided for you (and you can write your own). Macros are just functions that take your source code and transform it into some other source code, usually automating some repetitive pattern for you.
Optional Arguments
Most Janet functions will raise an error at runtime
if not passed exactly the right number of arguments.
Sometimes, you want to define a function with optional arguments, where the arguments
take a default value if not supplied by the caller. Janet has support for this via
the &opt
symbol in parameter lists, where all parameters after &opt
are
nil
if not supplied.
(defn my-opt-function
"A dumb function with optional arguments."
[a b c &opt d e f]
(default d 10)
(default e 11)
(default f 12)
(+ a b c d e f))
The (default)
macro is a useful macro for setting default values for parameters. If a parameter
is nil, (default)
will redefine it to a default value.
Variadic Functions
Janet also provides first-class support for variadic functions. Variadic functions can take any number
of parameters, and gather them up into a tuple. To define a variadic function, use the &
symbol
as the second to last item if the parameter list. Parameters defined before the last variadic argument
are not optional, unless specified as so with the &opt
symbol.
(defn my-adder
"Adds numbers in a dubious way."
[& xs]
(var accum 0)
(each x xs
(+= accum (- (* 2 x) x)))
accum)
(my-adder 1 2 3) # -> 6
Ignoring Extra Arguments
Sometimes you may want to have a function that can take a number of extra arguments but not
use them. This happens because a function may be part of an interface, but the function itself
doesn't need those arguments. You can write a function that will simply drop extra parameters
by adding &
as the last parameter in the function.
(defn ignore-extra
[x &]
(+ x 1))
(ignore-extra 1 2 3 4 5) # -> 2