clojure:相当于scheme的`set!`

问题描述 投票:1回答:2

我正试图在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 lisp
2个回答
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
投票

注意:这个答案已经过时,因为OP已经编辑了问题,包括我要求的“为什么”。我将它留在上下文中,但Alan Thompson的答案对于当前版本的问题要好得多。


这取决于你变异的原因和原因。在一些Scheme样式中,变异是常见的,所以你可能会问“如何在Clojure中改变一个东西”,因为你的Scheme算法涉及变异。一个更好的问题是,“在Clojure中解决这个问题的正确算法是什么”。询问关于非常狭窄的代码片段的非常广泛的问题将不会有效。

例如,您的代码片段实际上根本没用,因为即使在Scheme中它也类似于:

(define (f x)
  (lambda (newvalue) '()))

也就是说,x的突变在你的功能中并不重要,因为它不可能读到x!所以,告诉你Clojure相当于这个并不是很有趣:它很简单

(defn f [x]
  (fn [newvalue] nil))

但当然这并不能回答你真正的问题。所以关键是要备份:你真正的问题是什么?你为什么要改变这个东西?然后,响应者可以建议适合您的情况的那种突变,或者(可能)一种不需要突变的替代方法。

热门问题
推荐问题
最新问题