Am I using atom? wrong or there is something else…

2019-06-18 11:02发布

问题:

Basically...

=> (atom? 5)

CompilerException java.lang.RuntimeException: Unable to resolve symbol: atom? in this context, compiling:(NO_SOURCE_PATH:1)

=> (atom? /a)

RuntimeException Invalid token: /a clojure.lang.Util.runtimeException (Util.java:156) RuntimeException Unmatched delimiter: ) clojure.lang.Util.runtimeException (Util.java:156)

=> (atom? "hello world")

CompilerException java.lang.RuntimeException: Unable to resolve symbol: atom? in this context, compiling:(NO_SOURCE_PATH:1)

So does anyone know what's happening?? I am using Eclipse Juno 4.2, the CounterClockwise plugin.

回答1:

What's called an atom in Clojure is something completely different than what's called an atom in other Lisps. In classic Lisp an atom is a single value, defined as being not null or not a cons cell (pair):

(define (atom? x)
  (not (or (pair? x)
           (null? x ))))

In Clojure an atom is a concurrency reference type. Atoms in Clojure can be either single-valued or collections/sequences, where updating (mutable state change) is guaranteed to happen atomically.

In Clojure there's far more reference types than the cons list in Lisp, and there's all the Java interop collection types to be reckoned with. That makes it hard to define a check on single-values.

If you do want to, the simplest check is to see if something can be counted. Looking at (source counted), it references clojure.lang.RT/count and countFrom. There, several classes / interfaces are specified, which I included in the following function:

=> (defn single-valued?
     [x]
     (not (or (nil? x) 
              (.. x getClass isArray)
              (some #(instance? % x) [clojure.lang.Counted
                                      clojure.lang.IPersistentCollection
                                      java.util.Collection
                                      java.util.Map]))))

=> (map single-valued? [1 "foo" \a 'x true not nil])
(true true true true true true false)

=> (map single-valued? ['(1 2 3 4)
                        [1 2 3 4]
                        {:a 1 :b 2}
                        #{1 2 3 4}
                        (seq [1 2 3 4])
                        (seq {:a 1 :b 2})
                        (seq "foo")
                        (int-array [1 2 3 4])
                        (seq [])])
(false false false false false false false false false)

Since (seq []) evaluates to nil it's not considered single-valued. Of course, java objects with multiple fields, as well as Clojure deftypes / defrecords will register as such, even though they're composite objects.



回答2:

I suspect you are confusing a clojure atom with an atom in something like scheme.

  • In scheme an atom is a fundamental unit.
  • In clojure an atom is one of clojure's reference types (like ref and var) that can be updated atomically.

This fits nicely with clojure's concurrency model.

e.g.

user> (def a (atom '(1 2 3)]); create an atom with value (1 2 3)
user> @a ; look up (deference) the atoms value
(1 2 3)
user> (swap! a (fn [v] (map inc v))) ; add 1 to each element, v is the
                                     ; old value of the atom. other threads will
                                     ; see the three values in a change atomically
user> @a
(2 3 4)
user> (reset! a '(5 10 15))
user> @a
(5 10 15)


回答3:

atom? is not a function.

You could use

(def x (atom 5))
(instance? clojure.lang.Atom x)


回答4:

You can create atom? function like this:

   (defn atom? [x]
          (not (coll? x))
    )


回答5:

The complement function returns the opposite of any predicate passed to it as argument, so you can make a atom? with it:

(defn atom?
  [x]
  ((complement coll?) x))

(atom? []) ;=> false
(atom? ()) ;=> false
(atom? {}) ;=> false
(atom? 4) ;=> true