Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure不变性实践_Clojure - Fatal编程技术网

Clojure不变性实践

Clojure不变性实践,clojure,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 [order

我试图理解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)
谢谢,
这绝对不是用Clojure或任何其他FP语言进行函数式编程的正确方法。尽管您使用了Clojure作为实现语言,但您的代码本质上仍然是必需的

正确的方法是,每当需要某个数据结构的新版本时,使用修改过的内容创建新的数据结构。比如:

(let [a []
         b (conj a "order1")
         c (conj b "order2")]
     (println c))
在本例中,conj通过向结构中添加一个新元素(作为conj的参数)来创建一个新的数据结构。旧结构没有任何修改,这意味着它是不可变的


如果你真的需要某种状态,Clojure有一些原语,比如atom。但是,首先尝试在没有可修改的中心状态的情况下编写函数代码。

这绝对不是用Clojure或任何其他FP语言进行函数编程的正确方法。尽管您使用了Clojure作为实现语言,但您的代码本质上仍然是必需的

正确的方法是,每当需要某个数据结构的新版本时,使用修改过的内容创建新的数据结构。比如:

(let [a []
         b (conj a "order1")
         c (conj b "order2")]
     (println c))
在本例中,conj通过向结构中添加一个新元素(作为conj的参数)来创建一个新的数据结构。旧结构没有任何修改,这意味着它是不可变的


如果你真的需要某种状态,Clojure有一些原语,比如atom。但是首先尝试编写没有可修改的中心状态的函数代码。

下面是一种更典型的方法。它使用
spyx pretty
函数,但如果需要,您可以替换
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"}
订单队列=> # 订单队列=> # 订单队列=> # 烹饪:#tst.demo.core.Order{:fplate“汤”,splate“鱼和薯条”} 烹饪:#tst.demo.core.Order{:fplate“沙拉”,splate“汉堡”} 烹饪:#tst.demo.core.Order{:fplate“Rice”,splate“Steak”}
下面是一种更典型的方法来完成此示例。它使用
spyx pretty
函数,但如果需要,您可以替换
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"}
订单队列=> # 订单队列=> # 订单队列=> # 烹饪:#tst.demo.core.Order{:fplate“汤”,splate“鱼和薯条”} 烹饪:#tst.demo.core.Order{:fplate“沙拉”,splate“汉堡”} 烹饪:#tst.demo.core.Order{:fplate“Rice”,splate“Steak”}
也许您可以使用atom?看看这个相关的问题:也许你可以使用atom?看到这个相关的问题:嗨,洛科里,谢谢你的回答。我明白你的意思。在真实场景中(餐厅),订单不断地来来去去,必须有一个点来保持“实际订单”,因此“准备”或“更新”等其他功能必须依赖。在let中发生的事情会留在let中,所以我想这是我仍然缺少的东西。谢谢你的回答。我明白你的意思。在真实场景中(餐厅),订单不断地来来去去,必须有一个点来保持“实际订单”,因此“准备”或“更新”等其他功能必须依赖。在let中发生的事情会留在let中,所以我想这是我仍然缺少的东西。谢天谢地,这无疑是对问题中代码的改进,尽管我更愿意看到关于如何在功能上真正做到这一点的解释,因为问题是关于不变性实践的。有一件事我不明白:在
ns
子句中导入的
demo.core
名称空间是什么?(我不介意这里的
tupelo
,因为您使用
:as
来引用它,并解释如何使用clojure.core)我通常使用测试
ns
进行演示,但忘了删除未使用的
:use
内容。但是,这个答案没有任何单元测试,可能在主名称空间中。如果我错了,请纠正我,但从您的示例和注释中,我了解如果需要维护和更新任何类型集合的状态,我可以使用atom和swap!。问题是关于不变性的,因为通过更新某些集合,我正在对其进行变异,在本例中,必须维护订单的动态列表。谢谢。是的,原子和交换!是Clojure为您提供的可能性之一。交换!您并不是直接修改状态,而是以原子方式替换状态的新值。您可以通过对前一状态执行某些操作(如conj操作或其他操作),从前一状态计算新状态。原子和交换!从某种意义上说,它是原始的,如果您需要这样的东西,它不会为同步事务更新提供任何保护。这当然是对问题中代码的改进,尽管我更希望看到关于如何在功能上真正做到这一点的解释,因为问题询问的是不变性实践。有一件事我不明白:在
ns
子句中导入的
demo.core
名称空间是什么?(我不介意这里的
tupelo
,因为您使用
:as
来引用它,并解释如何使用clojure.core)我通常使用测试
ns
进行演示,但忘了删除未使用的
:use
内容。但是,这个答案没有任何单元测试,可能在主名称空间中。如果我错了,请纠正我,但从您的示例和注释中,我了解如果需要维护和更新任何类型集合的状态,我可以使用atom和swap!。问题是关于不变性的,因为通过更新某些集合,我正在对其进行变异,在本例中,必须维护订单的动态列表。谢谢,是的,atom an