2

我是 Clojure 的初学者,我遇到了一个问题,我什至不确定是否可以在 Closure 中完成。

所以问题如下。我已经实现了一个函数,它从一个区间(直到一个限制)计算素数。

(defn gather_primes_in_range [range_start range_end target_number prime_list]
    (if (or (= 0 target_number) (> range_start range_end) (= FIND_MORE_PRIMES false)) 
        prime_list
        (do
            (if (is_prime? range_start)
                (gather_primes_in_range (+ range_start 1) range_end (- target_number 1) (conj, prime_list, range_start))
                (gather_primes_in_range (+ range_start 1) range_end target_number prime_list)
            )
        )
    )
)

(defn find_nr_of_primes_in_range [range_start range_end target_number]
    (if (< range_start 2)
        (gather_primes_in_range 2 range_end target_number [])
        (gather_primes_in_range range_start range_end target_number [])
    )
)

这工作得很好。但我现在想要的是有一个全局变量,它应该存储在每个方法上,调用在变量中找到的素数,以便稍后查找。在 Python、Ruby 或 Scala 等其他语言中,我只需使用一个 Set 来完成此操作,然后在从函数返回之前向其中添加条目。但是在 Clojure 中,我不知道如何解决这个问题。

基本上我尝试的是,在某个地方声明了全局:

(def PRIMES_FOUND_SO_FAR #{})

然后以某种方式在返回时将条目添加到该变量中。这在 Clojure 中是否可行,如果可以,怎么办?我已经尝试使用swap!andatom或 set 来更改其他变量的值!但在任何情况下都无法在这里工作。

4

2 回答 2

8

首先,我强烈建议您阅读有关 clojure 代码约定的内容 Clojure 的命名约定是什么?

让我向您展示您的代码的一些改进。

1)应用clojure命名约定。

然后从 切换(+ variable 1)(inc variable)(与 相同的优化dec)。

(= FIND_MORE_PRIMES false)可以简单地替换为find-more-primes?

最后条件(= 0 smthng)可以写成更惯用的风格(zero? smthng)

现在您的代码看起来更具可读性:

(defn gather-primes-in-range [range-start range-end target-number prime-list]
  (if (or (zero? target-number) (> range-start range-end) need-more-primes?)
    prime-list
    (do
      (if (is-prime? range-start)
        (gather-primes-in-range (inc range-start) range-end (dec target-number) (conj prime-list range-start))
        (gather-primes-in-range (inc range-start) range-end target-number prime-list)))))

2)现在我们应该删除多余do的调用,因为它包装了唯一的一个函数调用。

最后一个技巧是通过将整个调用交换到gather-primes-in-rangerecur

(defn gather-primes-in-range 
  [range-start range-end target-number prime-list]
    (if (or (zero? target-number) (> range-start range-end) need-more-primes?)
      prime-list
      (if (is-prime? range-start)
        (recur (inc range-start) range-end (dec target-number) (conj prime-list range-start))
        (recur (inc range-start) range-end target-number prime-list))))

是时候回答你的问题了。您不会从这种方法中受益

(def PRIMES_FOUND_SO_FAR #{})

因为你没有机会改变这一套。您唯一可以处理的就是从该结构创建一些新的不可变数据结构。

正如@georgek 提到的,您可以在这种特殊情况下简单地使用atom 。

(def PRIMES_FOUND_SO_FAR (atom #{}))

向原子添加新的素数:

(swap! PRIMES_FOUND_SO_FAR conj prime-number)

用于提取值的 Deref atom:

@PRIMES_FOUND_SO_FAR ;; or (deref PRIMES_FOUND_SO_FAR)
-> #{2 3 5 7 11}

无论如何,您的代码有点必要,但您应该始终记住,clojure 是具有不可变数据结构、函数作为参数等的函数式语言。使用全局变量根本不是一个好主意。顺便说一句,这就是你的函数在 clojure 风格中的样子:

(defn gather-primes-in-range [start end target-number]
  (take target-number (filter is-prime? (range start end))))
于 2013-02-10T00:24:52.397 回答
0

对于那些花费太多时间搜索如何在 clojure 中修改全局(根)变量的人来说,这里是解决方案:

(def user-remote-browser "anonymous")

你可以从我想的任何地方修改它,但在相同的命名空间中:

(alter-var-root #'user-remote-browser (constantly name))

alter-var-root 使用函数修改变量,不断创建一个常量函数,这里返回字符串名称

于 2019-10-17T15:14:18.453 回答