Elva is a tiny LISP on Java. Everyone can write elva by learning only how to define functions and macros and how to call the Java APIs.
The elva specification is very small and is independent of the complex traditions of Common Lisp and Scheme. Unlike Clojure, you don't have to keep up with the latest language evolution to maintain the programs. This is a great advantage for domain-specific issues.
Everything you need to learn is written on this page. If you find a function or macro that you are not familiar with, you can always find the definition by following the source code dependencies.
A program is written as an atom or a list form. Atoms are all values that are not lists, e.g., a symbol, type, number, boolean, string, function, macro, and other Java objects. Unlike lists, they cannot be disassembled, so they are called atoms.
1919810 ;atom
"Hello" ;atom
(3 6 4) ;list
Elva evaluates these programs according to the following rules.
- The value of an atom is the atom itself.
- The value of a symbol is the variable value referenced by the symbol.
- For lists, apply the operator at the first element to the subsequent list elements.
There are no exceptions.
The following shows an example of defining and referencing the variable JR1ZTT
.
(setq JR1ZTT 1420)
JR1ZTT ;1420
If there is no variable with the specified name, the symbol will be resolved as the name of the Java class.
(import java.lang.String)
String ;java.lang.String
A number is an instance of Number
, e.g., an int
, long
, float
, double
and BigDecimal
.
The entity of integer literal is an int
, and all other numeric literals with a decimal point are BigDecimal
s.
1919810 ;int
364.364 ;BigDecimal
A boolean literal is an instance of Boolean
.
#t ;true
#f ;false
A string literal is an instance of String
.
"Ramen Yatai"
Any other atoms are instances of Object
.
A list is a data structure in which multiple elements are arranged in order.
A list is an instance of List
.
'(1 2 3) ;a list whose contents are 1, 2, and 3
To create a list, use the list
function.
(list 1 2 3)
To insert an element at the beginning of the list, use the cons
function.
(cons 1 (list 2 3)) ;(1 2 3)
Use the car
function to retrieve the first element of the list.
Use the cdr
function to get a partial list with the second and subsequent elements of the list.
(car (list 1 2 3)) ;1
(cdr (list 1 2 3)) ;(2 3)
The nth
function is an efficient way to specify an index by number and retrieve the element at that position.
(nth 0 (list 1 14 5 14)) ;1
(nth 2 (list 1 14 5 14)) ;5
Note that Java arrays are handled as lists in elva.
A function works as the C and Java programmers know.
You can define some functions add
and mul
as follows.
(defun add (x y z) (+ x y z))
(defun mul (x y z) (* x y z))
These functions take three values as arguments and calculate the sum or product. To call these functions, write as follows.
(add 1 2 3) ; 6
(mul 3 6 9) ;162
Note that the function arguments are evaluated before calling the function. Therefore, you can specify the value of a function as an argument to another function as follows.
(add (mul 5 9 9) (mul 1 0 0) (mul 1 1 0)) ;405
(mul (add 5 9 9) (add 1 0 0) (add 1 1 0)) ; 46
The arguments are evaluated as follows. Keep this behavior in mind and compare it to the macro behavior described below.
(add 405 0 1) ;405
(mul 23 1 2) ; 46
To create an anonymous function, use the lambda
form.
(lambda () (+ 1420 16005)) ;accepts no arguments and returns 17425
(lambda (x y z) (+ x y z)) ;accepts three arguments
These anonymous functions can be called in the same way as named functions.
((lambda (x y) (* x y)) 100 110) ;11000
In fact, the defun
macro is syntactic sugar equivalent to the following expression.
(defmacro defun (name params body) (list 'setq name (list 'lambda params body)))
A macro is a function that transforms a macro call into another expression and evaluates the converted expression.
The functions add
and mul
introduced above can be redefined as macros as follows.
(defmacro add (x y z) (list + x y z)) ;will expand x,y,z into the template (+ x y z)
(defmacro mul (x y z) (list * x y z)) ;will expand x,y,z into the template (* x y z)
And you can use them like functions.
(add (mul 5 9 9) (mul 1 0 0) (mul 1 1 0)) ;405
(mul (add 5 9 9) (add 1 0 0) (add 1 1 0)) ; 46
However, macros are not functions. First, the macro call is evaluated as follows:
(+ (mul 5 9 9) (mul 1 0 0) (mul 1 1 0)) ;405
(* (add 5 9 9) (add 1 0 0) (add 1 1 0)) ; 46
Great.
By using the list
function, both macros embed their arguments into the template without evaluating the arguments.
The converted expression is then evaluated as follows.
(+ 405 0 0) ;405
(* 23 1 2) ; 26
Unlike functions, macros give you the freedom to decide whether to evaluate an argument or treat it as data without evaluating it.
Macros are a good way to implement some syntax or domain-specific languages in LISP.
To create an anonymous macro, use the syntax
form.
(syntax () (+ 1420 16005)) ;accepts no arguments and returns 17425
(syntax (x y z) (+ x y z)) ;accepts three arguments
These anonymous macros can be called in the same way as named macros.
((syntax (x y) (* x y)) 100 110) ;11000
In fact, the defmacro
macro is syntactic sugar equivalent to the following expression.
(defmacro defmacro (name params body) (list 'setq name (list 'syntax params body)))
To import a Java class, use the import
function.
(import java.lang.String)
You can access the Java constructor by using the new
function.
(new Integer int) ;Integer::new
To reference a Java method, use the method
function.
(method 'length String) ;String.length()
Give arguments to call the constructor and method.
((method 'replaceAll String String String) "foobar" "r" "z") ;"foobaz"
((method 'replaceAll String String String) "foobar" "f" "b") ;"boobar"
For instance methods, the first argument must be the instance.
This argument is not required when calling constructors or static methods.
The second and subsequent arguments are passed to the constructor or method as their arguments.
To reference a Java field, use the access
function.
((access 'x Point) ((new Point int int) 123 321)) ;123
((access 'y Point) ((new Point int int) 123 321)) ;321
If you do not mind the processing efficiency, Java APIs can be referenced using the new!
, method!
, and access!
functions.
((new! Integer) 123)
((method! 'replaceAll) "foobar" "r" "z")
((access! 'x Point) ((new! Point) 12 3))
Passing an elva list to a Java method will convert the list to a Java List
.
If the method requires an array, the list will be converted to an array.
Quoting is an important feature that realizes LISP's powerful metaprogramming capabilities.
The quote
form controls when the expression is evaluated.
(quote (+ 1 2 3)) ;a list (+ 1 2 3)
The quote
form accepts a single expression as an argument and returns it as is without evaluation.
You can abbreviate the quote
form as follows.
'(+ 1 2 3) ;is equivalent to (quote (+ 1 2 3))
There is another version of quoting, namely quasiquote
.
`(+ 1 2 3)
(quasiquote (+ 1 2 3))
You can unquote some sub expressions in the quasi-quoted expression.
These sub expressions are evaluated exceptionally.
You can use the unquote
function or a special symbol `
for this purpose.
`(+ 1 2 ,(+ 1 2)) ;(+ 1 2 3)
There is another version of unquoting, called unquote-splicing
.
This evaluates the unquoted sub expression as a list and then embeds the elements to the expression as a list.
`(+ 1 2 ,@(list 3 4 5)) ;(+ 1 2 3 4 5)
creates and returns a absence
object.
(absence name code)
returns the field with the specified name.
(access 'name class)
returns the field with the specified name.
(access! 'name)
performs addition and returns a real value.
(+ real1 *reals)
performs and operation and returns a bool value.
(and bool1 *bools)
returns an array type.
(array element-type)
throws an error if the expression returns false.
(assert condition message)
evaluates the expressions inside a nested scope.
(block *expressions)
returns the second element of the specified list.
(cadr list)
returns the first element of the specified list.
(car list)
evaluates the expression specified by the key.
(case condition (key value)*)
evaluates the expression and returns an error.
(catch expression)
returns the third and subsequent elements of the specified list.
(cddr list)
returns the second and subsequent elements of the specified list.
(cdr list)
concatenates the specified value and list into a list.
(cons first second)
creates and returns a contest
object.
(contest name host mail link start-day final-day dead-line)
performs division and returns a real value.
(/ real1 *reals)
performs identify test and returns a bool value.
(equal value1 value2)
performs equality test and returns a bool value.
(equal value1 value2)
evaluates the specified value.
(eval value)
formats a string using the specified arguments.
(format string *arguments)
performs greater-equal operation and returns a bool value.
(>= real1 *reals)
performs greater operation and returns a bool value.
(> real1 *reals)
evaluates the first (or second) expression if true (or false).
(if condition first second)
imports the specified class.
(import class)
creates and returns an anonymous closure.
(lambda (parameters) body)
performs less-equal operation and returns a bool value.
(<= real1 *reals)
returns the length of the list.
(length list)
creates a local variable and evaluates the expression.
(let variable value expression)
creates a list of elements as specified.
(list *elements)
loads the specified LISP file.
(load string)
performs less operation and returns a bool value.
(< real1 *reals)
tests if the list contains the specified value.
(member value list)
returns a method with the specified name.
(method 'name class *parameter-types)
returns a method with the specified name.
(method! 'name [class])
performs modulo and returns a real value.
(mod real1 *reals)
performs multiplication and returns a real value.
(* real1 *reals)
returns a qualified name in the specified namespace.
(name namespace local-name)
returns a constructor of the specified class.
(new class *parameter-types)
returns a constructor of the specified class.
(new! class)
tests if the argument is nil or not.
(nil? argument)
performs not operation and returns a bool value.
(not bool)
returns the n-th element of the list.
(nth index list)
tests if the argument is null or not.
(null? argument)
performs or operation and returns a bool value.
(or bool1 *bools)
creates and returns a pattern
object.
(pattern normalize transform cross-check)
evaluates the argument and print its value.
(print argument)
quotes the expression except for some unquoted sub-expressions.
(quasiquote expression)
returns the expression without evaluation.
(quote expression)
removes elements for which the specified function returns false.
(remove-if fun list)
takes four functions and returns a section
object.
(section name code cities verify unique entity result)
creates a variable with the specified name and value.
(set name value)
performs subtraction and returns a real value.
(- real1 *reals)
returns a subsequence of the specified list.
(subseq list start end)
returns a symbol with the specified name.
(symbol name)
creates and returns an anonymous macro.
(syntax (parameters) body)
throws an error with the specified message.
(throw string)
returns the type of the specified value.
(type value)
embeds the specified list elements into the outer expression.
(unquote-splicing list)
embeds the specified value into the outer expression.
(unquote value)
performs exclusive-or operation and returns a bool value.
(xor bool1 bool2)