clojure:相当于scheme的set!

时间:2019-04-15 17:17:11

标签: clojure lisp

我正在尝试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!的等效项(或最接近的替代项)是什么?

2 个答案:

答案 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))

但是,这当然不能回答您的真正问题。因此,重点是要备份:您真正的问题是什么? 为什么您要突变这个东西?然后,响应者可以提出适合您情况的突变类型,或者(可能)是一种根本不需要突变的替代方法。