在clojure上保存状态

时间:2018-03-25 21:44:36

标签: clojure compojure ring compojure-api

我现在开始进行函数式编程,并且在没有变量的情况下工作变得非常疯狂。

我读过的每一个教程都说,重新定义变量并不酷,但我不知道如何在不保存变量状态的情况下解决实际问题。

例如:我正在研究API,我希望通过请求保留值。假设我有一个添加Sub OCRReader() Dim doc1 As MODI.Document Dim inputFile As String Dim strRecText As String Dim imageCounter As Integer inputFile = Application.GetOpenFilename strRecText = "" Set doc1 = New MODI.Document doc1.Create (inputFile) doc1.OCR ' this will ocr all pages of a multi-page tiff file For imageCounter = 0 To (doc1.Images.Count - 1) ' work your way through each page of results strRecText = strRecText & doc1.Images(imageCounter).Layout.Text ' this puts the ocr results into a string Next fnum = FreeFile() Open "C:\Test\testmodi.txt" For Output As fnum Print #fnum, strRecText Close #fnum doc1.Close End Sub 的终点,我有一个person列表,我想persons或更改redefine的值列表添加新persons。我怎么能这样做?

可以使用personvar-setalter-var-root吗?

(对于api我正在使用conj!而每个compojure-api都是person

2 个答案:

答案 0 :(得分:6)

Clojure将值与身份区分开来。您可以使用atoms来管理compojure应用程序中的状态。

(def persons (atom [])) ;; init persons as empty vector
(swap! persons #(conj % {:name "John Doe"})) ;; append new value

您可以在文档中找到更多内容:

https://clojure.org/reference/atoms

https://clojure.org/reference/data_structures

https://clojuredocs.org/clojure.core/atom

答案 1 :(得分:1)

您可能需要在大型应用程序中的某个位置使用可变状态,但在所有情况下都不需要。

我不熟悉compojure,但这是一个使用不变性的小例子,可能会给你一个更好的想法:

(loop [requests []
       people []

   (let [request (receive-request)]
     ; Use requests/people

     ; Then loop again with updated lists
     (recur (conj requests request)
            (conj people (make-person request))))])

我在这里使用假设的receive-requestmake-person函数。

loop会创建一对绑定,并在每个recur更新它们。这是“重新定义变量”的简便方法。这与纯递归相似,你不会在任何时候改变最终结果,只需改变传递给下一次迭代的值。

当然,这非常简单,而且不切实际,因为您一次只收到一个请求。如果您同时收到来自多个线程的请求,这对于一个原子来说是合理的情况:

(defn listen [result-atom]
  (Thread.
    (fn []
      (while true ; Infinite listener for simplicity
        (let [request (receive-request)]
          (swap! result-atom #(conj % (make-person request))))))))

(defn listen-all []
  (let [result-atom (atom [])]
    (listen result-atom)
    (listen result-atom)))
    ; result-atom now holds an updating list of people that you can do stuff with

swap!通过conj oining将原子变为它所拥有的列表。原子中的列表没有变异,它只是被自身的修改版本所取代。 任何持有对旧人员名单的引用的人都不会受到swap! 的调用的影响。

更好的方法是使用像core / async这样的库,但这样就远离了这个问题。

关键是,您可能需要在某处使用可变变量,但对它们的需求比您习惯的要少得多。在大多数情况下,几乎所有事情都可以像第一个例子中那样使用不变性来完成。