13

私はclojureinstance?関数に少し混乱しています。単一の引数を取るのはとても幸せそうです。そう

(instance? String) 

正常に動作しますが、常に false を返します。

ここで何か不足していますか?私はこれを 2 日間で 2 回行いましたが、どちらの場合もデバッグにかなりの時間がかかりました (そうです、間違いを犯すと 1 回は不幸と見なされるかもしれませんが、2 回は不注意のように見えます)。

アリティエラーで壊れないのはなぜですか?

後で追加された注: Clojure 1.6 の時点で、これは修正されています。

http://dev.clojure.org/jira/browse/CLJ-1171

4

4 に答える 4

8

興味深い...instance?は で定義されていますが、フォーム用core.cljに特別な処理が組み込まれているようです。clojure.lang.Compiler(instance?)

Compiler.java、3498 行目:

    if(fexpr instanceof VarExpr && ((VarExpr)fexpr).var.equals(INSTANCE))
        {
        if(RT.second(form) instanceof Symbol)
            {
            Class c = HostExpr.maybeClass(RT.second(form),false);
            if(c != null)
                return new InstanceOfExpr(c, analyze(context, RT.third(form)));
            }
        }

これは、フォームをコンパイル/評価するときに、(instance?)で定義された関数core.cljが無視され、2 番目の引数の欠落を として解釈するハードワイヤードな動作が優先されることを意味すると解釈しnilます。これは、一種のインライン化として、パフォーマンス上の理由から行われていると思います。

どうやら、この特別な処理は特定の場合にのみ適用されるようです (そして、私はそれらが何であるかを知るほどコンパイラに精通していません)。Ankur の回答に示されているようにinstance?、で定義された関数を呼び出す方法がcore.cljあります。

于 2012-11-01T17:13:34.453 に答える
3

バグだと思います。instance? の新しいバージョンを定義する場合、たとえば

(def
^{:arglists '([^Class c x])
  :doc "Evaluates x and tests if it is an instance of the class
        c. Returns true or false"
  :added "1.0"}
foo? (fn foo? [^Class c x] (. c (isInstance x))))

予想される例外が発生します

user=> (foo? String "bar")
true
user=> (foo? String 1)
false
user=> (foo? String)
ArityException Wrong number of args (1) passed to: user$foo-QMARK-  clojure.lang.AFn.throwArity (AFn.java:437)
于 2012-11-01T15:48:43.867 に答える
2

うーん....興味深い...以下の呼び出しはすべて失敗します(これが想定されている方法です):

user=> (.invoke instance? String)
ArityException Wrong number of args (1) passed to: core$instance-QMARK-  clojure.lang.AFn.throwArity (AFn.java:437)

user=> (instance? (type ""))
ArityException Wrong number of args (1) passed to: core$instance-QMARK-  clojure.lang.AFn.throwArity (AFn.java:437)

user=> (apply instance? String [])
ArityException Wrong number of args (1) passed to: core$instance-QMARK-  clojure.lang.AFn.throwArity (AFn.java:437)

user=> (#'instance? Long)
ArityException Wrong number of args (1) passed to: core$instance-QMARK-  clojure.lang.AFn.throwArity (AFn.java:437)

"instance?" の新しいインスタンスを作成するイベント 関数オブジェクトは、機能するはずのとおりに機能します。

user=> (def a (.newInstance (aget (.getConstructors (type instance?)) 0) (into-array [])))
#'user/a
user=> (a String)
ArityException Wrong number of args (1) passed to: core$instance-QMARK-  clojure.lang.AFn.throwArity (AFn.java:437)
user=> (a String "")
true
于 2012-11-01T15:58:28.363 に答える
2

instance?コードを見ると、次のメソッドisInstanceClass呼び出されていることがわかります。

(def
    ^{:arglists '([^Class c x])
      :doc "Evaluates x and tests if it is an instance of the class
            c. Returns true or false"
      :added "1.0"}
    instance? (fn instance? [^Class c x] (. c (isInstance x))))

内部的にはnil(or false)xは、 に渡されたときにパラメータのデフォルト値と見なされ、isInstanceが返されますfalse

于 2012-11-01T12:43:12.800 に答える