関数の代わりにVarを使用するのはいつですか?

モーレックス

私はclojureWeb開発ブックを読んでいますが、関数は動的に変化するため、関数自体ではなくハンドラー(以下で定義)のvarオブジェクトを渡すように指示されています(これがwrap-reloadの機能です)。

本は言う:

「このミドルウェアが機能するためには、ハンドラーからvarを作成する必要があることに注意してください。これは、現在のハンドラー関数を含むVarオブジェクトが返されるようにするために必要です。代わりにハンドラーを使用した場合、アプリは関数の元の値と変更は反映されません。」これが何を意味するのかよくわかりません。varsはcポインターに似ていますか?

(ns ring-app.core
  (:require [ring.adapter.jetty :as jetty]
            [ring.util.response :as response]
            [ring.middleware.reload :refer [wrap-reload]]))

(defn handler [request]
  (response/response
   (str "<html>/<body> your IP is: " (:remote-addr request)
        "</body></html>")))

(defn wrap-nocache [handler]
  (fn [request]
    (-> request
        handler
        (assoc-in [:headers "Pragma"] "no-cache"))))

ハンドラーの呼び出しは次のとおりです。

(defn -main []
  (jetty/run-jetty
   (wrap-reload (wrap-nocache  (var handler)))
   {:port 3001
    :join? false}))
アラン・トンプソン

はい、ClojureのVarはCポインターに似ています。これは十分に文書化されていません。

fred次のように関数を作成するとします

(defn fred [x] (+ x 1))

ここには実際に3つのことがあります。まず、fredシンボルです。記号fred(引用符なし)とキーワード:fred(先頭の:文字でマーク)および文字列"fred"(両端が二重引用符でマーク)には違いがあります。Clojureにとって、それぞれは4文字で構成されています。つまり、キーワードのコロンも文字列の二重引用符も、長さや構成に含まれていません。

