emacs lispには、メモリアドレスなどの一意のオブジェクト識別子を提供する関数がありますか? Python にはid()
、現在存在するオブジェクト間で一意であることが保証された整数を返す があります。エリスプはどうですか?
3 に答える
関数 likeid()
が必要な唯一の理由は、オブジェクトを比較し、それらが同じ場合 (同じメモリ位置にある場合など) にのみ等しいことを確認することです。Lisp では、これは Python とは少し異なります。
elisp を含むほとんどの Lisp には、等価性のいくつかの異なる概念があります。最も高価で、最も弱い同等物はequal
です。2 つのリスト (たとえば) が同じ要素を持っていれば等しい ( で再帰的にテストされる) ため、これはあなたが望むものではありませんequal
。そのような
(equal (list 1 2) (list 1 2)) => T
本当です。スペクトルの反対側にある はeq
、同等性ではなく「同一性」をテストします。
(eq (list 1 2) (list 1 2)) => NIL
これはあなたが望むものだと思います。
したがって、Python は 1 つの等価テストを提供し、次に各オブジェクトのメモリ位置を提供する関数を提供することで機能しているようです。これは整数として比較できます。一方、Elisp (および少なくとも Common Lisp も) では、「平等」には複数の意味があります。
2つの間のどこかにある「eql」もあることに注意してください。
eq
(編集:私の最初の答えは、元のポスターが抱えていた問題をおそらく との区別がequal
解決する理由について十分に明確ではなかったでしょう)
質問をする上での私の全体的なポイントは、同じ名前を持つ異なるシンボルの印刷された表現を区別する方法を探していたということでした。elispマニュアルのおかげで、変数を発見しました。これがprint-gensym
ない場合、印刷されたインターンされていない記号の前に変数が追加されます。さらに、同じ呼び出しで同じ非インターンシンボルが複数回印刷される場合、最初のシンボルは `#N#でマークされ、後続のシンボルは`#N#でマークされます。これはまさに私が探していた種類の機能です。例えば:nil
#:
print
#N=
(setq print-gensym t)
==> t
(make-symbol "foo")
==> #:foo
(setq a (make-symbol "foo"))
==> #:foo
(cons a a)
==> (#1=#:foo . #1#)
(setq b (make-symbol "foo"))
==> #:foo
(cons a b)
==> (#:foo . #:foo)
#:
表記は次の場合read
にも機能します。
(setq a '#:foo)
==> #:foo
(symbol-name a)
==> "foo"
'
オンに注意して'#:foo
ください-#:
表記は記号文字です。がない'
場合、インターンされていないシンボルが評価されます。
(symbol-name '#:foo)
==> "foo"
(symbol-name #:foo)
==> (void-variable #:foo)
私の知る限り、Emacs Lisp にはそのような機能はありません。等しいかどうかだけが必要な場合は、 を使用しますeq
。これは、舞台裏でポインター比較を実行します。印刷可能な一意の識別子が必要な場合は、パッケージgensym
から使用してください。cl
データ構造のインデックスとして機能する一意の識別子が必要な場合は、を使用しますgensym
(または独自の一意の ID を維持します —gensym
より簡単でエラーが発生しにくくなります)。
一部の言語では、一意の ID をすべてのオブジェクトに焼き付けますが、これにはコストがかかります。すべてのオブジェクトが ID を格納するために余分なメモリを必要とするか、ID がオブジェクトのアドレスから派生するため、アドレスを変更できなくなります。Python はコストを支払うことを選択し、Emacs は支払わないことを選択します。