Is it possible to use both recur and post-condition functionality in the same Clojure function? I was hoping to throw an exception using the post-condition, but Clojure appears to be trying to wrap the exception throwing code after the recur somehow, so (just as a stupid example) functions like this cannot be evaluated.
(defn countup [x]
{:pre [(>= x 0)]
:post [(>= % 0)]}
(if (< x 1000000)
(recur (inc x))
x))
I'm using Clojure 1.3 at the moment.
If you look at the implementation of defn at https://github.com/clojure/clojure/blob/35bd89f05f8dc4aec47001ca10fe9163abc02ea6/src/clj/clojure/core.clj#L4580-L4585 you'll see that the body of a function gets modified so that tail calls get pushed out of the tail-position. One way around this is to use an auxiliary function to call the recur'd function and put the post-condition on that instead:
(defn- countup* [x]
(if (< x 1000000)
(recur (inc x))
x))
(defn countup [x]
{:pre [(>= x 0)]
:post [(>= % 0)]}
(countup* x))
(countup 999999)
;=> 1000000
(countup -1)
; Assert failed: (>= x 0)
"recur" is like "goto to the begin of the block with that parameters".
You cannot place any code after it because of it does not save things in the stack, so don't know where it came from (and what checks it should perform after running).
For example, (loop [] (recur)) will loop forever without consuming stack.
In your example I expect :post to be executed once, when x==1000000.
You can totally do this and in many cases the ability to get pre/post conditions may be worth the speed lost by not using the loop/recur special form.
The recur special form wont do it for ya because it is not really a function call. You could make your own wrapper function that does the bounds checking in pre and post conditions after all the code runs, or you can use the built in trampoline function and save a little effort and have the conditions checked on every iteration (you need to decide if you want that)
You can turn this into a recursive function with out blowing the stack:
(defn countup [x]
{:pre [(>= x 0)]
:post [(or (ifn? %) (>= % 0))]}
(if (< x 1000000)
#(countup (inc x))
x))
(trampoline (countup 0))
1000000
This changes the post condition to ignore the intermediate cases (where it returns the function to run next) and only verify the final result.
The idea behind trampolining is to avoid blowing the stack by having each iteration of the function return the call to the next function instead of calling it directly. this way one two stack frames are used (one for the trampoline and one for the current step)
IMHO the easiest (no trampolining or using auxiliary functions) would be something like this:
(defn countup [x]
{:pre [(>= x 0)]
:post [(>= % 0)]}
(loop [x x]
(if (< x 1000000)
(recur (inc x))
x)))
(countup 999999)
1000000
(countup -1)
; Evaluation aborted.
So, just inject an auxiliary loop (identical to the function signature).
Related
So I recently learned that I cannot modify parameters in a Clojure function.
I have a big function that takes in a list, then does about 5 different steps to modify it and then returns the output.
But what I'm doing now is
(defn modify [my-list other params]
(if (nil? my-list)
my-list
(let [running my-list]
(def running (filter #(> (count %) 1) my-list))
(def running (adjust-values running))
; a whole bunch of other code with conditions that depend on other parameters and that modify the running list
(if (< (count other) (count my-list))
(def running (something))
(def running (somethingelse)))
(def my-map (convert-list-to-map my-list))
(loop [] .... ) loop through map to do some operation
(def my-list (convert-map-to-list my-map)
running
)))
This doesn't seem correct, but I basically tried writing the code as I'd do in Python cuz I wasn't sure how else to do it. How is it done in Clojure?
Instead of using def inside the modify function, you can have a let with multiple bindings. Actually, def is typically only used at the top-level to define things once and is not meant to be a mechanism to allow for mutability. Here is an example of a let with multiple bindings, which is similar to introducing local variables except that you cannot change them:
(defn modify2 [my-list other params]
(if (nil? my-list)
my-list
(let [a (filter #(> (count %) 1) my-list)
b (adjust-values a)
c (adjust-values1 other b)
d (adjust-values2 params c)]
d)))
Here we introduce new names a, b, c and d for each partial result of the final computation. But it is OK to just have a single binding that gets rebound on each line, that is, you could have a single binding running that gets rebound:
(defn modify2 [my-list other params]
(if (nil? my-list)
my-list
(let [running (filter #(> (count %) 1) my-list)
running (adjust-values running)
running (adjust-values1 other running)
running (adjust-values2 params running)]
running)))
Which one you prefer is a matter of style and taste, there are up and downsides with either approach. The let form to introduce new bindings is a powerful construct, but for this specific example where we have a pipeline of steps, we can use the ->> macro that will generate the code for us. So we would instead write
(defn modify3 [my-list other params]
(if (nil? my-list)
my-list
(->> my-list
(filter #(> (count %) 1))
adjust-values
(adjust-values1 other)
(adjust-values2 params))))
It takes the first macro argument and then passes it in as the last parameter to the function call on the following line. Then the result of that line goes in as a last parameter to the line that follows and so on. If a function call just takes a single argument as is the case for adjust-values in the example above, we don't need to surround it with parentheses. See also the similar -> macro.
To see which code is generated by the ->>, we can use macroexpand:
(macroexpand '(->> my-list
(filter #(> (count %) 1))
adjust-values
(adjust-values1 other)
(adjust-values2 params)))
;; => (adjust-values2 params (adjust-values1 other (adjust-values (filter (fn* [p1__7109#] (> (count p1__7109#) 1)) my-list))))
Added: Summary
If your computation has a pipeline structure, the -> and ->> macros can be used to express that computation concisely. However, if your computation has a general shape where, you will want to use let to associate symbols with results of sub-expressions, so that you can use those symbols in subsequent expressions inside the let form.
Yes, this is the way Clojure was designed: as a functional language with
immutable data (of course with fallbacks to what the host offers if you
want or need it).
So if you want to modify data in consecutive steps, then you can either
chain the calls (looks nicer with the threading macros). E.g.
(->> my-list
(filter #(> (count %) 1))
(adjust-values))
This is the same as:
(adjust-values
(filter #(> (count %) 1)
my-list))
If you prefer to do that in steps (e.g. you want to print intermediate
results or you need them), you can have multiple bindings in the let. E.g.
(let [running my-list
filttered (filter #(> (count %) 1) running)
adjusted (adjust-values filtered)
running ((if (< (count other) (count adjusted)) something somethingelse))
my-map (convert-list-to-map my-list)
transformed-map (loop [] .... )
result (convert-map-to-list transformed-map)]
result)
This returns the adjusted values and holds on to all the things in
between (this does nothing right now with the intermediate results, just an example).
And aside: never ever def inside other forms unless you know what you
are doing; def define top level vars in a namespace - it's not a way
to define mutable variables you can bang on iteratively like you might
be used to from other languages).
I have some code which I refactored only to find out something was broken with loop. After some debugging I found out loop and with-redefs do not play well together. I realize it may not make sense to use with-redefs inside a loop, but I didn't expect it to not work. I'm not sure if its intentional or not.
This is an MCVE I've created to demonstrate the "problem":
(loop [test 3]
(with-redefs []
(if (zero? test)
"done"
(recur (dec test)))))
This gives me:
Mismatched argument count to recur, expected: 0 args, got: 1
Removing the with-redefs works as expected:
(loop [test 3]
(if (zero? test)
"done"
(recur (dec test))))
and returns "done".
What is the reason the first piece of code does not work? Is this intentional?
The explanation is in the macroexpansion of with-redefs:
(macroexpand-1
'(with-redefs []
(if (zero? test)
"done"
(recur (dec test)))))
returns:
(with-redefs-fn {}
(fn []
(if (zero? test)
"done"
(recur (dec test)))))
where you can see that because a new fn has been introduced, the recur is going to refer to that fn rather than the farther-away loop (which explains the arity exception).
There are a variety of other macros that are "incompatible" with loop in this way, because the recur needs to be in the tail position with respect to loop, and if the recur occurs inside a macro call, the macro may be manipulating the code such that the recur is no longer in tail position.
For with-redefs in particular (and a variety of other situations), a workaround could be:
(loop [test 3]
(let [[recur? val]
(with-redefs []
(if (zero? test)
[false "done"]
[true (dec test)]))]
(if recur?
(recur val)
val)))
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'm a total beginer in Clojure and I've ran into a problem that I'm not even sure if can be done in Closure.
So the issue is the following. I've implemented a function that computes the prime numbers from an interval (up to a limit).
(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 [])
)
)
This works just fine. But what I want now is to have a global variable that should store on each method call the primes that are found in a variable to lookup later. In other languages like Python, Ruby or Scala I would just do this by having a Set to which I add entries before returing from the function. But in Clojure I have no ideea how to go around this.
Basically what I tried is, have somewhere global declared:
(def PRIMES_FOUND_SO_FAR #{})
And then somehow on return add the entries to this variable. Is this possible at all in Clojure and if so how? I've tried on other variables to change their values using either swap! and atom, or set! but could not make it to work here in any situation.
Firstly, I strongly advice you to read about clojure code conventions What are Clojure's Naming Conventions?
Let me show you some improvements of your code.
1) Applying clojure naming conventions.
Then switch from (+ variable 1) to (inc variable) (the same optimizations with dec).
Also (= FIND_MORE_PRIMES false) can be simply replaced by find-more-primes?
And finally the condition (= 0 smthng) could be written in more idiomatic style (zero? smthng)
Now your code looks a bit more readable:
(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) Now we should remove redundant do call cause it wraps the only one function call.
And the last trick is to apply tail recursion (http://clojure.org/special_forms#Special%20Forms--(recur%20exprs*)) via swapping entire gather-primes-in-range calls to recur
(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))))
And here comes time for answering your question. You wouldn't benefit from this approach
(def PRIMES_FOUND_SO_FAR #{})
because you haven't opportunity to change this set. The only thing that you can deal with it is to create some new immutable data structure from that one.
As #georgek mention you could simply use atom in this particular case.
(def PRIMES_FOUND_SO_FAR (atom #{}))
Adding new prime number to atom:
(swap! PRIMES_FOUND_SO_FAR conj prime-number)
Deref atom for extracting the value:
#PRIMES_FOUND_SO_FAR ;; or (deref PRIMES_FOUND_SO_FAR)
-> #{2 3 5 7 11}
Anyway your code is a little bit imperative but you should always remember that clojure is functional language with immutable data structures, functions as arguments, etc. using global variables is not good idea at all. BTW thats how your function should look like in clojure style:
(defn gather-primes-in-range [start end target-number]
(take target-number (filter is-prime? (range start end))))
for those who have spent too much time searching how to modify a global (root) variable in clojure here is the solution:
(def user-remote-browser "anonymous")
you can modify it from anywhere i suppose but in the same namepace with:
(alter-var-root #'user-remote-browser (constantly name))
alter-var-root use a function to modify a variable,
constantly create a constant function returning here the string name