I was writing an answer for this challenge, when I needed to give a recursive function an optional parameter. I ended up with something kind of equivalent to:
(defn func [a & [b?]]
(if b?
b?
(recur a a)))
My intent was for b? to act as an optional parameter. If it wasn't supplied, it would be defaulted to nil via destructuring.
Instead of running though, it gave me an error:
(func 1)
UnsupportedOperationException nth not supported on this type: Long clojure.lang.RT.nthFrom (RT.java:947)
After some debugging, I realized that for some reason the rest parameter wasn't a list as I'd expect, but just the passed number! The error was coming about because it tried to destructure the number.
I can fix it by getting rid of the wrapper list in the parameter list:
(defn func [a & b]
...
But this just looks wrong. I know the rest parameter should be a list, but b is actually just a number. If I use "unoptimized" recursion, it works as I'd expect:
(defn func2 [a & [b?]]
(if b?
b?
(func2 a a)))
(func2 1)
=> 1
Can anyone explain what's going on here?
This appears to be a known difference
; Note that recur can be surprising when using variadic functions.
(defn foo [& args]
(let [[x & more] args]
(prn x)
(if more (recur more) nil)))
(defn bar [& args]
(let [[x & more] args]
(prn x)
(if more (bar more) nil)))
; The key thing to note here is that foo and bar are identical, except
; that foo uses recur and bar uses "normal" recursion. And yet...
user=> (foo :a :b :c)
:a
:b
:c
nil
user=> (bar :a :b :c)
:a
(:b :c)
nil
; The difference arises because recur does not gather variadic/rest args
; into a seq.
It's the last comment that describes the difference.
Related
I am trying figure out how to programmatically evaluate a list of functions.
Lets say that I have this code:
(defn foo
[]
(println "foo"))
(defn bar
[]
(println "bar"))
(def funcs [foo bar] )
I want execute all functions of funcs in a programmatically way.
I am tried use eval, but no succcess.
Thanks for any help.
Use for if you want the return values, and are OK with lazy evaluation (your functions are not guaranteed to be called until you access the return value), and doseq if you don't need the values and are doing this for immediate side effects.
(doseq [f [foo bar]]
(f))
(def fs
(for [f [foo bar]]
(f)))
You can use juxt:
((apply juxt funcs))
You can simply map over the functions with a call:
(map #(%) funcs)
doall and dorun can be used to force effects. doall retains results, while dorun just returns nil.
(defn foo [] :foo) ; no side-effects
(doall (map #(%) [foo foo]))
;=> (:foo :foo)
(defn print-foo [] (println (foo))) ; with side-effects
(dorun (map #(%) [print-foo print-foo]))
;=> :foo
; :foo
; nil
How can I make these three snippets work?
(defn bar [a b c] (println a b c))
> (bar :a :b :c)
:a :b :c
(defn foo [a & args] (bar a args)) ;; some magic is needed here.
> (foo :a :b :c)
MoralException: You're a bad person for trying this.
I have looked all over for how to do this. I tried lots of things like (apply bar [a args]) but that's an ArityException (which makes sense). What can I do?
You don't need to wrap arguments to apply in a vector.
(apply bar a args)
Intervening arguments are prepended to args.
I have functions that behave different depending on which keyword arguments have values supplied. For this question, I am wondering about functions that behave slightly differently depending on the type of argument supplied.
Example function, that increments each element of a list:
(defn inc-list [& {:keys [list-str list]}]
(let [prepared-list (if-not (nil? list) list (clojure.string/split list-str #","))]
(map inc prepared-list)))
Does it make sense to make a multimethod that instead tests for the type of argument? I have not used multimethods before, not sure about right time to use them. If it is a good idea, would the below example make sense?
Example:
(defn inc-coll [col] (map inc col))
(defmulti inc-list class)
(defmethod inc-list ::collection [col] (inc-col col))
(defmethod inc-list String [list-str]
(inc-col
(map #(Integer/parseInt %)
(clojure.string/split list-str #",")))
First things first: (map 'inc x) treats each item in x as an associative collection, and looks up the value indexed by the key 'inc.
user> (map 'inc '[{inc 0} {inc 1} {inc 2}])
(0 1 2)
you probably want inc instead
user> (map inc [0 1 2])
(1 2 3)
Next, we have an attempt to inc a string, the args to string/split out of order, and some spelling errors.
If you define your multi to dispatch on class, then the methods should be parameterized by the Class, not a keyword placeholder. I changed the multi so it would work on anything Clojure knows how to treat as a seq. Also, as a bit of bikeshedding, it is better to use type, which offers some distinctions for differentiating inputs in Clojure code that class does not offer:
user> (type (with-meta {:a 0 :b 1} {:type "foo"}))
"foo"
Putting it all together:
user> (defn inc-coll [col] (map inc col))
#'user/inc-coll
user> (defmulti inc-list type)
nil
user> (defmethod inc-list String [list-str]
(inc-coll (map #(Integer/parseInt %) (clojure.string/split list-str #","))))
#<MultiFn clojure.lang.MultiFn#6507d1de>
user> (inc-list "1,10,11")
(2 11 12)
user> (defmethod inc-list clojure.lang.Seqable [col] (inc-coll (seq col)))
#<MultiFn clojure.lang.MultiFn#6507d1de>
user> (inc-list [1 2 3])
(2 3 4)
Your first example is an obfuscated application of a technique called dispatching on type. It is obfuscated because in a message-passing style the caller must convey the type to your function.
Since in every case you only use one of the keyword args, you could as well define it as:
(defn inc-list
[m l]
(->> (case m ;; message dispatch
:list l
:list-str (map #(edn/read-string %) (str/split #",")) l)
(map inc)))
The caller could be relieved from having to pass m:
(defn inc-list
[l]
(->> (cond (string? l) (map ...)
:else l)
(map inc)))
This technique has the main disadvantage that the operation procedure code must be modified when a new type is introduced to the codebase.
In Clojure it is generally superseeded by the polymorphism construct protocols, e. g.:
(defprotocol IncableList
(inc-list [this]))
Can be implemented on any type, e. g.
(extend-type clojure.lang.Seqable
IncableList
(inc-list [this] (map inc this)))
(extend-type String
IncableList
(inc-list [this] (map #(inc ...) this)))
Multimethods allow the same and provide additional flexibility over message-passing and dispatching on type by decoupling the dispatch mechanism from the operation procedures and providing the additivity of data-directed programming. They perform slower than protocols, though.
In your example the intention is to dispatch based on type, so you don't need multimethods and protocols are the appropriate technique.
In clojure, I would like to apply a function to all the elements of a sequence and return a map with the results where the keys are the elements of the sequence and the values are the elements of the mapped sequence.
I have written the following function function. But I am wondering why such a function is not part of clojure. Maybe it's not idiomatic?
(defn map-to-object[f lst]
(zipmap lst (map f lst)))
(map-to-object #(+ 2 %) [1 2 3]) => {1 3, 2 4, 3 5}
Your function is perfectly idiomatic.
For a fn to be part of core, I think it has to be useful to most people. What is part of the core language and what is not is quite debatable. Just think about the amount of StringUtils classes that you can find in Java.
My comments were going to get too long winded, so...
Nothing wrong with your code whatsoever.
You might also see (into {} (map (juxt identity f) coll))
One common reason for doing this is to cache the results of a function over some inputs.
There are other use-cases for what you have done, e.g. when a hash-map is specifically needed.
If and only if #3 happens to be your use case, then memoize does this for you.
If the function is f, and the resultant map is m then (f x) and (m x) have the same value in the domain. However, the values of (m x) have been precalculated, in other words, memoized.
Indeed memoize does exactly the same thing behind the scene, it just doesn't give direct access to the map. Here's a tiny modification to the source of memoize to see this.
(defn my-memoize
"Exactly the same as memoize but the cache memory atom must
be supplied as an argument."
[f mem]
(fn [& args]
(if-let [e (find #mem args)]
(val e)
(let [ret (apply f args)]
(swap! mem assoc args ret)
ret))))
Now, to demonstrate
(defn my-map-to-coll [f coll]
(let [m (atom {})
g (my-memoize f m)]
(doseq [x coll] (g x))
#m))
And, as in your example
(my-map-to-coll #(+ 2 %) [1 2 3])
;=> {(3) 5, (2) 4, (1) 3}
But note that the argument(s) are enclosed in a sequence as memoize handles multiple arity functions as well.
Say I want to make a Clojure macro that does the following:
If x is a list calling the function "bar"
return :foobar
else
return x as a string
However, bar is not defined; rather, it is only used internally in the macro, like so:
(foo (bar))
:foobar
(foo 1)
"1"
One could do something like this:
(defmacro foo [x]
(if (and (coll? x) (= (first x) 'bar))
:foobar
(str x)))
This works great for the (bar) case, as well as for literals. However, symbols do not work as intended, giving the symbol name instead of its associated value:
user=> (def y 2)
#'user/y
user=> (foo y)
"y"
One could call the eval function on x before passing it to str, but this causes problem when using the function in let:
user=> (let [a 3 b (foo a)] b)
java.lang.UnsupportedOperationException: Can't eval locals (NO_SOURCE_FILE:89)
Presumably, the problem has to do with symbol resolution, so maybe we try to work something out with syntax-quote:
(defmacro foo [x]
`(if (and (coll? '~x) (= (first '~x) '~'bar))
:foobar
(str ~x)))
Now, the problem is with (foo (bar)), as this expands the else clause to (clojure.core/str (bar)), which throws an exception, as bar is not defined. I then tried doing some shenanigans with eval:
(defmacro foo [x]
`(if (and (coll? '~x) (= (first '~x) '~'bar))
:foobar
(eval '(str ~x))))
But this doesn't work with let bindings again:
user=> (let [a 1 b (foo a)] b)
java.lang.Exception: Unable to resolve symbol: a in this context (NO_SOURCE_FILE:153)
So I'm really at a loss here. It seems as though fixing one problem breaks another. Is there a better, simpler way of making this macro such that it works in the following cases:
In let bindings
With (bar)
With symbols
P.S. If anybody is curious as to why I want to do this, I'm working on a DSL for Yahoo's YQL service and I want to be able to do things like (select (table :t) ...), but I need to be able to pass in symbols, as well as literals.
I believe this should work.
(defmacro foo [x]
(if (and (coll? x) (= (first x) 'bar))
:foobar
`(str ~x)))