我试图了解Clojure的不变性最佳实践,我有一个简单的例子,我不断重新声明(更新)“新订单”,但我不确定这是否正确。< / p>
(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 :(得分:2)
这绝对不是在Clojure或任何其他FP语言中进行函数式编程的正确方法。尽管您已经使用Clojure作为实现语言,但您的代码仍然是必不可少的。
正确的方法是在需要某个数据结构的新版本时,使用修改后的内容创建新的数据结构。类似的东西:
(let [a []
b (conj a "order1")
c (conj b "order2")]
(println c))
在这种情况下,conj通过向作为conj的参数给出的结构添加新元素来创建新的数据结构。旧结构不会以任何方式进行修改,这意味着它是不可变的。
如果你真的需要某种状态,Clojure就有这样的原语,比如原子。但首先尝试编写没有可修改的中心状态的功能代码。
答案 1 :(得分: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 =>
#<Atom@4147f771: [{:fplate "Soup", :splate "Fish&Chips"}]>
orders-queue =>
#<Atom@4147f771:
[{:fplate "Soup", :splate "Fish&Chips"}
{:fplate "Salad", :splate "Hamburger"}]>
orders-queue =>
#<Atom@4147f771:
[{: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"}