2

CommonLispで次のことができることを私は知っています:

CL-USER> (let ((my-list nil))
       (dotimes (i 5)
         (setf my-list (cons i my-list)))
       my-list)
(4 3 2 1 0)

Clojureでこれを行うにはどうすればよいですか?特に、Clojureにsetfを持たずにこれを行うにはどうすればよいですか?

4

7 に答える 7

8

CommonLispであなたがしていることの私の個人的な翻訳はClojurewiseになります:

(into (list) (range 5))

その結果:

(4 3 2 1 0)

少し説明:

この関数intoは、すべての要素をコレクションに結合します。(list)ここでは、他のコレクション(ここでは範囲)から作成された新しいリストです0 .. 4。の動作はconjデータ構造ごとに異なります。リストの場合、は次のようにconj動作しconsます。リストの先頭に要素を配置し、それを新しいリストとして返します。だから何がこれです:

(cons 4 (cons 3 (cons 2 (cons 1 (cons 0 (list))))))

これは、CommonLispで行っていることと似ています。Clojureの違いは、1つのリストを変更するのではなく、常に新しいリストを返すことです。ミューテーションは、Clojureで本当に必要な場合にのみ使用されます。

もちろん、このリストをすぐに入手することもできますが、これはおそらくあなたが知りたかったことではありません。

(range 4 -1 -1)

また

(reverse (range 5))

または...私が思いつくことができる最短のバージョン:

'(4 3 2 1 0)

;-)。

于 2011-12-17T11:32:02.107 に答える
7

Clojureでこれを行う方法は、それを行わないことです。Clojureは可変状態を嫌います(利用可能ですが、あらゆる小さなことに使用することはお勧めしません)。代わりに、パターンに注意してください。実際にコンピューティングを行っています(cons 4 (cons 3 (cons 2 (cons 1 (cons 0 nil)))))。これは、リデュース(または必要に応じてフォールド)に非常によく似ています。だから(reduce (fn [acc x] (cons x acc)) nil (range 5))、、それはあなたが探していた答えをもたらします。

于 2011-12-17T00:09:09.750 に答える
3

Clojureは、スレッドセーフのためにローカル変数の変更を禁止していますが、変更がなくてもループを作成することは可能です。ループの実行ごとにmy-list異なる値を設定する必要がありますが、これは再帰を使用して実現することもできます。

(let [step (fn [i my-list]
             (if (< i 5)
               my-list
               (recur (inc i) (cons i my-list))))]
  (step 0 nil))

Clojureには、新しい関数、つまりを作成せずに「ループを実行する」方法もありますloop。のように見えletますが、本体の先頭にジャンプしてバインディングを更新し、。を使用して本体を再度実行することもできますrecur

(loop [i 0
       my-list nil]
  (if (< i 5)
    my-list
    (recur (inc i) (cons i my-list))))

再帰的な末尾呼び出しを使用した「更新」パラメーターは、変数の変更と非常によく似ていますが、重要な違いが1つありmy-listます。Clojureコードを入力すると、その意味は常に。の値になりmy-listます。入れ子関数が閉じてmy-listループが次の反復に続く場合、入れ子関数は常にmy-list入れ子関数が作成されたときに持っていた値を参照します。ローカル変数はいつでもその値に置き換えることができ、再帰呼び出しを行った後に持っている変数は、ある意味で別の変数です。

(Clojureコンパイラーは、この「新しい変数」に余分なスペースが必要ないように最適化を実行します。変数を記憶する必要がある場合、その値がコピーされ、recur呼び出された場合、古い変数が再利用されます。)

于 2011-12-19T16:10:52.577 に答える
2

このためrangeに、手動で設定した手順で使用します。

(range 4 (dec 0) -1) ; => (4 3 2 1 0)

dec終了ステップを1で減らし、値0を取得します。

于 2011-12-17T12:05:20.187 に答える
1
user =>(範囲5)
(0 1 2 3 4)
user =>(take 5(iterate inc 0))
(0 1 2 3 4)
user =>([x [-1 0 123]の場合]
         (inc x)); 何が起こっているのかを明確にするためだけに
(0 1 2 3 4)

setf状態の突然変異です。Clojureはそれについて非常に具体的な意見を持っており、必要に応じてそのためのツールを提供します。上記の場合はそうではありません。

于 2011-12-16T23:46:16.620 に答える
1
(let [my-list (atom ())]
  (dotimes [i 5]
    (reset! my-list (cons i @my-list)))
  @my-list)

(def ^:dynamic my-list nil);need ^:dynamic in clojure 1.3
(binding [my-list ()]
  (dotimes [i 5]
    (set! my-list (cons i my-list)))
  my-list)
于 2011-12-17T11:49:27.073 に答える
1

これは私が探していたパターンです:

(loop [result [] x 5]
  (if (zero? x)
    result
    (recur (conj result x) (dec x))))

StuartHallowayとAaronBedraによるProgrammingClojure (Second Edition)で答えを見つけました。

于 2011-12-21T20:57:43.547 に答える