(rontolisp) docs

Function Namespace

rontolisp is a Lisp-2, following Common Lisp: functions and variables live in separate namespaces.

  • A bare symbol evaluates as a variable. Evaluating car alone is an error (The variable car is unbound in the interpreter; a compile error in the compilers).
  • A symbol in call position (f args...) resolves in the function namespace only. A variable named car never shadows the function car: (let ((car 5)) (car (list car 2))) returns 5.
  • A function becomes a value through #'name (reader syntax for (function name)), #'(lambda ...), or (symbol-function 'name). This works for built-in operators (#'+, #'car, #'1+, #'cadr), user defuns, and lambdas.
  • funcall/mapcar/reduce also accept a symbol naming a function (a function designator): (funcall 'car '(1 2)) returns 1. The compilers support this when the symbol is a quoted literal.
  • defun defines into the function namespace and returns the function name. (setq f (lambda ...)) binds a variable to a function value; call it with (funcall f ...), not (f ...).
  • #' of a macro or special operator (e.g. #'if, #'defun) is an error.

Function values can be passed as arguments, returned from functions, and stored in data structures in all three execution modes.

Higher-order functions:

Closures (capture by reference):

Lambda as argument:

Built-in operators as first-class values:

Built-in operators like +, car, 1+ can be passed to higher-order functions via #':

Compiler restrictions. In the JVM/WASM compilers, #'name resolves against the functions known at compile time (user defuns and built-in operators); #'mapcar, #'reduce, #'apply and #'funcall themselves are not available as values (#'mapcan and #'sort are). symbol-function requires a quoted symbol literal argument. In --dynamic mode an unresolved #'name is deferred to the runtime eval environment like any other unresolved reference. In compiled code apply/funcall dispatch by the actual argument count against a fixed-arity wrapper synthesized for each built-in operator. The naturally variadic operators -- +, -, *, /, list, min, max -- have variadic wrappers, so (funcall #'+ 1 2 3), (apply #'list ...) and the like accept any argument count. Every other multi-argument built-in keeps a fixed wrapper arity: #'cons, #'append, #'gcd and the comparison chains (#'<, #'=, ...) are binary, so applying them to a different count is unsupported on the compile path (matching the Compiled eval limitations); use a user-defined function or a lambda for other arities. The interpreter has no such restriction.