7

mapcatをよりよく理解するために、例を挙げました。

user>  (mapcat #(list % %) [1 2 3])
(1 1 2 2 3 3)

そして、意図的にmapconcatを使用して、ドキュメントの説明を再現しようとしました:

user> (doc mapcat)
clojure.core/mapcat
([f & colls])
  Returns the result of applying concat to the result of applying map
  to f and colls.  Thus function f should return a collection.

これを行うことにより:

user>  (concat (map #(list % %) [1 2 3]))
((1 1) (2 2) (3 3))

ただし、ご覧のとおり、機能しません。ただし、次のように reduce を使用できますが、それが正しいかどうかはわかりません。

user>  (reduce #(concat %1 %2) (map #(vec (list % %)) [1 2 3]))
(1 1 2 2 3 3)

上記は機能しますが、mapconcatを使用してmapcatが行うことを再作成する正しい方法であるかどうかはわかりません。

基本的に、 mapcatが内部で動作することを理解したいと思います。

どうすればmapcatのソースにアクセスできますか? (私は Emacs + nrepl を使用しています)

4

2 に答える 2

6
user=> (source mapcat)
(defn mapcat
  "Returns the result of applying concat to the result of applying map
  to f and colls.  Thus function f should return a collection."
  {:added "1.0"}
  [f & colls]
    (apply concat (apply map f colls)))
nil
user=> 

その理由reduceも効果的です。

(concat (concat '(1 1) '(2 2)) '(3 3))

applyは、ソース コードで使用されているように、次のように展開されます。

(concat '(1 1) '(2 2) '(3 3))

あなたの最初の試みでconcat

  user=> (map #(list % %) [1 2 3])
  ((1 1) (2 2) (3 3))
  user=> (concat (list '(1 1) '(2 2) '(3 3)))
  ((1 1) (2 2) (3 3))
  user=> (concat [1])
  (1)

concat単一の引数で呼び出すと、その引数が返されることがわかります。

于 2012-11-05T01:22:57.377 に答える
2

concat可変長関数です。つまり、各パラメータが値のシーケンスである n 個のパラメータを取ることができます。つまり、シグネチャは になり(defn concat [& lst]])ます。あなたの例では、concatが連結される値のseqのseqを取ると仮定して、単一の引数でconcatを呼び出していますが、それが結果を得る理由です。つまり、リストの同じリストが返されます。

(apply concat(apply map #(list % %) [1 2]))動作しません。

(apply map #(list % %) [[1 2]])または(apply map #(list % %) [1 2] [])動作します。

これは、apply が最後のパラメーターが一連の値であると想定し、その一連の値の各項目がパラメーターとして適用された関数に渡されるためです。適用が失敗した場合、呼び出しは(map #(list % %) 1 2)どちらが間違っているかに展開され、エラーメッセージには、マップがパラメーターとしてシーケンスを必要とするため、ロングをシーケンスに変換できないことも示されます。

于 2012-11-05T04:21:20.383 に答える