Clojure,重新清除变量导致警告“已经指”

时间:2014-12-07 20:28:45

标签: clojure

我今天开始学习Clojure,遇到了一个我不会用切肉刀Googeling解决的问题。

我有一个简单的脚本,我希望在满足条件时增加一个计数器。我已经了解到Clojure中的变量是不可变的,而增加这种变量的方法是重新确定它,但这会引发警告。

(defn main[]
    (def num 0)
    (if [...]
        (def num (+ num 1))
    )
)

然而,这会引发以下警告:

WARNING: num already refers to: #'clojure.core/num in namespace: user, being replaced by: #'user/num

2 个答案:

答案 0 :(得分:1)

这里有两个问题:

一,你正在影响clojure.core中的一个函数。这会收到警告,因为它可能导致意外行为。如果您知道自己不能使用clojure.core/num,则可以在命名空间声明中包含以下内容:

(ns my.ns
  (:refer-clojure :exclude [num])
  ....)

下一个问题:def不适用于创建本地值。使用def作为顶级形式以外的任何东西几乎总是一个错误,任何例外都需要非常明确的理由。它只能创建全局可变var。使用let进行特定于一个范围的绑定,例如在函数内部。

(defn -main
  [& args]
  (let [num 0
        num (if ... num (inc num))]
    ...))

这里,num没有变异,也没有创建为全局var,但是它是一个被第二个绑定所遮蔽的本地绑定。

答案 1 :(得分:0)

简短版本:

在Clojure中,有一些特殊的抽象来表示随时间变化的东西。最简单的一个称为atom。您使用值0启动原子,然后通过将函数inc应用于其值来更改原子。

(def n (atom 0))

(def -main 
  [& [args]]
  (if condition
    (swap! n inc))
  ...)

长版:

如果我理解正确,你就是在寻求一种绕不变性的方法。这意味着您要对一些概念(即网站访问者)进行建模,这些概念随着时间的推移会采用不同的值(即42)。 Clojure非常重视如何做到这一点,它提供的技术(STM)是语言的核心。 Clojure工作方式不同的原因是使并发更容易,但您不需要考虑并发以增加计数器。要理解Clojure背后的基本原理,我建议使用Rich Hickey的会谈,在这种情况下The Value of Values