2

外側の let 式でバインドされたすべての変数を渡す関数を書いていることに気づきました。このシナリオを擬似コードで簡略化すると、次のようになります。

(let [a 1 b 2 c 3 d 4 e 5 f 6]
  (do-something a b c d)
  (f a b c d e f g)
  (compute-another-thing a c))

私はもっ​​と何かを書きたいのですが...

(let env-name [a 1 b 2 c 3 d 4 e 5 f 6]
   (do-something (take 4 env-name))
   (f env-name)
   (compute-another-thing a c))

つまり、clojure コア (または外部の信頼できるもの) は、letすべてのバインディングを名前付きのコレクションに集めるバリアントを提供しますか?

4

2 に答える 2

2

破壊すると、そこへの道のりの一部が得られます。

(let [[a b c d e f :as env-name] [1 2 3 4 5 6]]
   (apply do-something (take 4 env-name))
   (apply f env-name)
   (compute-another-thing a c))

env-name を使用して関数を呼び出す場合は、 applyを使用する必要があることに注意してください。

よりエレガントなもの (提案されたフォームなど) については、独自のマクロを作成する必要があると思います。

更新:単純なケースを処理できる(非常に軽くテストされた)マクロは次のとおりです。

(defmacro let-as 
  [as-bind-name bindings & body]
  (let [lhs-bindings (map first (partition 2 bindings))]
    `(let ~bindings
       (let [~as-bind-name [~@lhs-bindings]]
             ~@body))))

これは、通常の let バインディングの左側が単純なシンボルである (つまり、構造化を使用しない) 限り、目的どおりに動作するはずです。

説明するいくつかの REPL 相互作用:

core> (let-as env-name [a 1 b 2 c 3 d 4 e 5 f 6] (print env-name) (apply + env-name))
[1 2 3 4 5 6]
21

一部の破壊は行儀が良い:

core> (let-as env-name [[a b] [1 2] [c d] [3 4]] (print env-name) (map first env-name))
[[1 2] [3 4]]
(1 3)

その他の破壊は次のとおりではありません。

core> (let-as env-name [{:keys [a b]} {:a 1 :b 2}] (print env-name) (+ a b))
[{:keys [1 2]}]
3

これは修正できますが、マクロはより複雑にする必要があります

于 2014-08-25T19:31:57.903 に答える
1

ここではおそらく破壊が最善の解決策ですが、興味をそそるために、Fogus は彼のevalive プロジェクトに字句コンテキスト マクロを持っています。次のようになります。

(defmacro lexical-context
  []
  (let [symbols (keys &env)]
    (zipmap (map (fn [sym] `(quote ~sym))
                 symbols)
            symbols)))

(let [a 1]
  (let [b 2]
    (lexical-context))) ; => {a 1, b 2}

&envマクロで使用できる特別な変数を使用するため、別の形式のlet.

于 2014-08-26T08:29:35.513 に答える