I'd like to have a function/macro for checking a list to have truthy value eventually, and I hope the evaluation would be lazy. Here is my illustrative implementation without lazy evaluation:
(defn eventual [cols]
(or (first cols) (if-let [rs (rest cols)]
(eventual rs))
false))
Here is a trivial example to illustrate:
(if (eventual [false (+ 1 2) (* 10000 10000)])
true
false)
I feel that there must be an implication with lazy evaluation. Maybe I'm just blinded at the moment. Please help to help. Thanks
You can check if a sequence contains at least one truthy element with some function:
(some identity col)
If you pass it a lazy sequence as col it will evaluate its contents up to the first truthy element and won't realise the rest:
(let [col (take
10
(iterate
#(do (println "Generating new value from " %) (inc %))
0))]
(some #(> % 5) col))
produces:
Generating new value from 0
Generating new value from 1
Generating new value from 2
Generating new value from 3
Generating new value from 4
Generating new value from 5
true
As you can see, values 6..9 are not produces at all.
You also should double check that the col you pass to some is really lazy and not already realised, because it might confuse you.
Your eventual function is as lazy as it can be. It searches eagerly for the first truthy item then stops. But it has problems:
It fails to terminate on an empty collection. (rest ()) is (),
which is truthy. Use next instead of rest. (next ()) is nil,
which is falsy.
It is truly recursive. It will blow the stack on a long enough
search. Try (eventual (repeat false)). Since the recursion is
tail-recursion, you can fix this by using recur in its place.
While we are at it, it is idiomatic to return nil, not false,
upon running out of a collection. So drop the final false.
We end up with
(defn eventual [cols]
(or (first cols) (if-let [rs (next cols)]
(recur rs))))
I'm a little queasy about what happens if cols is empty. Code based upon the source for some is clearer:
(defn eventual [coll]
(when (seq coll)
(or (first coll) (recur next coll))))
But using (some identity col), as Piotrek suggests, is probably best.
Related
In my first Clojure project everything turned out nicely except this part at the end:
(let [broken-signs (->> (:symbols field)
(map make-sign)
(filter broken?))
broken-count (count broken-signs)
unfixable-count (-> (filter (complement fixable?) broken-signs)
(count))]
(println
(if (> unfixable-count 0)
-1
(- broken-count unfixable-count))))
The indentation looks off and it does not feel functional, since I am reusing state in the let block. I basically count the number of broken signs and then the number of fixable signs. If any sign is unfixable, I print -1, otherwise I print the number of signs to be fixed.
If I mapped/filtered twice, I'd have duplicate code, but most of all it'd run slower. Is there a way of improving this code nevertheless?
EDIT: This is what I settled on
(defn count-broken-yet-fixable []
(let [broken (->> (:symbols field)
(map make-sign)
(filter broken?))
unfixable (remove fixable? broken)]
(when (empty? unfixable)
(count broken))))
(defn solve-task []
(if-let [result (count-broken-yet-fixable)]
result
-1))
(println (solve-task))
The subtraction was indeed not necessary and the count did not have to happen in the let block. Outputting the -1 on bad input also isn't the job of the function and is only part of the task.
I don't think there's anything "non-functional" or wrong with your approach. The indentation looks fine.
(let [broken (->> (:symbols field)
(map make-sign)
(filter broken?))
unfixable (remove fixable? broken)]
(when (seq unfixable)
(- (count broken) (count unfixable))))
You could replace filter (complement with remove
Could use pos? instead of (> n 0)
I might put two printlns inside the if, but really it's better to return a value
You could inline the broken-count binding, since it's only used in one place
I personally think this is easier to read with less threading macros
Since the need to count unfixables is conditional, you could test for values with seq first
If you return -1 as a sentinel value, I'd use nil instead; this happens naturally when the when condition isn't met
The conditional logic seems backwards: you return -1 when unfixable-count is positive, and only use its value when it's not positive (which means it's zero b/c count can't be negative), e.g. it could be rewritten as (- broken-count 0) and then just broken-count
(let [broken-signs (->> (:symbols field)
(map make-sign)
(filter broken?))]
(if-let [unfixable-signs (seq (remove fixable? broken-signs))]
-1
(- (count broken-signs) (count unfixable-signs)))
Your code is already pretty neat and well laid out. The only change I would want to do, is stay in the domain as long as possible - in this case the signs objects. And use the counts only much later.
The return value can then use print to do the actual actions.
Your code doesn't have side-effects (except for printing, which we'll fix), so I wouldn't say it's not functional. let is designed for building up intermediate values. In comments are some potential improvements.
; align here (controversial)
(let [broken-signs (->> (:symbols field)
(map make-sign)
(filter broken?))
broken-count (count broken-signs)
unfixable-count (->> broken-signs ; maybe emphasize non-function start
(filter (complement fixable?))
count)] ; no parens needed
;; don't print; just return number
(if (< 0 unfixable-count) ; prefer less-than (Elements of Clojure book)
-1
(- broken-count unfixable-count)))
I highly recommend the Clojure Style Guide for related suggestions.
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
I need to write a Clojure function which takes an unevaluated arbitrarily deep nesting of lists as input, and then determines if any item in the list (not in function position) is non-numeric. This is my first time writing anything in Clojure so I am a bit confused. Here is my first attempt at making the function:
(defn list-eval
[x]
(for [lst x]
(for [item lst]
(if(integer? item)
(println "")
(println "This list contains a non-numeric value")))))
I tried to use a nested for-loop to iterate through each item in every nested list. Trying to test the function like so:
=> (list-eval (1(2 3("a" 5(3)))))
results in this exception:
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn listeval.core/eval7976 (form-init4504441070457356195.clj:1)
Does the problem here lie in the code, or in how I call the function and pass an argument? In either case, how can I make this work as intended?
This happens because (1 ..) is treated as calling a function, and 1 is a Long, and not a function. First you should change the nested list to '(1(2 3("a" 5(3)))). Next you can change your function to run recursively:
(defn list-eval
[x]
(if (list? x)
(for [lst x] (list-eval lst))
(if (integer? x)
(println "")
(println "This list contains a non-numeric value"))))
=> (list-eval '(1(2 3("a" 5(3)))))
There is a cool function called tree-seq that does all the hard work for you in traversing the structure. Use it then remove any collections, remove all numbers, and check if there is anything left.
(defn any-non-numbers?
[x]
(->> x
(tree-seq coll? #(if (map? %) (vals %) %))
(remove (some-fn coll? number?))
not-empty
boolean))
Examples:
user=> (any-non-numbers? 1)
false
user=> (any-non-numbers? [1 2])
false
user=> (any-non-numbers? [1 2 "sd"])
true
user=> (any-non-numbers? [1 2 "sd" {:x 1}])
true
user=> (any-non-numbers? [1 2 {:x 1}])
false
user=> (any-non-numbers? [1 2 {:x 1 :y "hello"}])
true
If you want to consider map keys as well, just change (vals %) to (interleave (keys %) (vals %)).
quoting
As others have mentioned, you need to quote a list to keep it from being evaluated as
code. That's the cause of the exception you're seeing.
for and nesting
for will only descend to the nesting depth you tell it to. It is not a for loop,
as you might expect, but a sequence comprehension, like the the python list comprehension.
(for [x xs, y ys] y) will presume that xs is a list of lists and flatten it.
(for [x xs, y ys, z zs] z) Is the same but with an extra level of nesting.
To walk down to any depth, you'd usually use recursion.
(There are ways to do this iteratively, but they're more difficult to wrap your head around.)
side effects
You're doing side effects (printing) inside a lazy sequence. This will work at the repl,
but if you're not using the result anywhere, it won't run and cause great confusion.
It's something every new clojurian bumps into at some point.
(doseq is like for, but for side effects.)
The clojure way is to separate functions that work with values from functions that
"do stuff", like printing to the console of launching missiles, and to keep the
side effecting functions as simple as possible.
putting it all together
Let's make a clear problem statement: Is there a non number anywhere inside an
arbitrarily nested list? If there is, print a message saying that to the console.
In a lot of cases, when you'd use a for loop in other langs reduce is what you want in clojure.
(defn collect-nested-non-numbers
;; If called with one argument, call itself with empty accumulator
;; and that argument.
([form] (collect-nested-non-numbers [] form))
([acc x]
(if (coll? x)
;; If x is a collection, use reduce to call itself on every element.
(reduce collect-nested-non-numbers acc x)
;; Put x into the accumulator if it's a non-number
(if (number? x)
acc
(conj acc x)))))
;; A function that ends in a question mark is (by convention) one that
;; returns a boolean.
(defn only-numbers? [form]
(empty? (collect-nested-non-numbers form)))
;; Our function that does stuff becomes very simple.
;; Which is a good thing, cause it's difficult to test.
(defn warn-on-non-numbers [form]
(when-not (only-numbers? form)
(println "This list contains a non-numeric value")))
And that'll work. There already exists a bunch of things that'll help you walk a nested structure, though, so you don't need to do it manually.
There's the clojure.walk namespace that comes with clojure. It's for when you have
a nested thing and want to transform some parts of it. There's tree-seq which is explained
in another answer. Specter is a library which is
a very powerful mini language for expressing transformations of nested structures.
Then there's my utils library comfy which contains reduce versions of the
functions in clojure.walk, for when you've got a nested thing and want to "reduce" it to a single value.
The nice thing about that is that you can use reduced which is like the imperative break statement, but for reduce. If it finds a non-number it doesn't need to keep going through the whole thing.
(ns foo.core
(:require
[madstap.comfy :as comfy]))
(defn only-numbers? [form]
(comfy/prewalk-reduce
(fn [ret x]
(if (or (coll? x) (number? x))
ret
(reduced false)))
true
form))
Maybe by "any item in the list (not in function position)" you meant this?
(defn only-numbers-in-arg-position? [form]
(comfy/prewalk-reduce
(fn [ret x]
(if (and (list? x) (not (every? (some-fn number? list?) (rest x))))
(reduced false)
ret))
true
form))
I am trying to read numbers from input and printing them back in Clojure till I read the number 42. A really basic thing to make sure I know how to read input. Taken from codechef
I have written this program. Might not be good clojure.
(defn universe
[]
(let [num (line-seq (java.io.BufferedReader. *in*))]
(if (not= num 42)
(do
(println num)
(recur (universe))
)
)
)
)
My understanding is that line-seq lazily evaluates from whatever reader is given. In this case the standard input.
So I have let it be num. Then if num is not 42 I print it and then recursively call universe. But it throws exception
Mismatched argument count to recur, expected: 0 args, got: 1,
I have seen an example and recur does take an argument. Looking at the official documentation I couldn't see the syntax for this. So why am I getting this error?
recur does not take the name of the location to recur to. Instead the recur special form jumps back up to the closest function or loop expression, whichever is closer. It then passes it different arguments. This lets you go through the same block of code repeatedly as you work through the data, and there is no function call overhead.
In your case it's recurring up to the function call:
(defn universe [] ...
and trying to pass it an argument, which fails because universe, the function, does not accept any arguments. perhaps you intended to put a loop expression around the if?
user> (defn universe
[]
(let [numbers (line-seq (java.io.BufferedReader. *in*))]
(loop [numbers numbers]
(let [num (first numbers)]
(if (not= (Integer/parseInt num) 42)
(do
(println num)
(recur (rest numbers))))))))
#'user/universe
user> (universe)
3 ;; typed 3
nil ;; typed 42
or where you intending to recur back to the top of the function, in which case just call (recur) instead of (recur universe)
I know at a certain point in my code that a list only has one element so I obtain it with
(first alist)
But I would also like the code to break if the list has more than one elements to alert me of the erroneous condition. What's an idiomatic way to achieve that in Clojure ?
Replace first with an only (or other poetically named) function with a pre-condition where you want to make your assertion:
(defn only [x] {:pre [(nil? (next x))]} (first x))
(only [1])
=> 1
(only [1 2])
=> AssertionError Assert failed: (nil? (next x)) user/only (NO_SOURCE_FILE:1)
This will blow up on a collection with anything other than one element. Works fine on lazy seqs as well.
(defn only
"Gives the sole element of a sequence"
[coll]
(if (seq (rest coll))
(throw (RuntimeException. "should have precisely one item, but had at least 2"))
(if (seq coll)
(first coll)
(throw (RuntimeException. "should have precisely one item, but had 0")))))
I can't immediately think of a nice concise, idiomatic way to do this.
Option 1 is that there isn't one, because this is a bit of an odd situation. If you know there's supposed to be exactly one element, why is it in a list in the first place?
Option 2 is that there is one, and someone will come along and tell off for not seeing it :)
That said, in your situation I'd probably write something like:
(let [[item & rest] alist]
(if (nil? rest)
(throw (IllegalArgumentException. "Expected a single-element list"))
item))
Possibly more simply, you could also just do (count alist) and make sure it had exactly one item. The code above, though, has the nice property that it won't force evaluation beyond the head of the list, but depending on your use case that might not be a concern.
The Tupelo library has this function defined as a core sanity-check, allowing one to "unwrap" scalar values from length-1 vectors/lists and document the intended result. The definition is simplicity itself:
(defn only
"(only coll)
Ensures that a sequence is of length=1, and returns the only value present.
Throws an exception if the length of the sequence is not one.
Note that, for a length-1 sequence S, (first S), (last S) and (only S) are equivalent."
[coll]
(let [coll-seq (seq coll)
num-items (count coll-seq)]
(when-not (= 1 num-items)
(throw (IllegalArgumentException. (str "only: num-items must=1; num-items=" num-items))))
(clojure.core/first coll-seq)))
You can find a similar function in the SuchWow library and other places.