2016-10-08 15 views
1

私はClojureマップを使いこなしていましたが、私はこの状況を理解できませんでした。Clojureのマップと匿名関数を使用した例外

のは、私はこのようなマップだとしましょう:私は、このマップの値を変更したい

(def map-test {:name "head" :size 3}) 

を、Clojureの中で通常の方法が変更されたデータと新しいものを生成することです。

だから私はこの機能があります。{:name "head-1", :size 3}

だから私はこのように、ハッシュマップを所定の回数のクローンを作成するmapを使用してこの機能を書いた:呼び出しが(map-change map-test)戻り予想通り

(defn map-change 
    [part] 
    {:name (str (:name part) "-" 1) :size (:size part)}) 

{:name "head-1" ...}{:name "head-2" ...}{:name "head-3" ...}など:

(defn repeat-test 
    [part times] 
    (map #({:name (str (:name part) "-" %) :size (:size part)}) (range 1 (inc times)))) 

しかし、私は理解できない例外があります

Unhandled clojure.lang.ArityException 
    Wrong number of args (0) passed to: PersistentArrayMap 

        AFn.java: 429 clojure.lang.AFn/throwArity 
        AFn.java: 28 clojure.lang.AFn/invoke 
         REPL: 80 clj-lab-00.hobbits/repeat-test/fn 
        core.clj: 2644 clojure.core/map/fn 
       LazySeq.java: 40 clojure.lang.LazySeq/sval 
       LazySeq.java: 49 clojure.lang.LazySeq/seq 
        RT.java: 521 clojure.lang.RT/seq 
        core.clj: 137 clojure.core/seq 
      core_print.clj: 46 clojure.core/print-sequential 
      core_print.clj: 153 clojure.core/fn 
      core_print.clj: 153 clojure.core/fn 
       MultiFn.java: 233 clojure.lang.MultiFn/invoke 
        core.clj: 3572 clojure.core/pr-on 
        core.clj: 3575 clojure.core/pr 
        core.clj: 3575 clojure.core/pr 
        AFn.java: 154 clojure.lang.AFn/applyToHelper 
.... 

しかし:ここではスタックトレースの最後の部分だ(:size part)=>3

の評価を行った直後:sizeに値を代入されたときにデバッガがこの例外をスロー

Wrong number of args (0) passed to: PersistentArrayMap

:私は(repeat-test map-test 5)を呼び出します匿名の関数と同じ操作をする非匿名関数を使用すると、

(defn map-change 
    [part i] 
    {:name (str (:name part) "-" i) :size (:size part)}) 

(defn repeat-test 
    [part times] 
    (map #(map-change part %1) (range 1 (inc times)))) 

今や(repeat-test map-test 5)を呼び出します。どうして ?私は何が欠けていますか?

答えて

6

エラーは、この簡略化した例のようになります。

(map #({:a %}) [1 2 3]) 

clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentArrayMap 

あなたが実際にコンパイルされ、実行されているどのようなコードを参照する#({:a %})を展開することができます。つまり

(macroexpand '#({:a %})) 
;;=> (fn* [p1__21110#] ({:a p1__21110#})) 

#({:a %})が何かに展開します(fn [x] ({:a x}))のように。この関数の本体の問題は、マップが引数なしで関数として呼び出されることです。

マップは機能のように動作します。マップはそのキーの機能です。しかし、少なくとも1つの議論と2つ以下の議論を期待しています。

({:a 1} :a) ;;=> :a 
({:a 1} :b 2) ;;=> 2 

マップを関数として呼び出すつもりはありませんでした。あなたはマップを持っていただけです。無名関数リテラルは、常に関数呼び出しに展開され、直接値を生成することはできません。あなたはこのいくつかの方法を解決することができます。

  • #(-> {:a %})
  • #(identity {:a %})
  • #(hash-map :a %)
  • #(do {:a %})
  • (fn [x] {:a x})

私は最初のものは、かなり面白い発見が、私は、後者を好みます。それは私が指しているものを返すと言っているようです。

+1

オプションとして '#(do {:a%})'を追加します。 – OlegTheCat

+1

初心者のためのルールは '(fn [x] ...)'を使い、少なくともマクロを理解するまで '#()'形式を避けることです。 – Marcs

+0

@OlegTheCatそれも可能です。私はそれを加えた。さらに多くのオプションがあります: '#(と{:a%})'、 '#(または{:a%})' :-)。 @マックス私はこれが大雑把な経験だと思います。注意すべきもう1つの点:匿名関数リテラルは入れ子にできません。 –

関連する問題