如何解决Clojure中的“有状态的问题”?

时间:2019-10-13 14:16:04

标签: clojure functional-programming

我是Clojure的新手,我很难理解一些概念,特别是纯函数和不变性。

我仍然无法理解的一件事是如何在clojure中解决这样的问题:

具有登录方法的简单控制台应用程序,在该应用程序中,用户在1分钟的间隔内不能尝试登录3次以上。

例如,在C#中,我可以在用户每次尝试登录时将UserId和时间戳添加到集合中,然后检查最后一分钟是否有3个以上的尝试。

考虑到我无法更改收藏夹,我该如何在Clojure中做到这一点?

这不是一个务实的问题(尽管会欢迎一些代码示例),我想了解您如何解决这样的问题。

1 个答案:

答案 0 :(得分:5)

在大多数情况下,您不会更改对象,而是创建旧对象的新版本:

(loop [attempt-dates []]
  (if (login-is-correct)
    (login)
    (recur (conj attempt-dates (current-date-stamp)))))

在这种情况下,我正在使用loop。我对recur所做的任何操作都将传递到loop的下一个迭代中。我在创建(conj attempt-dates (current-date-stamp))时创建了一个包含新标记的新列表,然后将该新列表传递到loop的下一个迭代中。

大多数情况下就是这样。与其考虑更改对象,不如考虑创建对象的转换副本并将副本传递。

如果您确实确实需要可变状态,则可以使用可变atom来保持不可变状态:

(def mut-state (atom []))

(swap! mut-state conj 1)

(println @mut-state)  ; Prints [1]

[]在这里仍然是不变的,新版本只是替换了可变atom容器中的旧版本。

除非您需要与UI回调或类似功能进行通信,否则通常通常不需要可变性。练习改用loop / recurreduce