I was solving problems in 4clojure and got stuck at Problem 46 or example
(= true ((__ >) 7 8))
where we need to fill in the _
Basically I need to create a function that would take in another function as an argument but don't know where to go with that. Also, the evaluation kind of confuses me, if I create an anonymous function
(fn [f] ())
which takes in the function > I don't know how to pass in the other arguments for > to operate on.
I don't want the answer, just some direction.
Given what ever you put in the blank will take > and then be evaluated as a function what you need is a function that returns a function.
You have this:
(fn [f] ())
How do we get that to return a function?
(fn [f] (fn [something here] (something here)))
Now all you have to do is fill out the 'something here's.
The function you are looking for is the one that returns a function that reverses its arguments and applies to the original function:
(fn [f]
(fn [x y]
(f y x)))
Related
I am pretty new with Clojure language.
While reading about Clojure functions, I find the example #([%]). So I try to use it as follows:
(def test1 #([%]))
(test1 5)
As a result, I get the following error:
ArityException Wrong number of args (0) passed to: PersistentVector clojure.lang.AFn.throwArity (AFn.java:429)
which seems to be that it is trying to invoke the array I wanted to return.
After digging a while, I find a solution as follows:
(def test1 #(-> [%]))
(test1 5)
I would have some questions:
Why doesn't the #([%]) work? What did I do with the expression #([x])?
In the correct example I am using the thread-first macro. Based on its documentation, it is used to pass an argument to the next function, e.g. (-> x (+ 1)). In this case I do not even have a function to pass to; *what is the next function in this context? I can not realize why it solved my issue
Question 1
The syntax #([%]) translates into: "Create a function that when called will evaluate the expression ([%]) with % being the first (and only) argument passed to the function". This expression has the syntax of a function call with [%] being the function to be called. You can see what goes on using a macroexpand:
(macroexpand '#([%]))
;; => (fn* [p1__6926#] ([p1__6926#]))
The class of persistent vectors in clojure is clojure.lang.PersistentVector. They implement the IFn interface for arity 1, so that you can treat the vector as a function mapping an index to an element. But they do not implement arity 0, which is what you are trying to call. In other words, your code does not work:
(def test1 #([%]))
(test1 5) ;; ERROR
However, if you would pass the argument 0 to your function [%], you would get back the element:
(def test1 #([%] 0))
(test1 5)
;; => 5
Do you see what happens? However, for the thing you are trying to do, there is a better way: The [a b c] syntax is just sugar for calling (vector a b c). So to get something that works, you can just do
(def test1 vector)
(test1 5)
;; => [5]
Question 2
The thread-first macros has the syntax of (-> x f0 f1 f2 ...) where x is the initial value and f0, f1 and so on are function calls with their first argument left out to be replaced by the value that is being piped through. Again we can use macroexpand to understand:
(macroexpand '(-> x f0 f1 f2))
;; => (f2 (f1 (f0 x)))
But in your case, the function calls are left out. To analyze your second example, we need to use clojure.walk/macroexpand-all for a full expansion, because we have nested macros:
(clojure.walk/macroexpand-all '#(-> [%]))
;; => (fn* [p1__6995#] [p1__6995#])
although, we can also look at it one step at a time:
(macroexpand '#(-> [%]))
;; => (fn* [p1__7000#] (-> [p1__7000#]))
(macroexpand '(-> [p1__7000#]))
;; => [p1__7000#]
So to answer your question: There is no next function in (-> [%]). The number of next functions can be any non-negative number, including zero, which is the case with (-> [%]).
#Rulle gives an exhaustive explanation of the details.
May I point out the most important part? Your reference from Clojure.org says:
;; DO NOT DO THIS
#([%])
So, don't do that! It is a silly trick that will only cause confusion & pain. Why would you want that???
I am trying to pass some vectors containing a list of nodes in to a function in clojure the function works if i was to type the variables in but i am not sure how to pass a single variable from each vector in at a time.
(def ItemPickUp [:a1 :Mail])
(def ItemDestinations [:Storage :a1])
(def Robot {[ItemPickUp] [ItemDestinations]})
(defn shortestPath [g start dest]
(let [not-destination? (fn [[vertex _]] (not= vertex dest))]
(-> (shortest-paths g start)
(->> (drop-while not-destination?))
first
(nth 2))))
(apply shortestPath G (apply first Robot)((apply second Robot)))
I need to pass a variable from the ItemPickUp and ItemDestination into shortestPath using robot but instead of passing one of the variable in it passes both :a1 and :Mail and vice versa for the other one.
How do i go about passing each variable in individually so the first two variables for the first iteration is :a1 and :Storage and so on?
Thanks.
In Clojure this is normally done with map - it takes a function f and any number of collections and lazily produces a sequence of (f (first coll1) (first coll2)...), (f (second coll1) (second coll2)...)...
So it should just be
(map (partial shortestPath G) ItemPickup ItemDestinations)
(Some other functional languages distinguish one-collection mapping from multi-collection zipping - I believe Haskell is influential here. It needs this because its functions have fixed arities, so you have zipWith,zipWith3 etc. Having the parenteses to indicate number of arguments means Lisps don't have to deal with that.)
In case of (def Robot [[ItemPickUp] [ItemDestinations]]) and you want to use it you can do:
(apply map (partial shortestPath G) Robot)
Apply in this case will reduce to:
(map (partial shortestPath G) (first Robot) (second Robot))
and of course will throw ArityException if Robot has other than two elements.
You can think about apply as moving parentheses (function call) to his first argument and taking out parentheses from last argument (if some).
Question:How to I turn Read-Line into a usable vector to pass in to another function to do work.
(defn iAcceptUserInputAsAVector [a b c] ( )) ; I do work with the userInput as a vector
(defn input []
(let [userKeyboardInput ( read-line)]
(
[userKeyboardInput]; doesnt work I tried (vector userKeyboardInput)
)
)
)
Update 1: My Progress so far thanks to noisesmith
(defn input []( let [userKeyBoardInput [(read-line)]]
(println userKeyBoardInput)
))
Update 2 My current solution and working... I imagine it can be done so much better
(defn split-by-whitespace [s]
(clojure.string/split s #"\s+"))
(defn input []
( let [userKeyBoardInput [(split-by-whitespace(read-line))]]
;Then insanity below is because I have to convert to integers, list then a vector. Why? map returns list
;which I dont need instead I need a vector []
;Also the initial entry is returned as [[]] which I need to convert to [] for map to be able to take
;it as parameter. There probably a better way. Show me...
(def x (into[](map #(Integer/parseInt %) (into [](flatten [userKeyBoardInput])))))
(println x)
(myLoopFunc x); basically it takes my vector and does something .. not important
))
Parenthesis are not a grouping construct in Clojure.
There are two major errors in your code:
((read-line)) this gets a string via read-line and then attempts to execute it. This will fail, strings do not implement IFn.
([userKeyboardInput]) if the code even got this far, this would fail as well, because you can't call a vector as a function without providing any arguments.
In clojure, wrapping something in parens usually means you want to execute it as a function. Adding extraneous parens will easily break things.
I will comment on how to improve your current solution (source code comments removed, linenumbers added):
01: (defn split-by-whitespace [s]
02: (clojure.string/split s #"\s+"))
03:
04: (defn input []
05: ( let [userKeyBoardInput [(split-by-whitespace(read-line))]]
06: (def x (into[](map #(Integer/parseInt %) (into [](flatten [userKeyBoardInput])))))
07: (println x)
08: (myLoopFunc x)
09:
10: ))
The function split-by-whitespace looks good. Note that it already returns a vector. (Suppose read-line returned "6 34 12". Then split-by-whitespace will give you ["6" "34" "12"]). So when you call it in line 5, you do not need the [] around your call, because you don't want a vector in a vector. Therefore, you no longer need flatten. You can just map over the vector you already have. Then a function that did the desired transformation for you would look like this:
(defn string->number-vector ; name is verbose but meaning is clear :)
[s]
(into []
(map #(Integer/parseInt %)
(split-by-whitespace s))))
And you might call it with (myLoopFunc (string->number-vector (read-line))).
I'm a newbie to Clojure and I was wondering if there is a way to define a function that can be called like this:
(strange-adder 1 2 3 :strange true)
That is, a function that can receive a variable number of ints and a keyword argument.
I know that I can define a function with keyword arguments this way:
(defn strange-adder
[a b c & {:keys [strange]}]
(println strange)
(+ a b c))
But now my function can only receive a fixed number of ints.
Is there a way to use both styles at the same time?
unfortunately, no.
The & destructuring operator uses everything after it on the argument list so it does not have the ability to handle two diferent sets of variable arity destructuring groups in one form.
one option is to break the function up into several arities. Though this only works if you can arrange it so only one of them is variadic (uses &). A more universal and less convenient solution is to treat the entire argument list as one variadic form, and pick the numbers off the start of it manually.
user> (defn strange-adder
[& args]
(let [nums (take-while number? args)
opts (apply hash-map (drop-while number? args))
strange (:strange opts)]
(println strange)
(apply + nums)))
#'user/strange-adder
user> (strange-adder 1 2 3 4 :strange 4)
4
10
Move the variadic portion to the the tail of the argument list and pass the options as a map:
(defn strange-adder [{:keys [strange]} & nums]
(println strange)
(apply + nums))
(strange-adder {:strange true} 1 2 3 4 5)
There is no formal support that I know of, but something like this should be doable:
(defn strange-adder
[& args]
(if (#{:strange} (-> args butlast last))
(do (println (last args))
(apply + (drop-last 2 args)))
(apply + args)))
I don't know if this can be generalized (check for keywords? how to expand to an arbitrary number of final arguments?). One option may be putting all options in a hashmap as the final argument, and checking if the last argument is a hashmap (but this would not work for some functions that expect arbitrary arguments that could be hashmaps).
I'm writing a small wrapper for a Java API, and I create a listener like this
(defn conv-listener [f]
(proxy [com.tulskiy.keymaster.common.HotKeyListener] [] (onHotKey [hotKey] (f))))
Is there a way in which I can make this work whether the function f accepts 1 or zero arguments. (Ie. if f does not accept arguments, just call it with (f), if it accepts an argument - which will be the value of the hotkey in this case - call it with (f hotKey))?
No. Just call (f hotKey) all the time, and if someone wants to use a function that ignores hotKey then they can just pass something like (fn [_] (...do whatever...)).
This is how we ended up solving it (pull request from Nic Marsh):
(defn arg-count [function]
"Counts the number of arguments the given function accepts"
(let [method (first (.getDeclaredMethods (class function)))
parameters (.getParameterTypes method)]
(alength parameters)))
(defn call-with-correct-args [function & args]
"Call the given function on all given args that it can accept"
(let [amount-accepted (arg-count function)
accepted-args (take amount-accepted args)]
(apply function accepted-args)))
(defn- conv-listener [function]
"Takes a function with one argument, which will get passed the keycode, and creates a listener"
(proxy [com.tulskiy.keymaster.common.HotKeyListener] []
(onHotKey [hotKey] (call-with-correct-args function hotKey))))
http://github.com/houshuang/keymaster-clj