関数名前空間
rontolispはCommon Lispに倣った Lisp-2 です。関数と変数は別々の名前空間に存在します。
- 裸のシンボルは 変数 として評価されます。
car単独の評価はエラーです(インタプリタではThe variable car is unbound、コンパイラではコンパイルエラー)。 - 呼び出し位置
(f args...)のシンボルは関数名前空間のみで解決されます。carという名前の変数が関数carをシャドウすることはありません。(let ((car 5)) (car (list car 2)))は5を返します。 - 関数は
#'name((function name)のリーダ構文)、#'(lambda ...)、(symbol-function 'name)を通じて 値 になります。これは組み込み演算子(#'+,#'car,#'1+,#'cadr)、ユーザ定義のdefun、ラムダで機能します。 funcall/mapcar/reduceは関数を指す シンボル(関数指定子)も受け付けます。(funcall 'car '(1 2))は1を返します。コンパイラはシンボルが引用されたリテラルである場合にこれをサポートします。defunは関数名前空間に定義し、関数名を返します。(setq f (lambda ...))は 変数 を関数値に束縛します。これは(f ...)ではなく(funcall f ...)で呼び出します。- マクロまたは特殊演算子の
#'(例:#'if,#'defun)はエラーです。
関数値は、3つの実行モードすべてで、引数として渡したり、関数から返したり、データ構造に格納したりできます。
高階関数:
クロージャ(参照によるキャプチャ):
引数としてのラムダ:
第一級の値としての組み込み演算子:
+, car, 1+ のような組み込み演算子は #' を通じて高階関数に渡せます:
コンパイラの制限。 JVM/WASMコンパイラでは、#'name
はコンパイル時に判明している関数(ユーザ定義の defun と組み込み演算子)に対して解決されます。#'mapcar、#'reduce、#'apply、#'funcall
自体は値として利用できません(#'mapcan と #'sort は利用できます)。symbol-function
は引用されたシンボルリテラルの引数を要求します。--dynamic モードでは、未解決の #'name
は他の未解決参照と同様にランタイムの eval 環境に委ねられます。コンパイルされたコードでは、apply/funcall
は各組み込み演算子のために合成された固定アリティのラッパーに対して、実際の引数の数でディスパッチします。本来可変長の演算子
-- +、-、*、/、list、min、max -- には可変長ラッパーがあるため、(funcall #'+ 1 2 3)、(apply #'list ...)
などは任意の引数の数を受け取ります。それ以外の複数引数の組み込みは固定アリティのラッパーのままです。#'cons、#'append、#'gcd
や比較チェイン(#'<、#'=、...)は 2 引数なので、異なる数に適用することはコンパイルパスではサポートされません(
コンパイルされた eval の制限
に一致します)。それ以外のアリティにはユーザ定義関数か lambda を使ってください。インタプリタにはそのような制限はありません。