(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), or a funcall of its name, signals undefined-function naming the operator, as an undefined function does, on every backend.

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). #'reduce and #'apply themselves are not available as values there (the interpreter has them); #'mapcar, #'mapcan, #'sort and #'funcall 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.

Redefining a COMMON-LISP function

(defun random ...), (defun length ...) and the like are undefined behavior in Common Lisp (CLHS 11.1.2.1.2), and rontolisp's backends genuinely differ:

  • the interpreter resolves the call through the function cell, so your definition runs;
  • the JVM and WASM compilers recognize the standard operator at the call site and compile it inline, so your definition does not run there. They print a compile-time warning naming the operator and the position of the first such call site, so the divergence is never silent.

#'random names your definition on every backend, which is why the warning says the definition is still reachable that way. To have one definition everywhere, give it a name of your own or shadow the symbol into a package of your own. A defmethod on a built-in name is a different case and does work on every backend: it becomes the generic's default method.