3

Clojure 標準ライブラリに次のような関数はありますか?

(fn [& args] args)

そうでない場合、なぜですか?

使用例:

(take 10 (apply (fn [& args] args) (range)))
;=> (0 1 2 3 4 5 6 7 8 9)

;; ironically, map isn't lazy enough, so let's take it up to 11
(defn lazy-map [f & colls]
  (lazy-seq (cons (apply f (map first colls))
                  (apply lazy-map f (map rest colls)))))

(defn transpose [m]
  (apply lazy-map (fn [& args] args) m))

(defn take-2d [rows cols coll]
  (take rows (map (partial take cols) coll)))

(take-2d 3 3 (transpose (map (partial iterate inc) (range))))
;=> ((0 1 2) (1 2 3) (2 3 4))

vectorまたはのような変形的で熱心な関数を求めているわけではないことに注意してくださいlist

4

2 に答える 2

3

そのような機能はありません。自由に実装して、好きなように使用してください。

(defn args [& args] args)

(set (map type (apply map args [[1 2 3][4 5 6][7 8 9]])))
=> #{clojure.lang.ArraySeq}

なぜまだ利用できないのですか?

これはめったに実りのない質問です: 実装者の心の中で何が起こっているのかを知らないだけでなく、彼らが何かをしなかった理由を正当化または文書化するよう依頼することは実際的ではありません. この機能を追加することは考えられていましたか? どうすれば知ることができますか?本当に理由があるのですか、それとも単に起こったのですか?

一方、args既存の不変シーケンスを通過するため、よりシンプルに感じることに同意します。倹約のためだけなら、そもそも引数を永続的なリストとして変換しないほうがよいと思われる場合も理解できます。

しかし、これは実装方法ではなく、使用のオーバーヘッドlistは本当に無視できます (また、 のインスタンスから構築する場合に特殊ArraySeq化されます)。インターフェイスにコーディングし、カーテンの後ろを決して見ないようにする必要があり、この観点からは、同じ結果が返されなくてもlist同等argsです

怠惰についてのコメントを追加しましたが、そのとおりです。可変引数関数から引数を取得し、シーケンスで動作する関数に渡す必要がある場合、 のバージョンlistは指定されたすべての引数を消費しますが、消費しargsません。場合によっては、(apply list (range))文字通り無限の数の引数を渡す のように、永久にハングアップする可能性があります。

その観点から、この小さなargs関数は興味深いものです。潜在的な問題を引き起こすことなく、引数から実際のシーケンスに移行できます。ただし、このケースが実際にどのくらいの頻度で発生するかはわかりません。実際、引数リストの遅延が問題となるユースケースを見つけるのに苦労していargsます。結局のところ、無限のシーケンスを渡すには、apply を使用する (?) しか方法がありません。

(apply f (infinite))

のユースケースを持つためにはargs、引数リストから単一のリストに変換して、別の関数gが次のようにシーケンスとして使用できるようにする必要があることを意味します。

(g (apply args (infinite)))

しかし、その場合、直接呼び出すことができます:

(g (infinite))

あなたの例では、 insidegを表しますが、入力で指定されているため、直接書き込むことはできません。したがって、この例は の真の使用例のように見えますが、指定したスニペットが非常に複雑であるため、関数を詳しく文書化する必要があります。私は、関数に無制限の数の引数を与えることはコードのにおいだと考える傾向があります:与えられたシーケンスが実際には無限である可能性があるため、シグネチャを持つすべての関数はすべての引数を消費することを避けるべきでしょうか? 意図を明確にするために、引数リスト全体ではなく、単一の引数をこの種の使用法 (および必要に応じて渡す) の遅延シーケンスにすることをお勧めします。しかし、結局のところ、私はどちらの使用にも強く反対しているわけではありません。conslazy-mapf(cons (map ...) ...)args[& args]lazy-mapidentityargs

結論として、Rich Hickey にコア関数として追加するよう説得できない限り、argsこれだけを行う外部ライブラリに依存したいと思う人はほとんどいないと確信しています1。 . 唯一の報酬は、ほとんどの場合費用がかからない小さな変換ステップをスキップできることを知ることです. 同様に、ベクターとリストのどちらを選択する必要があるかについて心配する必要はありません。実際にはコードに影響を与えず、必要であることが証明できれば後でコードを変更できます。怠惰に関しては、リストまたはベクトルで引数をラップすると、無制限の引数リストで問題が発生する可能性があることに同意しますが、実際に問題が実際に発生するかどうかはわかりません。


1 . もちろん、それが に到達した場合clojure.core、誰もがすぐにそれが最も有用で間違いなく慣用的な基本的な操作であると言うでしょう</cynic>

于 2015-11-24T10:43:12.983 に答える
1

機能がありidentityます。引数を取り、その引数を返すだけです。ただし、 Clojureidentityは単一のアリティです。

利用方法:

(identity 4) ;=> 4

(identity [1 2 3 4]) ;=> [1 2 3 4]

Clojure 関数は 1 つの値しか返さないため、可変アリティを持つ ID 関数を使用する意味はあまりないと思います。関数から複数の値を返したい場合は、後で分解できる seq でそれらをラップできます。その場合、次のようなものを使用できます。

(defn varity-identity [& args]
    (map identity args))

(varity-identity 1 2 3 4 5) ;=> (1 2 3 4 5)

お役に立てれば。

于 2015-11-23T22:54:42.247 に答える