2017-11-21 13 views
0

Clojureの不変性のベストプラクティスを理解しようとしていますが、私は常に新しい注文を再宣言(更新)するこの簡単な例がありますが、これが正しいかどうかわかりません方法。Clojure不変性練習

(defrecord Order [fplate splate]) 

(def new-orders clojure.lang.PersistentQueue/EMPTY) 

(defn add-order [orders order] 
    (conj orders order)) 

(defn cook [order]()) 

(defn cook-order [orders] 
(cook (first orders)) (pop orders)) 

;;order1 
(def o1 (->Order "Soup" "Fish&Chips")) 
(def new-orders (add-order new-orders o1)) 

;;order2 
(def o2 (->Order "Salad" "Hamburger")) 
(def new-orders (add-order new-orders o2)) 

;;order3 
(def o3 (->Order "Rice" "Steak")) 
(def new-orders (add-order new-orders o3)) 

;;cook order 
(def new-orders (cook-order new-orders)) 
(peek new-orders) 

おかげで、 R.

+0

はおそらく、あなたが原子https://clojure.org/reference/atomsを使用することができますか?この関連する問題を参照してください:https://stackoverflow.com/questions/8938330/clojure-swap-atom-dequeuing – netchkin

答えて

1

ここでは、この例を行うためのより一般的な方法を示します。それはspyx-pretty機能from the Tupelo libraryを使用していますが、あなたがしたい場合は、printlnに置き換えることができます:結果と

(ns tst.demo.core 
    (:require [tupelo.core :as t])) 

(defrecord Order [fplate splate]) 

(def orders-queue (atom [])) 

(defn add-order [order] 
    (swap! orders-queue conj order)) 

(defn cook [order] (println "cooking: " (pr-str order))) 

(add-order (->Order "Soup" "Fish&Chips")) ; order1 
(t/spyx-pretty orders-queue) 

(add-order (->Order "Salad" "Hamburger")) ; order2 
(t/spyx-pretty orders-queue) 

(add-order (->Order "Rice" "Steak")) ; order3 
(t/spyx-pretty orders-queue) 

; cook orders 
(newline) 
(doseq [order @orders-queue] 
    (cook order)) 

orders-queue => 
#<[email protected]: [{:fplate "Soup", :splate "Fish&Chips"}]> 

orders-queue => 
#<[email protected]: 
    [{:fplate "Soup", :splate "Fish&Chips"} 
    {:fplate "Salad", :splate "Hamburger"}]> 

orders-queue => 
#<[email protected]: 
    [{:fplate "Soup", :splate "Fish&Chips"} 
    {:fplate "Salad", :splate "Hamburger"} 
    {:fplate "Rice", :splate "Steak"}]> 

cooking: #tst.demo.core.Order{:fplate "Soup", :splate "Fish&Chips"} 
cooking: #tst.demo.core.Order{:fplate "Salad", :splate "Hamburger"} 
cooking: #tst.demo.core.Order{:fplate "Rice", :splate "Steak"} 
+0

これは確かに問題のコードを改善したものですが、実際にこの機能をどのように実際に行うかについては、不変性の練習について質問しています。あなたが 'ns'節でインポートしている' demo.core'名前空間は何ですか? (私はここで 'tupelo'を気にしません。なぜなら、':as'で参照し、代わりにclojure.coreを使う方法を説明しているからです) – amalloy

+0

私は通常、 'ns'のテストをデモ用に使います。 :使用するもの。しかし、この答えには単体テストがなく、メインの名前空間に入っている可能性があります。 –

+0

こんにちはamalloy、アラン。私が間違っている場合は私を修正してください。しかし、あなたの例とコメントから、私が原子とスワップを使うことができるあらゆる種類のコレクションの状態を維持し更新する必要があると私は理解しています!いくつかのコレクションを更新することで、私はそれを変更しており、この場合、動的なオーダーリストを維持することが必須であるため、不変性に関する質問がありました。ありがとうございました。 – razvan

2

は、これは間違いなく、Clojureの中に関数型プログラミング、または任意の他のFP言語を行うには正しい方法ではありません。 Clojureを実装言語として使用していますが、コードは本質的に必須です。

正しい方法は、新しいバージョンのデータ構造が必要なときはいつでも、変更された内容の新しいデータ構造を作成することです。何かのように:

(let [a [] 
     b (conj a "order1") 
     c (conj b "order2")] 
    (println c)) 

この場合、conjは、conjにパラメータとして与えられた構造体に新しい要素を追加することによって新しいデータ構造を作成します。古い構造は決して変更されません。つまり、それは不変です。

本当に本当に何らかの状態が必要な場合、Clojureには、原子などのプリミティブがあります。しかし、変更可能な中央の状態を持たない機能コードを書くようにしてください。

+0

こんにちは、こんにちは、あなたの答えをありがとう。私はあなたのことを理解しています。現実世界のシナリオ(レストラン)では、注文は常に行き来し、「実際の注文」を維持して「準備」や「更新」などの他の機能を頼りにする必要があります。レットの内部で何が起こるのかはレットの中にとどまるので、これは私がまだ紛失しているものだと思います。ありがとう – razvan