In Clojure, when and why does one want to use a named anonymous function? E.g.,
((fn add-five [x] (+ x 5)) 3))
In ClojureDocs, one example's comment says that it is useful in stack traces. Can one give an example of that?
There are two reasons to name anonymous functions (or at least two reasons that I've done so). The first is that giving it a name tells a later reader (perhaps yourself 6 months down the line) what the heck that anonymous function is supposed to do.
The second is (as you mention) to have better information in a stack trace to point you at the right location in your code when a failure occurs. Functions are compiled into classes and the class name includes a (munged) version of the function name. When you have a stack trace, it will include that class name and thus point you semantically towards the proper location.
user=> (filter (fn [x] (/ 100 x)) [100 50 0])
ArithmeticException Divide by zero clojure.lang.Numbers.divide (Numbers.java:158)
user=> (pst *e)
ArithmeticException Divide by zero
clojure.lang.Numbers.divide (Numbers.java:158)
clojure.lang.Numbers.divide (Numbers.java:3784)
user/eval8/fn--9 (NO_SOURCE_FILE:3)
clojure.core/filter/fn--6908 (core.clj:2790)
...
nil
user=> (filter (fn hundred-div [x] (/ 100 x)) [100 50 0])
ArithmeticException Divide by zero clojure.lang.Numbers.divide (Numbers.java:158)
user=> (pst *e)
ArithmeticException Divide by zero
clojure.lang.Numbers.divide (Numbers.java:158)
clojure.lang.Numbers.divide (Numbers.java:3784)
user/eval14/hundred-div--15 (NO_SOURCE_FILE:5) ;; <---
clojure.core/filter/fn--6908 (core.clj:2790)
...
Apart from being useful in stacktraces, I suppose you could use it when you need an anonymous function to be recursive, as it would be able to call itself.
For instance:
(fn factorial[n]
(if (<= n 1)
1
(* n (factorial (- n 1)))))
Although recursing like this in Clojure is a bit dangerous, as it could potentially cause stack overflows.
Named anonymous functions can be useful when they refer to themselves, and also by being printed with their name:
user=> ((fn [] (throw (Exception. "unnamed"))))
Exception unnamed user/eval805/fn--806 (NO_SOURCE_FILE:1)
user=> ((fn myfn [] (throw (Exception. "named"))))
Exception named user/eval809/myfn--810 (NO_SOURCE_FILE:1)
Related
Given that :post takes a form that gets evaluated later (e.g. {:post [(= 10 %)]}). How could one dynamically pass a 'pre-made' vector of functions to :post?
For example:
(def my-post-validator
[prediate1 predicate2 predicate3])
(defn foo [x]
{:post my-post-validator}
x)
this throws a syntax error
Don't know how to create ISeq from: clojure.lang.Symbol
With my fuzzy understanding, it's because defn is a macro, and the thing that allows the % syntax in :post is that it's quoted internally..?
I thought maybe I then use a macro to pass a 'literal' of what I wanted evaluated
(defmacro my-post-cond [spec]
'[(assert spec %) (predicate2 %) (predicate n)])
example:
(defn foo [x]
{:post (my-post-cond :what/ever)}
x)
However, this attempt gives the error:
Can't take value of a macro
Is there a way to pass a vector of things to :post rather than having to define it inline?
You can't pass a vector of predefined predicates, but you can combine multiple predicates under a single name and use that name in :post:
(defn my-post-cond [spec val]
(and
;; Not sure if this is exactly what you want,
;; given that `val` becomes an assert message.
(assert spec val)
(predicate2 val)
;; You used `n` - I assume it was supposed to be `%`.
(predicate val)))
(defn foo [x]
{:post [(my-post-cond :what/ever %)]}
x)
I started off as a fan of pre- and post-conditions, but I've changed over the years.
For simple things, I prefer to use Plumatic Schema to not only test inputs & outputs, but to document them as well.
For more complicated tests & verifications, I just put in an explicit assert or similar. I also wrote a helper function in the Tupelo library to reduce repetition, etc when debugging or verifying return values:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn oddly
"Transforms its input. Throws if result is not odd"
[x]
(let [answer (-> x (* 3) (+ 2))]
(with-result answer
(newline)
(println :given x)
(assert (odd? answer))
(println :returning answer))))
(dotest
(is= 5 (oddly 1))
(throws? (oddly 2)))
with result
------------------------------------
Clojure 1.10.3 Java 11.0.11
------------------------------------
Testing tst.demo.core
:given 1
:returning 5
:given 2
Ran 2 tests containing 2 assertions.
0 failures, 0 errors.
Passed all tests
So with either the println or assert, the returned value is easy to see. If it fails the assert, an Exception is thrown as normal.
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))
We can define and use an anonymous function like this:
repl=> (#(+ 10 %) 1)
11
But -> macro won't accept such anonymous functions. Say I want to add 10 and then multiply by 2. I'd try to write:
(-> 5 #(+ 10 %) #(* 2 %))
But that is not the correct code for some reason, the correct code is
(-> 5 (+ 10) (* 2))
What is the difference between (+ 10) and #(+ 10 %), and why won't -> macro accept anonymous functions defined with #()?
Here's my attempt at an explanation. There are two parts.
First, the anonymous literal syntax. When you write #(+ 10 %), it gets expanded into something that is functionally similar to the following:
(fn [x] (+ 10 x))
For ex.
=> (macroexpand '(#(+ 10 %))
Would return something like:
(fn* [p1__7230#] (+ 10 p1__7230#))
The second part. When you use the threading macro, as the docs say, the macro expands by inserting the first argument as the second item into the first form. And if there are more forms, inserts the first form as the second item in second form, and so on.
The key term here is second item. It doesn't care about what forms you are providing as arguments, it will just do an expansion using that rule.
So, to combine both the points, when you use
(-> 5 #(+ 10 %) #(* 2 %))
following the rules, it gets expanded into something that is functionally similar to this
(fn (fn 5 [x] (+ 10 x)) [y] (* 2 y))
which doesn't compile.
Also, as a side note, the form (+ 10) is not an anonymous function. It is a partial function call that gets updated with arguments during macro expansion. And by 'partial', I mean in the literal sense, not in the functional programming sense.
Update
To explain why it works when you enclose the anonymous literal within parentheses (as a comment on the question says), you can infer the results from these two rules. For ex.
=> (macroexpand '(#(+ 10 %)))
would result in the functional equivalent of
((fn [x] (+ 10 x)))
So, when an item is inserted in its second place, it would look like
((fn [x] (+ 10 x)) 5)
Which is equivalent to
(#(+ 10 %) 5)
I'm a Clojure beginner and I want to understand the -> macro
This code works:
(-> '(1 2 3) reverse)
But this doesn't even compile and I don't know how to deal with the error message:
user=> (-> '(1 2 3) (fn [x] (reverse x)))
CompilerException java.lang.IllegalArgumentException: Parameter declaration quote should be a vector, compiling:(NO_SOURCE_PATH:1:1)
How can I fix this?
I use macroexpand and friends a lot when unexpected things start happening. If you use these here it becomes really obvious what's going on.
user=> (macroexpand-1 '(-> '(1 2 3) (fn [x] (reverse x))))
(fn (quote (1 2 3)) [x] (reverse x))
I think seeing this it's pretty obvious that the (quote (1 2 3) should not be the first arg to fn.
We can also see that the ugly double-parens approach fixes it:
user=> (macroexpand-1 '(-> '(1 2 3) ((fn [x] (reverse x)))))
((fn [x] (reverse x)) (quote (1 2 3)))
Side note that tripped me up: you have to use macroexpand-1 to get a result here. If you use macroexpand or clojure.walk/macroexpand-all it'll blow up (with your exception) after the first expansion, since fn itself is a macro, and is being called with bad syntax after the first expansion.
I'm trying to understand when clojure's lazy sequences are lazy, and when the work happens, and how I can influence those things.
user=> (def lz-seq (map #(do (println "fn call!") (identity %)) (range 4)))
#'user/lz-seq
user=> (let [[a b] lz-seq])
fn call!
fn call!
fn call!
fn call!
nil
I was hoping to see only two "fn call!"s here. Is there a way to manage that?
Anyway, moving on to something which indisputably only requires one evaluation:
user=> (def lz-seq (map #(do (println "fn call!") (identity %)) (range 4)))
#'user/lz-seq
user=> (first lz-seq)
fn call!
fn call!
fn call!
fn call!
0
Is first not suitable for lazy sequences?
user=> (def lz-seq (map #(do (println "fn call!") (identity %)) (range 4)))
#'user/lz-seq
user=> (take 1 lz-seq)
(fn call!
fn call!
fn call!
fn call!
0)
At this point, I'm completely at a loss as to how to access the beginning of my toy lz-seq without having to realize the entire thing. What's going on?
Clojure's sequences are lazy, but for efficiency are also chunked, realizing blocks of 32 results at a time.
=>(def lz-seq (map #(do (println (str "fn call " %)) (identity %)) (range 100)))
=>(first lz-seq)
fn call 0
fn call 1
...
fn call 31
0
The same thing happens once you cross the 32 boundary first
=>(nth lz-seq 33)
fn call 0
fn call 1
...
fn call 63
33
For code where considerable work needs to be done per realisation, Fogus gives a way to work around chunking, and gives a hint an official way to control chunking might be underway.
I believe that the expression produces a chunked sequence. Try replacing 4 with 10000 in the range expression - you'll see something like 32 calls on first eval, which is the size of the chunk.
A lazy sequence is one where we evaluate the sequence as and when needed. (hence lazy). Once a result is evaluated, it is cached so that it can be re-used (and we don't have to do the work again). If you try to realize an item of the sequence that hasn't been evaluated yet, clojure evaluates it and returns the value to you. However, it also does some extra work. It anticipates that you might want to evaluate the next element(s) in the sequence and does that for you too. This is done to avoid some performance overheads, the exact nature of which is beyond my skill-level. Thus, when you say (first lz-seq), it actually calculates the first as well as the next few elements in the seq. Since your println statement is a side effect, you can see the evaluation happening. Now if you were to say (second lz-seq), you will not see the println again since the result has already been evaluated and cached.
A better way to see that your sequence is lazy is :
user=> def lz-seq (map #(do (println "fn call!") (identity %)) (range 400))
#'user/lz-seq
user=> (first lz-seq)
This will print a few "fn call!" statements, but not all 400 of them. That's because the first call will actually end up evaluating more than one element of the sequence.
Hope this explanation is clear enough.
I think its some sort of optimization made by repl.
My repl is caching 32 at a time.
user=> (def lz-seq (map #(do (println "fn call!") (identity %)) (range 100))
#'user/lz-seq
user=> (first lz-seq)
prints 32 times
user=> (take 20 lz-seq)
does not print any "fn call!"
user=> (take 33 lz-seq)
prints 0 to 30, then prints 32 more "fn call!"s followed by 31,32