11

Clojure では、関数fがある場合、

(defn f [& r] ... )

そして、 f を呼び出したい引数を持つseq argsがあるので、簡単にapplyを使用できます:

(apply f args)

ここで、別の関数gがあるとします。この関数は、多数のオプションの名前付き引数のいずれかを取るように設計されています。つまり、残りの引数はマップとして分解されます。

(defn g [& {:keys [a b] :as m}] ... )

私は通常、次のようなことで g を呼び出します

(g :a 1 :b 2)

しかし、たまたま値 {:a 1 :b 2} を持つマップmy-mapがあり、g を my-map に「適用」したい場合、つまり、上記の呼び出しのようになる何かを取得します。 、それから私は当然適用できませんでした。

(g [:a 1] [:b 2])

これを処理する良い方法はありますか?設計の軌道から外れて、これになってしまったのではないでしょうか? 私が見つけることができる最善の解決策は

(apply g (flatten (seq my-map)))

しかし、私は確かにそれが好きではありません。より良い解決策はありますか?

編集:提案された解決策に対するわずかな改善は、

(apply g (mapcat seq my-map))

これにより、少なくとも 1 つの関数呼び出しが削除されますが、何が起こっているのかはまだ明確ではない可能性があります。

4

4 に答える 4

6

私は自分でこの問題に遭遇し、1 つのマップを期待する関数を定義することになりました。マップには可変量のキーと値のペアを含めることができ、十分に柔軟であれば、 & 残りの引数は必要ありません。また、塗布しても痛みはありません。生活がずっと楽になります!

(defn g [{:keys [a b] :as m}] ... )
于 2013-05-02T20:46:12.640 に答える
3

seq に変換するより直接的な方法はありません。

これで完了です。あなたはできる限りのことをしました。

Common Lisp スタイルの :keyword arg 関数を使用することは、実際には不自然ではありません。Clojure コードを調べてみると、そのように記述された関数はほとんどないことがわかります。

偉大な RMS でさえ、それらのファンではありません。

「あまり好きではないことの 1 つは、キーワード引数 (8) です。それらは私にはあまり Lispy に見えません。時々そうしますが、そうする時間を最小限に抑えています。」(ソース

完全なハッシュ マップを断片に分割して、すべてをキーワード マップされた引数として渡す必要がある場合は、関数の設計に疑問を抱く必要があります。

一般的なオプションを渡したい場合は:consider-nil true、 hash-map で関数を呼び出すことはおそらくないでしょう{:consider-nil true}

ハッシュ マップのいくつかのキーに基づいて評価を行いたい場合、99% の確率でf ([m & args])宣言が行われます。

Clojure で関数を定義し始めたとき、同じ問題にぶつかりました。しかし、私が解決しようとした問題についてもっと考えてみると、関数宣言でデストラクタをほとんど使用していないことに気付きました。

于 2013-05-04T05:43:36.100 に答える
1

以下は、apply とまったく同じように使用できる非常に単純な関数ですが、最後の引数 (マップである必要があります) が :key1 val1 :key2 val2 などに展開されます。

(defn mapply
  [f & args]
  (apply f (reduce concat (butlast args) (last args))))

それを行うためのより効率的な方法があると確信しており、そのような関数を使用しなければならない状況に陥りたいかどうかは議論の余地がありますが、元の質問に答えます. ほとんどの場合、私は子供っぽい名前に満足しています...

于 2013-05-08T20:54:36.273 に答える
0

私が見つけた最も良い解決策:

(apply g (apply concat my-map))
于 2017-10-15T14:51:08.520 に答える