In Clojure I do this
(println (cond false "don't care" "otherwise" "otherwise"))
In Common LISP this would be
(print (cond (nil "don't care") ("otherwise") ))
Is there a way to get this kind of simplified cond in Clojure?
Version which includes a fix for that Alex Taggart noticed below. Passes all the test cases shown in the test. It allows for arbitrary clauses passed to my-cond to be length 1 instead of 2 which results in the length 1 clause being both the test for truthiness and the result if it is true. Based off my limited experience with CL I actually think this behavior is different from what cond does but seems to be in line with how I've interpreted what you're asking for. Kotarak's answer seems to line up with the CL one as using the last statement in the CL cond seems to match up with using the :else clause in the Clojure version.
Regardless here is a solution where it should allow any clause to be a length of one and use that for both the truth test and result.
(defmacro my-cond
[& others]
(if others
(let [more# (next others)
extra-clauses# (if more# `(my-cond ~#more#))
clause# (first others)]
(if (= 2 (count clause#))
`(if ~(first clause#) ~(second clause#) ~extra-clauses#)
`(if ~(first clause#) ~(first clause#) ~extra-clauses#)))))
(deftest my-cond-works
(is (= 3 (my-cond (false 1) (false 2) (3))))
(is (= "otherwise" (my-cond (false "don't care") ("otherwise"))))
(is (= nil (my-cond (:one nil) ("otherwise"))))
(is (= "care" (my-cond (1 "care") ("otherwise"))))
(is (= "otherwise" (my-cond (false "care") ("otherwise") (true "true"))))
(is (= "silly" (my-cond (nil "no") (nil) ("yes" "silly")))))
I'd really advise translating the CL over to the Clojure form of cond. I would place the mental overhead of allowing the CL syntax along with the Clojure syntax in the same project as not worth saving time in translating it now. Looking at the code in the future after becoming used to how Clojure's cond and trying to remember why the other syntax is there seems not worth the time saved by not translating.
Below version fails as Alex Taggart says below. Keeping it here so his comment makes sense.
The below version does:
(defmacro my-cond [[if1 then1] & others]
(when (or if1 then1 others)
(let [extra-clauses# (if others `(my-cond ~#others))]
(if then1
`(if ~if1 ~then1 ~extra-clauses#)
`(if ~if1 ~if1 ~extra-clauses#)))))
user> (my-cond (false "first") (nil nil) ("otherwise"))
"otherwise"
I believe the clojure version was intended to have fewer parens. You can certainly write your own cond-ish macro to do what you want.
Here is a simple implementation (i.e. does not implement the full CL version)...
(defmacro my-cond [[if1 then1] & others]
(if others
`(if ~if1 ~then1 (my-cond ~#others))
`(if ~if1 ~then1)))
And you can then...
(my-cond (false 1) (false 2) (3 3)) ; results in 3
An important feature of the CL cond is that if any of the operands of cond is a singleton, then the element within the singelton is evaluated, and if that value is non-nil, it is returned without evaluating it a second time.
(cond
(a 100)
((f 1 2 3))
(b 200))
This form evaluates to 100 if a is true, else to the value of (f 1 2 3) if that is non-nil, else to 200 if b is non-nil, else to nil.
I believe what you need is the following.
(defmacro my-cond [[if1 & then1] & others]
(when (or if1 then1 others)
(let [extra-clauses# (if others `(cl-cond ~#others))]
(if then1
`(if ~if1 (do ~#then1) ~extra-clauses#)
`(or ~if1 ~extra-clauses#)))))
Related
I want to know if this is the right way to loop through an collection:
(def citrus-list ["lemon" "orange" "grapefruit"])
(defn display-citrus [citruses]
(loop [[citrus & citruses] citruses]
(println citrus)
(if citrus (recur citruses))
))
(display-citrus citrus-list)
I have three questions:
the final print displays nil, is it ok or how can avoid it?
I understand what & is doing in this example but I donĀ“t see it in other cases, maybe you could provide a few examples
Any other example to get the same result?
Thanks,
R.
First of all your implementation is wrong. It would fail if your list contains nil:
user> (display-citrus [nil "asd" "fgh"])
;;=> nil
nil
And print unneeded nil if the list is empty:
user> (display-citrus [])
;;=> nil
nil
you can fix it this way:
(defn display-citrus [citruses]
(when (seq citruses)
(loop [[citrus & citruses] citruses]
(println citrus)
(if (seq citruses) (recur citruses)))))
1) it is totally ok: for non-empty collection the last call inside function is println, which returns nil, and for empty collection you don't call anything, meaning nil would be returned (clojure function always returns a value). To avoid nil in your case you should explicitly return some value (like this for example):
(defn display-citrus [citruses]
(when (seq citruses)
(loop [[citrus & citruses] citruses]
(println citrus)
(if (seq citruses) (recur citruses))))
citruses)
user> (display-citrus citrus-list)
;;=> lemon
;;=> orange
;;=> grapefruit
["lemon" "orange" "grapefruit"]
2) some articles about destructuring should help you
3) yes, there are some ways to do this. The simplest would be:
(run! println citrus-list)
Answering your last question, you should avoid using loop in Clojure. This form is rather for experienced users that really know what they do. In your case, you may use such more user-friendly forms as doseq. For example:
(doseq [item collection]
(println item))
You may also use map but keep in mind that it returns a new list (of nils if your case) that not sometimes desirable. Say, you are interested only in printing but not in the result.
In addition, map is lazy and won't be evaluated until it has been printed or evaluated with doall.
For most purpose, you can use either map, for or loop.
=> (map count citrus-list)
(5 6 10)
=> (for [c citrus-list] (count c))
(5 6 10)
=> (loop [[c & citrus] citrus-list
counts []]
(if-not c counts
(recur citrus (conj counts (count c)))))
[5 6 10]
I tend to use map as much of possible. The syntax is more concise, and it clearly separates the control flow (sequential loop) from the transformation logic (count the values).
For instance, you can run the same operation (count) in parallel by simply replacing map by pmap
=> (pmap count citrus-list)
[5 6 10]
In Clojure, most operations on collection are lazy. They will not take effect as long as your program doesn't need the new values. To apply the effect immediately, you can enclose your loop operation inside doall
=> (doall (map count citrus-list))
(5 6 10)
You can also use doseq if you don't care about return values. For instance, you can use doseq with println since the function will always return nil
=> (doseq [c citrus-list] (println c))
lemon
orange
grapefruit
The case doc says
Unlike cond and condp, case does a constant-time dispatch... All manner of constant
expressions are acceptable in case.
I would like to benefit from case's constant-time dispatch to match on Java enums. Java's switch statement works well with enums, but doing the following in Clojure:
(defn foo [x]
(case x
java.util.concurrent.TimeUnit/MILLISECONDS "yes!"))
(foo java.util.concurrent.TimeUnit/MILLISECONDS)
Results in: IllegalArgumentException No matching clause: MILLISECONDS
Are enums not supported in case? Am I doing something wrong? Must I resort to cond or is there a better solution?
The problem here is that case's test constants, as described in the docs, " must be compile-time literals". So, rather than resolving java.util.concurrent.TimeUnit/MILLISECONDS, the literal symbol 'java.util.concurrent.TimeUnit/MILLISECONDS is being tested against.
(foo java.util.concurrent.TimeUnit/MILLISECONDS) ; IllegalArgumentException
(foo 'java.util.concurrent.TimeUnit/MILLISECONDS) ; yes!
Instead, the solution is to dispatch on the .ordinal of the Enum instance, which is what Java itself does when compiling switch statements over enums:
(defn foo [x]
(case (.ordinal x)
2 "yes!"))
You can wrap this pattern in a macro which correctly evaluates the case ordinals for you:
(defmacro case-enum
"Like `case`, but explicitly dispatch on Java enum ordinals."
[e & clauses]
(letfn [(enum-ordinal [e] `(let [^Enum e# ~e] (.ordinal e#)))]
`(case ~(enum-ordinal e)
~#(concat
(mapcat (fn [[test result]]
[(eval (enum-ordinal test)) result])
(partition 2 clauses))
(when (odd? (count clauses))
(list (last clauses)))))))
You could use use a cond on the name of the enumm
(case (.name myEnumValue)
"NAME_MY_ENUM" (println "Hey, it works!"))
Seems to me very simple compared to the alternatives
Here's a simpler solution that just uses equality checking on the cases -
(defn cases [v & args]
(let [clauses (partition 2 2 args)]
(some #(when (= (first %) v) (second %)) clauses)))
=> (cases EventType/received EventType/send "A" EventType/received "B")
=> "B"
How to make clojure to count '() as nil?
For example:
How to make something like
(if '() :true :false)
;to be
:false
;Or easier
(my-fun/macro/namespace/... (if '() :true :false))
:false
And not just if. In every way.
(= nil '()) or (my-something (= nil '()))
true
And every code to be (= '() nil) save.
(something (+ 1 (if (= nil '()) 1 2)))
2
I was thinking about some kind of regural expression. Which will look on code and replace '() by nil, but there are some things like (rest '(1)) and many others which are '() and I am not sure how to handle it.
I was told that macros allow you to build your own languages. I want to try it by changing clojure. So this is much about "How clojure works and how to change it?" than "I really need it to for my work."
Thank you for help.
'() just isn't the same thing as nil - why would you want it do be?
What you might be looking for though is the seq function, which returns nil if given an empty collection:
(seq [1 2 3])
=> (1 2 3)
(seq [])
=> nil
(seq '())
=> nil
seq is therefore often used to test for "emptiness", with idioms like:
(if (seq coll)
(do-something-with coll)
(get-empty-result))
You say you would like to change Clojure using the macros. Presently, as far as I know, this is not something you could do with the "regular" macro system (terminology fix anyone?). What you would really need (I think) is a reader macro. Things I have seen online (here, for example) seem to say that there exists something like reader macros in Clojure 1.4--but I have no familiarity with this because I really like using clooj as my IDE, and it currently is not using Clojure 1.4. Maybe somebody else has better info on this "extensible reader" magic.
Regardless, I don't really like the idea of changing the language in that way, and I think there is a potentially very good alternative: namely, the Clojure function not-empty.
This function takes any collection and either returns that collection as is, or returns nil if that collection is empty. This means that anywhere you will want () to return nil, you should wrap it not-empty. This answer is very similar to mikera's answer above, except that you don't have to convert your collections to sequences (which can be nice).
Both using seq and not-empty are pretty silly in cases where you have a "hand-written" collection. After all, if you are writing it by hand (or rather, typing it manually), then you are going to know for sure whether or not it is empty. The cases in which this is useful is when you have an expression or a symbol that returns a collection, and you do not know whether the returned collection will be empty or not.
Example:
=> (if-let [c (not-empty (take (rand-int 5) [:a :b :c :d]))]
(println c)
(println "Twas empty"))
;//80% of the time, this will print some non-empty sub-list of [:a :b :c :d]
;//The other 20% of the time, this will return...
Twas empty
=> nil
What about empty? ? It's the most expressive.
(if (empty? '())
:true
:false)
You can override macros and functions. For instance:
(defn classic-lisp [arg]
(if (seq? arg) (seq arg) arg))
(defn = [& args]
(apply clojure.core/= (map classic-lisp args)))
(defmacro when [cond & args]
`(when (classic-lisp ~cond) ~#args))
Unfortunately, you can't override if, as it is a special form and not a macro. You will have to wrap your code with another macro.
Let's make an if* macro to be an if with common-lisp behavior:
(defmacro if* [cond & args]
`(if (classic-lisp ~cond) ~#args)
With this, we can replace all ifs with if*s:
(use 'clojure.walk)
(defn replace-ifs [code]
(postwalk-replace '{if if*} (macroexpand-all code)))
(defmacro clojure-the-old-way [& body]
`(do ~#(map replace-ifs body)))
Now:
=> (clojure-the-old-way (if '() :true :false) )
:false
You should be able to load files and replace ifs in them too:
(defn read-clj-file [filename]
;; loads list of clojure expressions from file *filename*
(read-string (str "(" (slurp filename) ")")))
(defn load-clj-file-the-old-way [filename]
(doseq [line (replace-ifs (read-clj-file filename))] (eval line))
Note that I didn't test the code to load files and it might be incompatible with leiningen or namespaces. I believe it should work with overriden = though.
Are there non-macro versions of and and or in Clojure?
Update: In this case I don't care about the short circuiting.
or
The function some "Returns the first logical true value of (pred x) for any x in coll, else nil."
So you could use (some identity coll) for or. Note that its behaviour will differ from or when the last value is false: it will return nil where or would return false.
and
If you don't need to know the value of the last form in the coll vector, you can use (every? identity coll) for and. This will differ from the behaviour of the and macro in that it returns true if all of its arguments are truthy. See larsmans' answer if you need the result of the last form.
Let land stand for "logical and", then they're trivial to define:
(defn land
([] true)
([x & xs] (and x (apply land xs))))
Or, slightly closer to the standard and behavior:
(defn land
([] true)
([x] x)
([x & xs] (and x (apply land xs))))
And similarly for or.
This actually came up as a topic on clojure-dev recently. Rich Hickey ultimately concluded they should be added to core for 1.3 as every-pred and any-pred (logged as CLJ-729). I think further discussions there have led them to now be called every-pred (the and variant) and some-fn (the or variant). The final version was just recently committed to master.
If you mean functions: no, and they cannot be. The reason is that function forms always evaluate all their arguments before applying the function to their value. You do not want that here.
Most cases where you want this there is a more idiomatic way to do it, but just an exercise, it is possible to defer evaluation by thunking. Thunk your expressions and give them to logical operators that evaluate the the thunk when needed, using the standard and/or:
(defn &&* [& fns]
(cond (= 1 (count fns)) ((first fns))
:otherwise
(and ((first fns)) (apply &&* (next fns)))))
(defn ||* [& fns]
(cond (= 1 (count fns)) ((first fns))
:otherwise
(or ((first fns)) (apply ||* (next fns)))))
Example use:
(map
(partial apply &&*)
(map (partial map constantly) ;; thunk all of these values
[["yes" "no"]
[false true]
[true "something"]
[true "something" "false"]]))
("no" false "something" "false")
Another Example:
(defmacro thunks
"convert expressions into thunks to prevent advance evaluation"
[& exprs]
(let [fns# (map (fn [e] `(fn [] ~e)) exprs)]
(cons 'vector fns#)))
(apply ||* (thunks (+ 1 2) false (* 1 5)))
3
(apply &&* (thunks (+ 1 2) false (* 1 5)))
false
(apply &&* (thunks (+ 1 2) (* 1 5)))
5
Does not exist?
Does exist:
Clojure 1.2.0
user=> (not= 1 2)
true
user=> (not= 1 1)
false
user=> (doc not=)
-------------------------
clojure.core/not=
([x] [x y] [x y & more])
Same as (not (= obj1 obj2))
nil
Amusingly, you could define != to be the same as not= if you really wanted:
user=> (def != not=)
#'user/!=
user=> (!= 2 2)
false
user=> (!= 2 3)
true
In a lot of clojure code the ! char means that a function changes the state of something in a way you should watch out for. the clojure transients make heavy use of these
compare-and-set!
alter-meta!
conj!
persistent!
check out http://clojure.github.com/clojure/ and search for the ! character. these functions usually come with caveats like "must be free of side effects"
According to my google search "not=" is the equivalent but I have zero personal familiarity with Clojure.
Is there some reason not= doesn't suit your purposes?