1

私はClojureでLandOfLispのオークバトルゲームを書き直しています。その過程で、私はより機能的なスタイルを使用しています。私は、より高いレベルのゲームループの一部を書くための2つの方法を考え出しました。1つはループ/繰り返しを含み、もう1つはdoseqとアトムを使用します。2つの機能は次のとおりです。

(defn monster-round [player monsters]
  (loop [n 0 p player]
    (if (>= n (count monsters))
      p
      (recur (inc n)
         (if (monster-dead? (nth monsters n))
           p
           (let [r (monster-attack (nth monsters n) p)]
             (print (:attack r))
             (:player r)))))))


(defn monster-round-2 [player monsters]
  (let [p (atom player)]
    (doseq [m monsters]
      (if (not (monster-dead? m))
        (let [r (monster-attack m @p)]
             (print (:attack r))
             (reset! p (:player r)))))
    @p))

コードがより簡潔でわかりやすいので、2番目の方法の方が好きです。最初のアプローチが優れている理由はありますか?それとも私はこれを行うための別の方法を逃していますか?

4

1 に答える 1

8

これは同等ですか?もしそうなら、私はそれを好みます-それはコンパクトで、あなたのソリューションよりも明確で(imho!)、そして機能的です

(defn monster-round [monsters player]
  (if-let [[monster & monsters] monsters]
    (recur monsters
      (if (monster-dead? monster)
        player
        (let [r (monster-attack monster player)]
          (print (:attack r))
          (:player r))))
    player))

monster-round(注:繰り返しが見栄えが良くなるように、引数の順序をに変更しました)

nより一般的には、「機能的な」バージョンを導入するべきではありませんでした(インデックスがある場合、実際には機能的ではありません...)。シーケンスへのインデックス作成が必要になることはほとんどありません。もしあなたがそれをもう少し難しくしたいという誘惑と戦っていたら、私はあなたが上記のルーチンを書いていただろうと思います...

しかし、それを書いた後、私は次のように考えました。プレイヤーを前進させます」。そして、書くのは簡単でした:

(defn- fight [player monster]
  (if (monster-dead? monster)
    player
    (let [r (monster-attack monster player)]
      (print (:attack r))
      (:player r))))

(defn monster-round [player monsters]
  (reduce fight player monsters))

これは(それがあなたが望むことをするなら)正解(tm)です。

(多分私は質問に答えていませんか?私はあなたが上記のようにあなたがより良い方法を逃したと思います。一般に、あなたは通常突然変異を必要としないデータ構造の周りに計算をスレッド化できるはずです;しばしばあなたは-そしてすべきです-他の人のためにプロセスを文書化するのに役立つため、mapやreduceなどの標準フォームを使用してください)。

于 2012-04-17T02:56:32.830 に答える