> (name 'fred)
"fred"
> (name :fred)
"fred"
> (name "fred")
"fred"

唯一の違いは、それらがどのように解釈されるかです。文字列は、あらゆる種類のユーザーデータを表すことを目的としています。キーワードは、プログラムの制御情報を読み取り可能な形式で表すことを目的としています(1 =左、2 =右などの「マジックナンバー」とは対照的に、キーワード:leftとを使用:rightます。

シンボルは、JavaやCの場合と同じように、物事を指すことを意味します。

(let [x 1
      y (+ x 1) ]
  (println y))
;=> 2

次にx、値1をyポイントし、値2をポイントすると、結果が出力されます。

(def ...)フォームが導入不可視第三元素、VARを。だから私たちが言うなら

(def wilma 3)

考慮すべき3つのオブジェクトがあります。wilmaは記号であり、を指しvar、次に値を指します3プログラムがシンボルwilma遭遇すると、を見つけるために評価されますvar同様に、varは値3を生成するために評価されます。つまり、Cのポインターの2レベルの間接参照のようなものです。シンボルvarの両方が「自動評価」されるため、これは自動的かつ目に見えない形で発生します。 varについて考える必要があります(実際、ほとんどの人は目に見えない中間ステップが存在することにさえ気づいていません)。

fred上記の関数の場合、var。のような(fn [x] (+ x 1))値ではなく無名関数を指すことを除いて、同様の状況が存在3wilmaます。

varの自動評価を次のように「短絡」させることができます。

> (var wilma)
#'clj.core/wilma

または

> #'wilma
#'clj.core/wilma

ここで、リーダーマクロ#'(ポンドクォート)は、(var ...)特別なフォームを呼び出す簡単な方法ですのような特殊な形式varは、ifまたはのようなコンパイラ組み込みdefであり、通常の関数と同じでないことに注意してくださいvar特殊な形態は、シンボルに取り付けVarのオブジェクトを返しますwilmaclojure REPLVarは同じ省略形を使用しオブジェクトを印刷するため、両方の結果は同じように見えます。

私たちが持っていたらVar、オブジェクトを、自動評価が無効になっています:

> (println (var wilma))
#'clj.core/wilma

wilma指す値を取得する場合は、次を使用する必要がありますvar-get

> (var-get (var wilma))
3
> (var-get    #'wilma)
3

同じことがフレッドにも当てはまります。

> (var-get #'fred)
#object[clj.core$fred 0x599adf07 "clj.core$fred@599adf07"]
> (var-get (var fred))
#object[clj.core$fred 0x599adf07 "clj.core$fred@599adf07"]

ここで、#object[clj.core$fred ...]Clojureが関数オブジェクトを文字列として表現する方法です。

Webサーバーに関しては、var?関数を介して、または指定された値がハンドラー関数であるか、ハンドラー関数を指すvarであるかを判別できます。

次のように入力した場合:

(jetty/run-jetty handler)

二重自動評価により、ハンドラー関数オブジェクトが生成され、これがに渡されrun-jettyます。代わりに、次のように入力した場合:

(jetty/run-jetty (var handler))

次に、Varハンドラー関数オブジェクトを指すwhichがに渡されrun-jettyます。次に、ステートメントまたは同等のものrun-jettyを使用して、if受信したものを判別し、関数の代わりに(var-get ...)受信した場合は呼び出す必要Varがあります。したがって、毎回(var-get ...)Var現在ポイントしているオブジェクトが返されますしたがって、VarCのグローバルポインタ、またはJavaのグローバル「参照」変数のように機能します。

関数オブジェクトをに渡すと、関数オブジェクトへrun-jettyの「ローカルポインタ」が保存され、外部ポインタがローカルポインタの参照先を変更する方法はありません。

詳細については、こちらをご覧ください。


更新

OlegTheCat尖ったアウトを持って、Clojureのはまだヴァールについてその袖まで別のトリックはClojureの機能をポイントするオブジェクトを持っています。単純な関数を考えてみましょう。

(defn add-3 [x] (+ x 3))
; `add-3` is a global symbol that points to
;     a Var object, that points to
;         a function object.

(dotest
  (let [add-3-fn  add-3           ; a local pointer to the fn object
        add-3-var (var add-3)]    ; a local pointer to the Var object
    (is= 42 (add-3 39))           ; double deref from global symbol to fn object
    (is= 42 (add-3-fn 39))        ; single deref from local  symbol to fn object
    (is= 42 (add-3-var 39)))      ; use the Var object as a function 
                                  ;   => SILENT deref to fn object

Varオブジェクトを関数として扱う場合、Clojureはそれを関数オブジェクトにサイレントにデリファレンスし、指定された引数を使用してその関数オブジェクトを呼び出します。我々は3つのすべてのことを見てadd-3add-3-fnそしてadd-3-var動作します。これがJettyで起こっていることです。関数ではなくVarオブジェクトを指定したことに気付くことはありませんが、Clojureは、通知せずにその不一致を魔法のように修正します。

サイドバー:私たちの「桟橋」が実際にClojureのラッパーコードであるので、これはのみ動作しますのでご注意くださいring.adapter.jetty、とない実際の桟橋ウェブサーバのJavaClojureラッパーの代わりに実際のJava関数を使用してこのトリックに依存しようとすると、失敗します。実際、proxyClojure関数をJavaコードに渡すには、のようなClojureラッパーを使用する必要があります。

Varオブジェクトを関数以外のものとして使用する場合、あなたを救うような守​​護天使はありません。

  (let [wilma-long  wilma         ; a local pointer to the long object
        wilma-var   (var wilma)]  ; a local pointer to the Var object
    (is (int? wilma-long))        ; it is a Long integer object
    (is (var? wilma-var))         ; it is a Var object

    (is= 4 (inc wilma))          ; double deref from global symbol to Long object
    (is= 4 (inc wilma-long))     ; single deref from local  symbol to Long object
    (throws? (inc wilma-var))))  ; Var object used as arg => WILL NOT deref to Long object

したがって、関数を期待していて、誰かが関数を指すVarオブジェクトを提供した場合、Clojureがサイレントに問題を修正するので、問題ありません。関数以外のものを期待していて、誰かがそのことを指すVarオブジェクトを提供した場合、あなたはあなた自身です。

このヘルパー関数について考えてみましょう。

(defn unvar
  "When passed a clojure var-object, returns the referenced value (via deref/var-get);
  else returns arg unchanged. Idempotent to multiple calls."
  [value-or-var]
  (if (var? value-or-var)
    (deref value-or-var) ; or var-get
    value-or-var))

これで、与えられたものを安全に使用できます。

(is= 42 (+ 39 (unvar wilma))
        (+ 39 (unvar wilma-long))
        (+ 39 (unvar wilma-var)))

付録

あることに注意してください3個の問題を混同することができ二重性は:

  • どちらvar-getderefClojureのと同じことを行いますVar
  • リーダーマクロ#'xxxはに翻訳されます(var xxx)
  • リーダーマクロ@xxxはに翻訳されます(deref xxx)

したがって、(紛らわしいことに!)同じことを行う方法はたくさんあります。

(ns tst.demo.core
  (:use tupelo.core tupelo.test))

(def wilma 3)
; `wilma` is a global symbol that points to
;     a Var object, that points to
;         a java.lang.Long object of value `3`

(dotest
  (is= java.lang.Long (type wilma))

  (is= 3 (var-get (var wilma)))
  (is= 3 (var-get #'wilma))

  ; `deref` and `var-get` are interchangable
  (is= 3 (deref (var wilma)))
  (is= 3 (deref #'wilma))

  ; the reader macro `@xxx` is a shortcut that translates to `(deref xxx)`
  (is= 3 @(var wilma))
  (is= 3 @#'wilma)) ; Don't do this - it's an abuse of reader macros.

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

C ++で関数ポインタの代わりに関数参照を使用するのはいつですか?

分類Dev

Z3で変数の代わりに関数を使用する必要があるのはいつですか?

分類Dev

関数の代わりに#definemacro(x)を使用するのはいつ、なぜですか?

分類Dev

Swift:「let」の代わりに「var」を使用する必要があるのはいつですか?

分類Dev

LESS関数の代わりにCSS関数を使用するにはどうすればよいですか?

分類Dev

getHoursの代わりにこの関数でgetMinutesを使用するにはどうすればよいですか?

分類Dev

HashMapの代わりにAndroidのArrayMapを使用するのはいつですか?

分類Dev

Kotlinの演算子を使用する代わりに、プラス、マイナス、回の関数を使用する必要があるのはいつですか?

分類Dev

Pythonでは%sの代わりに%rをいつ使用するのですか?

分類Dev

onChangeの代わりにonClickで関数を使用するにはどうすればよいですか?

分類Dev

open関数でshの代わりにbashを使用するにはどうすればよいですか?

分類Dev

ADCXの代わりにADOXを使用するのはいつですか?

分類Dev

`reshape(-1)`の代わりに `flatten()`を使用するのはいつですか?

分類Dev

grepの代わりにegrepを使用するのはいつですか?

分類Dev

setfの代わりにdefparameterを使用するのはいつですか?

分類Dev

mapcarの代わりにmapcを使用するのはいつですか?

分類Dev

JSON の代わりに JSON[] を使用するのはいつですか?

分類Dev

結合関数の代わりにforeachを使用するにはどうすればよいですか?

分類Dev

10進数の代わりにdoubleを使用する必要があるのはいつですか?

分類Dev

React状態変数の代わりにMobXobservableを使用する必要があるのはいつですか?

分類Dev

Kotlinでreturnの代わりにrun関数を使用することは良い習慣ですか?

分類Dev

javascriptでletの代わりにvarを使用する理由は何ですか?

分類Dev

SQL Server 2008で関数の代わりにストアドプロシージャを使用する必要があるのはいつですか?

分類Dev

typeofsomething!== "undefined"の代わりに短いヘルパー関数を使用することは可能ですか?

分類Dev

関数の代わりにサブプロシージャを使用するのが適切なのはいつですか?

分類Dev

array_udiffが述語関数の代わりに比較関数を使用するのはなぜですか?

分類Dev

リスト内包表記の代わりにフィルター関数を使用するのはいつですか?

分類Dev

要素の代わりに関数でいっぱいのnumpy配列を作成する方法はありますか?

分類Dev

PHPでvar値の代わりにvar名を出力するにはどうすればよいですか?

Related 関連記事

  1. 1

    C ++で関数ポインタの代わりに関数参照を使用するのはいつですか?

  2. 2

    Z3で変数の代わりに関数を使用する必要があるのはいつですか?

  3. 3

    関数の代わりに#definemacro(x)を使用するのはいつ、なぜですか?

  4. 4

    Swift:「let」の代わりに「var」を使用する必要があるのはいつですか?

  5. 5

    LESS関数の代わりにCSS関数を使用するにはどうすればよいですか?

  6. 6

    getHoursの代わりにこの関数でgetMinutesを使用するにはどうすればよいですか?

  7. 7

    HashMapの代わりにAndroidのArrayMapを使用するのはいつですか?

  8. 8

    Kotlinの演算子を使用する代わりに、プラス、マイナス、回の関数を使用する必要があるのはいつですか?

  9. 9

    Pythonでは%sの代わりに%rをいつ使用するのですか?

  10. 10

    onChangeの代わりにonClickで関数を使用するにはどうすればよいですか?

  11. 11

    open関数でshの代わりにbashを使用するにはどうすればよいですか?

  12. 12

    ADCXの代わりにADOXを使用するのはいつですか?

  13. 13

    `reshape(-1)`の代わりに `flatten()`を使用するのはいつですか?

  14. 14

    grepの代わりにegrepを使用するのはいつですか?

  15. 15

    setfの代わりにdefparameterを使用するのはいつですか?

  16. 16

    mapcarの代わりにmapcを使用するのはいつですか?

  17. 17

    JSON の代わりに JSON[] を使用するのはいつですか?

  18. 18

    結合関数の代わりにforeachを使用するにはどうすればよいですか?

  19. 19

    10進数の代わりにdoubleを使用する必要があるのはいつですか?

  20. 20

    React状態変数の代わりにMobXobservableを使用する必要があるのはいつですか?

  21. 21

    Kotlinでreturnの代わりにrun関数を使用することは良い習慣ですか?

  22. 22

    javascriptでletの代わりにvarを使用する理由は何ですか?

  23. 23

    SQL Server 2008で関数の代わりにストアドプロシージャを使用する必要があるのはいつですか?

  24. 24

    typeofsomething!== "undefined"の代わりに短いヘルパー関数を使用することは可能ですか?

  25. 25

    関数の代わりにサブプロシージャを使用するのが適切なのはいつですか?

  26. 26

    array_udiffが述語関数の代わりに比較関数を使用するのはなぜですか?

  27. 27

    リスト内包表記の代わりにフィルター関数を使用するのはいつですか?

  28. 28

    要素の代わりに関数でいっぱいのnumpy配列を作成する方法はありますか?

  29. 29

    PHPでvar値の代わりにvar名を出力するにはどうすればよいですか?

ホットタグ

アーカイブ