7

私はClojureと関数型プログラミング全般にかなり慣れていないので、次の問題に苦労しています。一連のトークン(文字列)に一意で安定したインデックスを割り当てたいのですが。挿入よりもはるかに多くのルックアップがあるので、ハッシュマップが進むべき道のようでした。

Javaでは、私は次のように何かを書いていただろう

int last = 0; 
HashMap<String, Integer> lut = new HashMap<String, Integer>();

function Integer getIndex(String token) {
   Integer index = lut.get(token); 
   if(index == null) 
      last++;
      lut.put(token, last);
      return last;
    else { 
      return index;
    }
}

Clojureの音訳バージョンは次のようになります

(def last-index (atom 0))
(def lookup-table (atom {}))

(defn get-index [token]
  (if (nil? (get @lookup-table token))
    (do 
      (swap! last-index inc)
      (swap! lookup-table assoc token @last-index)
      @last-index)
    (get @lookup-table token)))

しかし、これは基本的に副作用であり、それを隠すことさえないので、あまり理想的ではないようです。

では、状態を維持するための2つの原子がなくても、これをどのように行うのでしょうか。

4

2 に答える 2

3

Ankurによって与えられた答えはスレッドセーフではありませんが、sehの理由の説明はあまり役に立たないと思いますし、彼の選択肢はもっと悪いです。「今は複数のスレッドについて心配していません」と言うのは理にかなっています。その場合、その答えは問題ありません。ただし、特定のインスタンスでその保証が必要ない場合でも、そのようなものを安全に記述できることは価値があります。安全な唯一の方法は、次のswap!ように、内部ですべてのロジックを実行することです。

(let [m (atom {})]
  (defn get-index [token]
    (get (swap! m
                #(assoc % token (or (% token) (count %))))
         token)))

swap!関数が呼び出されたときにエントリがすでに存在する場合はaを回避し、入力後にエントリがすでに存在する場合はassocを回避することで、これを少し高速化できますが、マップを「再確認」する必要swap!があります。割り当てる前に現在のトークンのエントリがありません。これは、開始する前(ただし、決定した後)に他のスレッドが侵入し、現在のトークンに値を割り当てた可能性があるためです。この場合、尊重する必要があります。新しい割り当てを作成する代わりに、その割り当て。(count %)swap!swap!

編集:余談ですが、Javaバージョンにはもちろん同じスレッドセーフの問題があります。これは、デフォルトではJavaのすべてが変更可能であり、スレッドセーフではないためです。少なくともClojureでは!、「はい、これは危険だとわかっています。自分が何をしているのか知っています」と言って、そこに入れる必要があります。

したがって、ある意味でAnkurのソリューションはJavaコードの完全な翻訳ですが、それを改善することはさらに良いことです。

于 2012-11-17T04:32:09.823 に答える
0

アトムの単一のマップで十分です:

(def m (atom {}))
;adding new string to map
(swap! m #(assoc %1 "Hello" (count %)))
;get an index
(@m "Hello")

(defn get-index [token] 
    (or (@m token) 
        ((swap! m #(assoc %1 token (count %))) token)))

あなたは基本的にJavaの命令型コードをclojureにマッピングしようとしましたが、それがあなたの質問でその解決策を得た理由です。段階的な命令型を考えるのではなく、表現を構成するという観点から考えるようにしてください。

于 2012-11-16T11:31:34.440 に答える