Clojure 跨多个名称空间共享状态

Clojure 跨多个名称空间共享状态,clojure,Clojure,在编写我的第一个Clojure程序时,我偶然发现了以下任务,我无法解决: (ns core (:require [calc])) (def data 1) (calc/updatedata) data ;; should return 2 (ns calc) (refer 'core :only '[data]) (defn updatedata [] (def data (+ 1 data))) 现在我有两个问题: 由于core需要calc,calc首先被调用,但随后还没

在编写我的第一个Clojure程序时,我偶然发现了以下任务,我无法解决:

(ns core
  (:require [calc]))

(def data 1) 
(calc/updatedata)
data 
;; should return 2

(ns calc)
(refer 'core :only '[data]) 
(defn updatedata []
  (def data (+ 1 data)))
现在我有两个问题:

  • 由于
    core
    需要
    calc
    calc
    首先被调用,但随后还没有可参考的符号
    数据。我不知道如何避开这个问题:(
  • 我无法使用
    def
    重新定义
    data
    ,得到错误
    java.lang.IllegalStateException:数据已经引用了命名空间中的#core/data:calc
    。也许我应该在这里使用ref/atom/agent(还没有使用它们,但我现在正在研究..)

我如何在
calc
中引用和变异
core/data
,就好像它是在那里定义的一样?

在我看来,你这样做完全是错误的,可能对你应该如何在Clojure中编程有一个根本性的误解,但我们开始吧

(ns clojure-scratch.core
  (:require [clojure-scratch.calc :as calc]))

(def data (atom 1))

(swap! data calc/update-data)
在另一个文件中

(ns clojure-scratch.calc)

(defn update-data [n]
  (inc n))

在我看来,您这样做是完全错误的,并且可能对应该如何在Clojure中编程有一个根本性的误解,但现在我们开始

(ns clojure-scratch.core
  (:require [clojure-scratch.calc :as calc]))

(def data (atom 1))

(swap! data calc/update-data)
在另一个文件中

(ns clojure-scratch.calc)

(defn update-data [n]
  (inc n))

在我看来,您这样做是完全错误的,并且可能对应该如何在Clojure中编程有一个根本性的误解,但现在我们开始

(ns clojure-scratch.core
  (:require [clojure-scratch.calc :as calc]))

(def data (atom 1))

(swap! data calc/update-data)
在另一个文件中

(ns clojure-scratch.calc)

(defn update-data [n]
  (inc n))

在我看来,您这样做是完全错误的,并且可能对应该如何在Clojure中编程有一个根本性的误解,但现在我们开始

(ns clojure-scratch.core
  (:require [clojure-scratch.calc :as calc]))

(def data (atom 1))

(swap! data calc/update-data)
在另一个文件中

(ns clojure-scratch.calc)

(defn update-data [n]
  (inc n))

作为RedDeckWins建议的扩展,如果您希望让突变发生在
核心
中,并避免将
数据
传递给
计算
中的每个函数,您可以在
计算
中创建一个动态变量。
更新数据
中的第一个语句,您将传递的值绑定到动态变量
calc
中的oncerned函数总是引用动态变量

(ns noob-1.calc)

(def ^:dynamic *app-data* {:val false})

(defn action-1 []
  (println "action-1 data - " *app-data*))

(defn action-2 []
  (println "action-2 data - " *app-data*))

(defn actions [data]
  (binding [*app-data* data]
    (println "actions data - " *app-data*)
    (action-1)
    (action-2)
    (assoc *app-data* :val "2")))


也就是说,我仍然建议将
应用程序数据
传递给
calc
中的每个函数。这样,每个函数都可以增量修改
应用程序数据
,并且
操作
可以返回最终状态。为了支持突变并避免将状态传递给每个函数,您需要用atom替换动态变量。
calc
中的原子将在本地使用,它的值将从
操作中返回。我会避免这种情况。

作为RedDeckWins建议的扩展,如果您希望让突变发生在
核心
中,并避免将
数据
传递给
calc
中的每个函数,您可以在
ca>中创建一个动态变量lc
。在
更新数据
中的第一条语句中,您将把传入的值绑定到动态变量。
calc
中的所有相关函数将始终引用动态变量

(ns noob-1.calc)

(def ^:dynamic *app-data* {:val false})

(defn action-1 []
  (println "action-1 data - " *app-data*))

(defn action-2 []
  (println "action-2 data - " *app-data*))

(defn actions [data]
  (binding [*app-data* data]
    (println "actions data - " *app-data*)
    (action-1)
    (action-2)
    (assoc *app-data* :val "2")))


也就是说,我仍然建议将
应用程序数据
传递给
calc
中的每个函数。这样,每个函数都可以增量修改
应用程序数据
,并且
操作
可以返回最终状态。为了支持突变并避免将状态传递给每个函数,您需要用atom替换动态变量。
calc
中的原子将在本地使用,它的值将从
操作中返回。我会避免这种情况。

作为RedDeckWins建议的扩展,如果您希望让突变发生在
核心
中,并避免将
数据
传递给
calc
中的每个函数,您可以在
ca>中创建一个动态变量lc
。在
更新数据
中的第一条语句中,您将把传入的值绑定到动态变量。
calc
中的所有相关函数将始终引用动态变量

(ns noob-1.calc)

(def ^:dynamic *app-data* {:val false})

(defn action-1 []
  (println "action-1 data - " *app-data*))

(defn action-2 []
  (println "action-2 data - " *app-data*))

(defn actions [data]
  (binding [*app-data* data]
    (println "actions data - " *app-data*)
    (action-1)
    (action-2)
    (assoc *app-data* :val "2")))


也就是说,我仍然建议将
应用程序数据
传递给
calc
中的每个函数。这样,每个函数都可以增量修改
应用程序数据
,并且
操作
可以返回最终状态。为了支持突变并避免将状态传递给每个函数,您需要用atom替换动态变量。
calc
中的原子将在本地使用,它的值将从
操作中返回。我会避免这种情况。

作为RedDeckWins建议的扩展,如果您希望让突变发生在
核心
中,并避免将
数据
传递给
calc
中的每个函数,您可以在
ca>中创建一个动态变量lc
。在
更新数据
中的第一条语句中,您将把传入的值绑定到动态变量。
calc
中的所有相关函数将始终引用动态变量

(ns noob-1.calc)

(def ^:dynamic *app-data* {:val false})

(defn action-1 []
  (println "action-1 data - " *app-data*))

(defn action-2 []
  (println "action-2 data - " *app-data*))

(defn actions [data]
  (binding [*app-data* data]
    (println "actions data - " *app-data*)
    (action-1)
    (action-2)
    (assoc *app-data* :val "2")))


也就是说,我仍然建议将
应用程序数据
传递给
calc
中的每个函数。这样,每个函数都可以增量修改
应用程序数据
,并且
操作
可以返回最终状态。为了支持突变并避免将状态传递给每个函数,您需要用atom替换动态变量。
calc
中的atom将在本地使用,其值将从
操作中返回。我会避免这种情况。

谢谢你的回答。也许我过于简化了我的示例。实际上,更新数据函数包括许多其他函数,这些函数都依赖于数据。因此,由于我只处理一组数据,而不是传递数据拥有整个链我希望能够从代码中的任何地方引用它,这就是我希望引用它的原因。是否存在这样的用例:人们更喜欢这种“全局状态”行为而不是“传递状态”对于几乎所有的函数?例如,假设数据是
核心
ns中的一个中心配置,我想在
选项菜单
ns中对其进行变异。仔细想想,我喜欢这种变异(
交换!
)只出现在
核心
名称空间中,因为代码中其他地方没有副作用