(rontolisp) docs

サポートされない Common Lisp の機能

rontolisp は意図的に小さくした Common Lisp のサブセットで、3 つのバックエンド (インタプリタ、JVM、WASM)で同一に動作します。ランタイムのメタオブジェクト プロトコルなしで言語をそのままのバイトコードにコンパイルできるよう保つため、 完全な Common Lisp の機能の多くが意図的に省かれています。

このページでは、特に目立つ省略事項を挙げます。利用できるものについては、 言語リファレンスを参照するか、実行時に rontolisp:list-special-formsrontolisp:list-macrosrontolisp:list-functions で一覧表示してください。

機能状況
defmacro(ユーザーマクロ)利用可能(defmacro 参照)
&optional / &rest / &key / &auxdefun/lambda で利用可能(defun を参照)。defmacro&rest/&body のみ
&whole利用不可
values / multiple-value-bind利用可能。ユーザ関数の多値も含む(multiple-value-bind を参照)
block / return-from / tagbody / go利用不可
catch / throw利用不可
unwind-protectインタープリタ/JVM で利用可能(unwind-protect 参照)。WASM ではコンパイルエラー
条件(define-conditionhandler-caseignore-errorssignalインタープリタ/JVM で利用可能(handler-case 参照)。捕捉は WASM ではコンパイルエラー。リスタート(handler-bind/restart-case)は利用不可
flet / labels利用可能(fletlabels 参照)
macrolet利用不可
loop(拡張版)一部対応(単純ループのサブセット)
defstruct利用可能(defstruct 参照)。オプション/:include は利用不可
CLOS一部対応(静的サブセット: defclassdefgenericdefmethodmake-instanceslot-value
declare / declaim / proclaim / the解析されるだけの no-op として利用可能(declare 参照)
check-type / assert利用可能(ライト版、リスタートなし。check-type 参照)
eval-when利用可能(progn として扱う。eval-when 参照)
typep利用不可
coerce部分対応(リテラルの 'list / 'vector / 'string 結果型。coerce を参照)
defpackage(ユーザーパッケージ)一部対応(:use/:export/:nicknames/:import-fromdefpackage 参照)
make-package / export / use-package(ランタイム)利用不可
#+ / #- / *features* / #\| ... \|#利用可能(データ型参照)
#. read 時評価 / #: の新規 uninterned シンボル利用不可(#. は read エラー、.asd ファイル内でのみ許容。#:name は普通のシンボルとして読まれ、designator として受理される)
require / provide利用可能(require 参照)。*modules* 変数は利用不可
let による動的(special)束縛利用可能(defvar/defparameter/declaim special が名前を special 宣言する。progv はインタプリタのみ)
複素数利用不可

ユーザー定義マクロ(defmacro

ユーザーマクロはサポートされています — バッククォートのテンプレート構文(ネストしたバッククォートを含む)や制限事項 (&whole/&environment 非対応、コンパイル済みプログラムの実行時 eval では 認識されない、など)を含む詳細は defmacro を参照してください。 組み込みマクロのセット(condcasewhenunlessdotimesdolistdosetfpushpopincf など)は (rontolisp:list-macros) で 一覧できます。これらの名前は再定義できません。

ラムダリストキーワード(&optional&rest&key&aux

defunlambda&optional&rest&key&allow-other-keys&aux をサポートします。詳細は defun を参照してください。残る制限は次のとおりです: &whole は利用できません。 defmacro のラムダリストは引き続き必須パラメータと末尾の &rest/&body 1 つのみを取ります。funcall/apply 経由の呼び出しでは関数の物理パラメータは 7 個までです。コンパイル済み eval がランタイムに構築する lambda は ラムダリストキーワードを解釈しません(コンパイル済み eval の制限 を参照)。

多値(valuesmultiple-value-bind

多値は利用可能です: valuesvalues-listmultiple-value-bindmultiple-value-listmultiple-value-callnth-value、および floor/ceiling/round/truncate(剰余)、gethash(present-p)、 parse-integer(パース停止位置)の副次値と floor ファミリのオプションの 除数引数です。ユーザ定義関数の結果位置にある (values ...) は内部 チャネルを通じて呼び出し側のコンシューマに届くため、CL の一般的なイディオムが 動作します:

> (defun two () (values 1 2))
> (multiple-value-bind (a b) (two) (list a b))
(1 2)

Common Lisp からの残る相違点は次のとおりです:

  • 末尾以外の位置で values を呼んでから通常の値を返すプロデューサは 古い余剰値を残すことがあるため、values は結果位置で使ってください。
  • funcall #'values(ファーストクラス値)はコンパイル済みプログラムでは 主値のみを返します。
  • 組み込みの #'name を渡した multiple-value-call はラッパーの固定 アリティのままです — それ以外の引数個数にはユーザ定義関数か lambda を 渡してください。
  • CL で副次値を持つ他の組み込み関数(read-from-stringmacroexpand-1intern など)は単一値のままです。

非局所脱出と制御フロー

名前付きブロックや任意のジャンプは利用できません。

  • block / return-from — 名前付きブロックはありません。唯一の非局所脱出は return で、これは do / do* / dolist / dotimes によって確立された 最も内側の反復ブロックから抜けます。
  • tagbody / go — ラベルとジャンプによる制御フローはありません。
  • catch / throw — 動的スコープの脱出はありません。
> (block done (return-from done 1) 2)
The function block is undefined

unwind-protect(あらゆる 脱出時 — 通常復帰・error 巻き戻し・return/return-from — の クリーンアップ)はインタープリタと JVM バックエンドで利用可能です。 WASM コンパイラは拒否します(WASM のエラーは捕捉不能なトラップのため)。

条件とリスタート

条件システムのコアは利用可能です: コンディション型は組み込み階層 (condition > serious-condition > errorwarning)の上の CLOS サブセットクラスで、define-condition:report 付き)で定義し、make-condition や型付きの error/signal designator で構築し、インタープリタと JVM バックエンドでは handler-case / ignore-errors により型で捕捉できます (WASM コンパイラは捕捉を拒否します: WASM のエラーは捕捉不能なトラップです)。

リスタートシステムは利用できません: handler-bindrestart-case (主フォームだけを残す no-op として受理)、restart-bindinvoke-restartwith-simple-restartcerrorabortcontinuebreak は存在せず、 check-type/assert は再格納リスタートを提供せずにエラーを通知します。

局所マクロ(macrolet

局所関数は利用可能です -- fletlabels を参照してください。局所マクロ (macrolet)は利用できません。マクロは defmacro によってトップレベルで のみ存在します。

loop マクロ

拡張版 loop の限定的なサブセットが 利用可能 です(loop を参照)。 数値/リストのステップ(for)、文字列のステップ(for ... across)、よく使う集約 (collectappendsumcountmaximizeminimize など)、単純な制御節 (while/untilrepeatwhen/unlessfinallyreturn)に対応します。 対象外は、分配束縛、for 節同士の並行 andbeing、アナフォリックな itnamed/loop-finishthereis/always/never です。その他の反復フォーム(dodolistdotimeswhile)も引き続き利用できます。

構造体とオブジェクト(defstruct、CLOS)

構造体は defstruct利用可能 です。キーワードコンストラクタ、述語、コピー関数、setf 可能なアクセサを 生成します。defstruct のオプション構文(:conc-name:constructor など)、 :include による継承、#S(...) の印字/読み取り構文はサポートされません。

静的な CLOS サブセットが利用可能です: defclass(単一継承、 :initarg/:initform/:reader/:accessor スロットオプション)、 make-instanceslot-value(どちらもリテラルのクォート された名前が必要)、そして第 1 引数でディスパッチする defgeneric / defmethodeql、クラス、組み込み 型の specializer)で、標準メソッド結合 — :before/:after/:around 修飾子、 call-next-methodnext-method-p(クラスメソッドとデフォルトメソッド向け)— も含みます。対象外: 多重継承、第 2 引数以降の specializer、slot-boundp、 MOP / 実行時クラス操作(find-classchange-classadd-method、クラス 再定義)— コンパイルされたプログラムのクラスとメソッドの集合はコンパイル時に 固定されます。

型宣言、typepcoerce

型宣言は解析されるだけの no-op として 受理されますdeclaredeclaimproclaimthe はいずれもパースされ、効果を持たないため、 型注釈付きのソースを変更なしにロードできます。 check-typeassert は実際のランタイム検査を提供します (ライト版、リスタートなし)。ランタイムヘルパーの typep は利用できません。 coerce はリテラルの結果型 'list'vector'string に限り 利用できます(結果型は map と同様、クォートされたリテラルで なければなりません)。その他の結果型はサポートされません。

ユーザー定義パッケージ

新しいパッケージは defpackage で 定義 できます。これは :use:export:nicknames:import-from の clause をサポートする、リテラルなトップレベルの read/コンパイル時 ディレクティブです(:documentation/:size は受理されるが無視されます。 パッケージを参照)。 :shadow:shadowing-import-from はエラーで(シンボルのシャドウイングは ありません)、ランタイム のパッケージ操作はありません: make-packageexportimportuse-packagefind-packagerename-package は利用できません。パッケージの export(external)シンボルの 集合は定義時に固定されます。シングル/ダブルコロンの修飾子(external シンボルには pkg:name、internal シンボルには pkg::name)は Common Lisp と同様に 機能します(パッケージを参照)。 標準ニックネーム common-lisp/common-lisp-usercl/cl-user に解決され、 #:name の designator も受理されます。 複数の使用先パッケージが同じ名前を export している場合、コンフリクトをシグナル する代わりに :use 順で最初のパッケージが優先されます。

動的(special)変数束縛

動的(special)変数束縛は サポートされていますdefvardefparameterdefconstant(および (declaim (special *x*)))は変数を special 宣言し、special な名前に対する let/let* は、レキシカルではなく 動的 束縛を確立します。 これはエクステント内で呼ばれた関数からも見え、脱出時に復元されます。

> (defvar *factor* 1)
> (defun scale (n) (* n *factor*))
> (let ((*factor* 10)) (scale 5))
50

束縛は制御のスレッドごとに保持されるため、並行する rontolisp:http-handler リクエストが互いの束縛を見ることはありません。コンパイル済み バックエンドに 限り、2 つの制限があります(インタプリタには影響しません)。実行時に計算される シンボルのリストを束縛する progv は インタプリタのみで、JVM/WASM ではコンパイルエラーになります。また special な let の境界を 越えて 脱出する return/return-from は、そこでグローバルを 復元しません(通常の脱出とエラーによる中断は問題ありません)。

数値タワー

rontolisp は整数(任意精度の bignum を含む)、比(1/3)、倍精度浮動小数点数を サポートしますが、複素数はサポートしません。負の数の平方根は、複素数の結果 ではなく浮動小数点の NaN を返します。

> (sqrt -1)
NaN      ; full Common Lisp would return #C(0.0 1.0)

その他の省略事項

symbol-macrolet は利用できず、progv はインタプリタのみです(JVM/WASM では コンパイルエラー)。eval-whenprogn として扱われ、利用できます。この一覧はすべてを網羅したものではありません。rontolisp は 完全な標準ではなく、焦点を絞ったコアを実装しています。