I understand how apply works in a simple expression like this:
(apply + '(1 2 3))
I have come across a more complex example in a book I am reading.
(def make
(fn [class & args]
(let [seeded {:__class_symbol__ (:__own_symbol__ class)}
constructor (:add-instance-values (:__instance_methods__ class))]
(apply constructor seeded args))))
In the above example, seeded is a map and args is an ArraySeq.
Can anyone explain how apply works in this context?
In this case (apply constructor seeded args) is equivalent to calling (constructor seeded arg0 arg1 arg2 ...). It unwraps the last argument (which must be seqable) and appends them one by one to the list before evaluation.
For example, this: (apply + 1 [2 3]) unrolls to (+ 1 2 3).
It seems to be analogous to:
((make) MyClass) is equivalent to new MyClass()
((make) MyClass "foo" "bar" 3) is equivalent to new MyClass("foo", "bar", 3)
Related
In JavaScript, one can do the following:
function foo(arg1, arg2, arg3) {
...
}
var others = [ 'two', 'three' ];
foo('one', ...others); // same as foo('one', 'two', 'three')
In Clojure, "variable args" can be accepted like so:
(defn foo [arg1 & others]
...)
But to pass them in combination with other args, you have to do this:
(apply foo (concat '("one") others))
Which is frankly really ugly. It's also impossible when what you need to do is recur:
(apply recur (concat '("one") others)) ;; doesn't work
Is there a better way to do this? And if not, is there any way at all to accomplish it in the recur case?
But to pass them in combination with other args, you have to do this:
(apply foo (concat '("one") others))
You don't have to do that: apply is also a variadic function that can take arguments before the final sequence argument e.g.
(apply foo "one" others)
You can pass any number of individual arguments before the final sequence argument to apply.
user=> (defn foo [arg1 & args] (apply println arg1 args))
#'user/foo
user=> (apply foo "one" 2 "three" [4 "five" 6.0])
one 2 three 4 five 6.0
To further demonstrate, these calls to + are functionally equivalent:
(apply + 1 2 [3])
(apply + 1 [2 3])
(apply + [1 2 3])
It's also impossible when what you need to do is recur
recur is a special form, and apply doesn't work with it like it would a typical Clojure function.
is there any way at all to accomplish it in the recur case?
Not with apply. You can recur with variadic args, but you can't (apply recur ...).
I'm trying to do a really basic problem in clojure and having some trouble wrapping my head around how vectors/lists work.
First off when I am defining the arguments of a function that has a vector as an argument, how do you represent that as an argument.
Would you just have it as a single variable say
(defn example [avector] (This is where the function goes) )
Or do you have to list each element of a vector or list beforehand?
(defn example [vectorpart1 vectorpart2 vectorpart3 vectorpart4 ] (This is where the function goes) )
Also, in terms of vectors and lists, does anyone know of commands that allow you to figure out the length of a vector or get the first/last/or nth element?
To remove the element at index n from vector v:
(defn remove-indexed [v n]
(into (subvec v 0 n) (subvec v (inc n))))
For example,
(remove-indexed (vec (range 10)) 5)
;[0 1 2 3 4 6 7 8 9]
Lots can go wrong:
v might not be a vector.
n might not be a whole number.
n might be out of range for v (we require (contains? v n).
Clojure detects all these errors at run time. A statically typed language would detect 1 and 2 but not 3 at compile time.
Your first example defines a function that takes a single argument, regardless of type. If you pass a vector then that argument will be set to a vector.
(example [1 2 3 4]) ;; (= avector [1 2 3 4])
Your second example defines a function which takes four arguments. You need to pass four separate values for calls to this function to be valid.
(example [1] [2] [3] [4])
;; (= vectorpart1 [1])
;; (= vectorpart2 [2])
;; (= vectorpart3 [3])
;; (= vectorpart4 [4])
It sounds like you might be thinking about the destructuring syntax, which allows you to destructure values directly from an argument vector.
(defn example [[a b c d]]
())
The literal vector syntax in the argument definition describes a mapping between the items in the first argument and symbols available in the function scope.
(example [1 2 3 4])
;; (= a 1)
;; (= b 2)
;; (= c 3)
;; (= d 4)
The other function that also sits in this space is apply. Apply takes a list or vector of arguments and calls a function with them in-place.
(defn example [a b c]
(assert (= a 1))
(assert (= b 2))
(assert (= c 3)))
If we call this function with one vector, you'll get an arity exception.
(example [1 2 3])
;; ArityException Wrong number of args (1) passed ...
Instead we can use apply to pass the vector as arguments.
(apply example [1 2 3])
;; no errors!
You'll find all the methods you need to work with vectors in the Clojure docs.
If you want to remove a specific element, simply take the elements before it and the elements after it, then join them together.
(def v [1 2 3])
(concat (subvec v 0 1) (subvec v 2))
The short answer is that your first example is correct. You don't want to have to name every piece of your vector because you will commonly work with vectors of indeterminate length. If you want to do something with that vector where you need its parts to be assigned, you can do so by destructuring.
The slightly longer answer is that the list of parameters sent into any clojure defn already is a vector. Notice that the parameter list uses [] to wrap its list of args. This is because in Clojure code and data are the same thing. From this article...
Lisps are homoiconic, meaning code written in the language is encoded as data structures that the language has tools to manipulate.
This might be more than you're looking for but it's an important related concept.
Here'a a quick example to get you going... Pass a vector (of strings in this case) to a functions and it returns the vector. If you map over it however, it passes the contents of the vector to the function in succession.
user=> (def params ["bar" "baz"])
#'user/params
user=> (defn foo [params] (println params))
#'user/foo
user=> (foo params)
[bar baz]
nil
user=> (map foo params)
bar
baz
(nil nil)
Additionally, look at the Clojure cheatsheet to find more about things you can do with vectors (and everything else in Clojure).
I'm using the http-kit library to make some webcalls and it returns a promise for each.
When I try to deref any of the promises in the vector I get the following error
ArityException Wrong number of args (1) passed to: core/eval5473/fn--5474 clojure.lang.AFn.throwArity (AFn.ja
va:429)
Simplest way to reproduce in a repl without http-kit is as follows
Create collection
(def x [ [1 (promise)] [2 (promise)] [3 (promise)]])
Simple Test
(map first x)
;user=> (1 2 3)
My Test
(map #(vector % #%2) x)
;user=> ArityException Wrong number of args (1) passed to: user/eval109/fn--110 clojure.lang.AFn.throwArity (AFn.java
:429)
Update
I should probably delete this question. The problem had nothing to do with promises as Valentin noted below.
I was typing %2 and thinking second argument. When what i needed was #(second %). i.e second entry in first and only argument.
The function that is the second argument of map must accept only 1 argument in this case (which is meant to be an element of the seq that is being walked through).
You seem to be mistaking passing 2 arguments to a function and passing 1 argument that is a vector of 2 elements.
What you want to write is
(map (fn [[a b]] (vector a #b)) x)
...whereas what you're currently writing is equivalent to:
(map (fn [a b] (vector a #b)) x)
So this is not a problem about promises in fact.
I am doing the closure tutorial at http://clojurescriptkoans.com and I am stuck here: http://clojurescriptkoans.com/#functions/9
It looks like this
Higher-order functions take function arguments
(= 25 ( _ (fn [n] (* n n))))
I am supposed to fill in something at the underscore to make the expression true. I have no clue what to do.
The syntax simply consists of binding the function, and then calling it.
Since this is an exercise, I will show a similar situation rather than showing the exercise's solution:
user> ((fn [f] (f "abc")) (fn [s] (str s s s)))
"abcabcabc"
here I bind the argument of the first function to f, and call f with the argument "abc".
or you can use the short-hand notation:
#(%1 5)
Higher order functions takes functions as arguments.
Defining two functions
user=> (defn multiply [n] (* n n))
#'user/multiply
user=> (defn add [n] (+ n n))
#'user/add
Defining higher order function
user=> (defn highorderfn [fn number] (fn number))
#'user/highorderfn
Calling the higher order function
user=> (highorderfn multiply 5)
25
user=> (highorderfn add 5)
10
I want to create a function that takes in a required argument x, and either a optional argument opt1 OR a keyword argument opt2.
Right now I have
(defn foo x & [opt1 {:keys [opt2]}]
...
But the above signature only lets me pass in keyword argument opt2 when both x and opt1 is present like
(foo 'x 'opt1 {:opt2 'opt2})
not like this
(foo 'x {:opt2 'opt2})
Please help me create a function that takes a required argument X and either opt1 or opt2, where opt2 is a keyword argument.
Thank you.
EDIT: I want to do the same for other macros as well. So I still need to use the defmacro.
The problem is ambiguity. Consider a function (fn foo [x y & args]) that takes two optional arguments and then any number of keyword arguments. If you then call it like (foo :bar :baz), how does your program handle it? x => :bar, y => :baz? Or x and y not provided, with a single :bar => :baz keyword argument?
Even in Common Lisp, which has arguably even more flexibility than Clojure in parsing function parameters, mixing optional and keyword arguments is not recommended, according to at least one popular book.
Your best bet is to change all of your arguments to positional arguments, or all of your parameters to keyword arguments. If you use keyword arguments, you can use hash-map destructuring to provide defaults for "optional" keyword parameters.
user> (defn foo [& {:keys [x y bar]
:or {x 1 y 2 bar 3}}]
(prn [x y bar]))
#'user/foo
user> (foo)
[1 2 3]
nil
user> (foo :bar :baz)
[1 2 :baz]
nil
you have to check if the aditional arguments are keyword arguments or not anyway (I assume your or is an exclusive or) so you can do it like this:
(defn foo [& args]
(if (= (count args) 1)
(let [[opt1] args] (println opt1))
(let [{:keys [opt2]} args] (println opt2))))
check the arguments if they are keyword arguments or not. As you only have one optional parameter it's easy: check if there's only one as keyword arguments require two.