【问题标题】:How to solve "stateful problems" in Clojure?如何解决 Clojure 中的“有状态问题”?
【发布时间】:2020-02-10 08:20:22
【问题描述】:

我是 clojure 的新手,我无法理解一些概念,特别是纯函数和不变性。

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

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

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

考虑到我无法更改我的收藏,我将如何在 Clojure 中执行此操作?

这不是一个实际问题(尽管欢迎提供一些代码示例),我想了解您如何处理这样的问题。

【问题讨论】:

  • 我认为 Carcigenicate 对您的具体问题有很好的回答。为了更全面地了解 Clojure 程序设计,我建议在 youtube 上查看“Clojure 中的自下而上与自上而下的设计 - Mark Ba​​stian”。
  • 谢谢,我一定会看看的。我检查了几个资源,但没有一个能回答我的问题。
  • 为了能够给出更相关的答案,我想我需要一个更具体的例子来说明数据是如何被使用的。如果您正在处理异步代码,您可能需要使用atom,正如我在底部显示的那样。

标签: clojure functional-programming


【解决方案1】:

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

(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

【讨论】:

  • 抱歉删除评论。起初我以为我理解了你的例子,但我没有。在给了它一些之后,我终于做到了。我错误地认为您的代码就像一个端点,并且“尝试日期”在用户的每个新请求中都是空的。
  • @M.Arkk 哦,不。 attempt-dates 在对 loop 的一次调用中的每次迭代之间进行传送。如果您在 loop 内接受请求,那么这将起作用。如果您在其他地方异步接受请求,我可能会使用atom
猜你喜欢
  • 1970-01-01
  • 2015-08-04
  • 1970-01-01
  • 2017-09-24
  • 1970-01-01
  • 2021-02-20
  • 2010-11-11
  • 2020-01-31
  • 1970-01-01
相关资源
最近更新 更多