我正试图在clojure中进行结构和解释计算机程序的练习。但是,在多个地方它使用scheme的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!
函数,但它似乎以不同的方式工作。什么是方案的set!
在clojure中的等价(或最接近的替代方案)?
这个练习让我觉得不止一点(好吧,高度做作)。以下是我在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
是处理可变状态的最简单方法。
注意:这个答案已经过时,因为OP已经编辑了问题,包括我要求的“为什么”。我将它留在上下文中,但Alan Thompson的答案对于当前版本的问题要好得多。
这取决于你变异的原因和原因。在一些Scheme样式中,变异是常见的,所以你可能会问“如何在Clojure中改变一个东西”,因为你的Scheme算法涉及变异。一个更好的问题是,“在Clojure中解决这个问题的正确算法是什么”。询问关于非常狭窄的代码片段的非常广泛的问题将不会有效。
例如,您的代码片段实际上根本没用,因为即使在Scheme中它也类似于:
(define (f x)
(lambda (newvalue) '()))
也就是说,x
的突变在你的功能中并不重要,因为它不可能读到x
!所以,告诉你Clojure相当于这个并不是很有趣:它很简单
(defn f [x]
(fn [newvalue] nil))
但当然这并不能回答你真正的问题。所以关键是要备份:你真正的问题是什么?你为什么要改变这个东西?然后,响应者可以建议适合您的情况的那种突变,或者(可能)一种不需要突变的替代方法。