web-dev-qa-db-ja.com

ClojureでForループを実装する方法

この小さなコードをClojureに実装したいのですが、苦労しています。

struct mystruct {
   int id;
   int price;
};

mystruct mydata[10];

for (int i=0; i<10; i++) {
  myfunction(mydata[i].id, mydata[i].price);
  //other things...
}

私はClojureの初心者であり、このような単純なことを実行するのは本当に複雑ですが、refを使用するなど、Clojureには大きな利点があることを知っているので、できるだけ多くのことを学ぼうとしています...

誰かが私を助けてくれれば本当にありがたいです。ありがとう!!

27
nuvio

命令型forループをClojureに変換する1つの方法は、forマクロを使用することです。

(for [i (range 10)] (inc i))

上記の関数は、0から9までのすべての数値を1ずつ増加させて返します。ただし、シーケンシャルコレクションを反復処理して各項目を使用したいだけのようです。これで十分な場合は、インデックス値を参照する必要はなく、代わりに各アイテムを直接参照できます。

(for [d my-vec-of-data] (my-function d))

ただし、この単純なケースでは、map関数は、コレクションからの引数を使用して関数を呼び出すように設計されているため、おそらくより良い選択です。次の例は、上記のforの使用と同等です。

(map my-function my-vec-of-data)

mapforはどちらも、my-functionから返された値で構成される値のコレクションを返します。これは、Clojureのデータ構造が不変であるため、新しいコレクションを返す必要があるためです。それが必要なものでない場合、または関数に副作用がある場合は、doseqの代わりにforを使用できます。これにより、nilが返されます。

37
Jeremy

Jeremyの答えは、慣用的なClojureでforループを実行する方法に適しています。

Clojureで命令スタイルのforループが本当に必要な場合は、次のマクロを使用してforループを作成できます。

(defmacro for-loop [[sym init check change :as params] & steps]
 `(loop [~sym ~init value# nil]
    (if ~check
      (let [new-value# (do ~@steps)]
        (recur ~change new-value#))
      value#)))

次のように使用:

(for-loop [i 0 (< i 10) (inc i)] 
  (println i))
34
mikera