Clojure 更新原子/作用域
我试图改变一个原子的值,它保存着关于游戏状态的信息 代码如下:Clojure 更新原子/作用域,clojure,clojurescript,Clojure,Clojurescript,我试图改变一个原子的值,它保存着关于游戏状态的信息 代码如下: (def initial-state {:pos [0 0] :dir go-right}) (defonce app-state (atom initial-state)) (defn go-right [[x y]] [(inc x) y]) (defn new-pos [state] ((:dir @state) (:pos @state)))) (defn update-state [app-state] (a
(def initial-state {:pos [0 0] :dir go-right})
(defonce app-state (atom initial-state))
(defn go-right [[x y]] [(inc x) y])
(defn new-pos [state] ((:dir @state) (:pos @state))))
(defn update-state [app-state]
(assoc @app-state :pos (new-pos app-state)))
我有一个函数,它应该根据存储在“:dir
”中的函数更新atom的:pos
”
我的问题是,在newpos
函数中,我得到一个错误,即@state基本上是nil
(def app-state (atom { :dir go-right :pos [0 0] }))
(:dir @state) ;; ===> nil
错误:
未捕获类型错误:无法读取null的属性“call”
我遗漏了什么?在声明
向右运行
函数之前,您正在定义atom。当您取消引用它时,您将得到nil
(def app-state (atom { :dir go-right :pos [0 0] }))
(:dir @state) ;; ===> nil
您可以重新安排代码,但我认为更好的解决方案是使用更简单的数据类型,例如语义上合适的关键字
(def app-state (atom { :dir :right :pos [0 0] }))
然后,一旦原子被解除引用,就使用它引用适当的函数
(def movement { :right go-right
:left go-left
:up go-up
:down go-down })
(defn new-pos [state]
(let [dir (:dir state)
pos (:pos state)
move (get movement dir)]
(move pos)))
通过这种方式,您将能够序列化应用程序状态
atom,这将允许您将状态保存到磁盘,并在以后再次加载
我也会选择使用通用的移动功能,而不是对每个方向进行硬编码
(defn move [[dx dy] [x y]]
[(+ dx x) (+ dy y)])
(def movement { :left (partial move [-1 0])
:right (partial move [1 0])
:up (partial move [0 1])
:down (partial move [0 -1]) })
您可能也不想在手动延迟的atom上开始调用assoc
。这将导致需要使用reset
,您可以通过首先使用swap
来避免所有这些
我们可以删除所有的deref调用,让swap
处理它们。如果函数只处理普通数据,则通常更有用。让较低级别的去引用发生在其他地方
(defn update-state [app-state]
(assoc app-state :pos (new-pos app-state)))
最后,要更新原子状态,请使用swap
(swap! app-state update-state)
;; ===> {:dir :right, :pos [1 0]}
完整的代码-在的REPL上工作
(defn move [[dx dy] [x y]]
[(+ dx x) (+ dy y)])
(def movement { :left (partial move [-1 0])
:right (partial move [1 0])
:up (partial move [0 1])
:down (partial move [0 -1]) })
(defn new-pos [state]
(let [dir (:dir state)
pos (:pos state)
move (get movement dir)]
(move pos)))
(defn update-state [app-state]
(assoc app-state :pos (new-pos app-state)))
(def app-state (atom { :dir go-right :pos [0 0] }))
(swap! app-state update-state)
我们需要更多的代码。什么是
交换代码>呼叫看起来像什么?右转的源代码是什么?错误是什么?在新pos功能上,它在交换前断开。:dir
的值是否可能是nil
?右转
在地图上的位置是否为零?我知道Clojure,但不知道Clojurescript的不同之处。我不知道我的建议是否可信。我同意这一点,但也注意到(不是重新排列代码),您还可以使用。