我正在尝试Clojure中计算机程序的结构和解释的练习。但是,它在多个地方使用了方案的set!
,它会更改闭包内部变量的值。例如
(define (stash x)
;; return a procedure which returns a value, which
;; you can change by providing an argument
(lambda (nv-maybe)
(if (null? nv-maybe)
x
(begin
(set! x (car nv-maybe))
x))))
我尝试了clojure的set!
函数,但是它似乎以不同的方式工作。 Clojure中方案set!
的等效项(或最接近的替代项)是什么?
答案 0 :(得分:3)
这个练习给我的印象是有点虚构(好的,非常虚构)。这是我在Clojure中(如果被迫)的方式:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test) )
(defn new-stash
"Saves an initial value and returns a function `stash` that can retrieve the
value via `(stash)`. Value can be mutated via `(stash <new-val>)` "
[some-val]
(let [local-state (atom some-val)]
(fn
([] @local-state)
([new-val] (reset! local-state new-val)))))
(dotest
(let [stash (new-stash 5)]
; stash saves the value 5
(is= 5 (stash))
(is= 5 (stash))
; mutate value in stash to 7
(is= 7 (stash 7))
(is= 7 (stash)) ; stash now contains 7
(is= 7 (stash))))
当然,以上是高度非意识形态的Clojure代码。通常,您只需要直接使用atom
并避免所有关闭垃圾:
(def stash (atom :uninitialized)) ; could use `nil`
(dotest
(reset! stash 5) ; save the initial value
; stash saves the value 5
(is= 5 @stash)
(is= 5 @stash)
; mutate value in stash to 7
(is= 7 (reset! stash 7))
(is= 7 @stash) ; stash not contains 7
(is= 7 @stash))
您可以通过其他方式(例如,使用var
来获得相同的结果,但是atom
是处理可变状态的最简单方法。
答案 1 :(得分:1)
注意:此答案已过时,因为OP已将问题编辑为包含我要求的“为什么”。我将其保留在上下文中,但是对于当前版本的问题,艾伦·汤普森的答案要好得多。
这取决于您要变异的内容以及原因。在某些Scheme样式中,突变很常见,因此您可能会问“我如何在Clojure中对事物进行突变”,因为您的Scheme算法涉及突变。一个更好的问题是:“在Clojure中解决该问题的正确算法是什么?”对非常狭窄的代码段提出非常广泛的问题将不会产生效果。
例如,您的代码段实际上根本没有用,因为即使在Scheme中,它也类似于:
(define (f x)
(lambda (newvalue) '()))
也就是说,x
的突变在您的功能中并不重要,因为不可能读过x
!因此,告诉您与Clojure等效的方法不是很有趣:这很简单
(defn f [x]
(fn [newvalue] nil))
但是,这当然不能回答您的真正问题。因此,重点是要备份:您真正的问题是什么? 为什么您要突变这个东西?然后,响应者可以提出适合您情况的突变类型,或者(可能)是一种根本不需要突变的替代方法。