I need a function that thinly wraps amazonica's sqs/receive-message in order to add a default wait time. The function requires a queue URL, and then accepts any number of optional named parameters, which should be passed along to sqs/receive-message untouched. I would like to call it like this:
(my-receive-message "https://sqs.us-east-1.amazonaws.com/123/test-q"
:max-number-of-messages 10
:delete true)
This should result in a call to sqs/receive-message like this:
(sqs/receive-message :queue-url "https://sqs.us-east-1.amazonaws.com/123/test-q"
:wait-time-seconds 20
:max-number-of-messages 10
:delete true)
This is something I find myself wanting to do fairly often, but I haven't found a nice way yet. Is there an idiomatic way to do this?
Use apply over the merged parameters.
(defn my-receive-message
[url & {:as args}]
(apply sqs/receive-message (-> {:queue-url url
:wait-time-seconds 20}
(merge args)
seq
flatten)))
You could always write a macro:
(defmacro my-receive-message [url & opts]
`(sqs/receive-message
~#(flatten (seq (merge {:queue-url url :wait-time-seconds 20}
(apply hash-map opts))))))
(Note that this does pretty much exactly the same thing as Guillermo's function. The main difference is that you don't have to apply sqs/receive-message -- the unquote-splicing (~#) takes care of the apply part implicitly.)
Related
I'm using ring-cors and trying to pass a cors-policy for the (wrap-cors) function. This is what my code looks like:
(def cors-policy
{:access-control-allow-origin [#"http://localhost:8080"]
:access-control-allow-methods [:get :put :post]})
(def dev-handler (-> #'japi/routes
wrap-reload
wrap-params
(wrap-cors cors-policy) ;; <- Here
wrap-json-response
(wrap-defaults api-defaults)
push-state/handle))
This results in an error:
No value supplied for key: {:access-control-allow-origin
#{"http://localhost:8080"}, :access-control-allow-methods #{:get :post :put}}
Looking at the source code for (wrap-cors) it looks like the error is coming from trying to apply (hash-map) to my cors-policy map. It seems like I cannot pass a map definition but instead I have to pass the keys/values explicitly when calling (wrap-cors). Any ideas to work around this?
I've tried (apply hash-map cors-policy) in the repl and that works fine, however when passing a dummy handler such as (wrap-cors identity cors-policy) this again results in the same error.
Edit: cfrick's answer is correct, note however that I had to remove shadow-cljs' (push-state/handle) handler at the end of my dev-handler definition for my setup to work.
The wrapper uses a "pattern" that is sometimes seen and focuses on
"human consumption" of the function. It takes the "rest" of the
arguments and turns the pairs of it into a map. This is already "meh"
for humans and is utterly bad for machines (e.g. to pass as arguments).
You have to do the call it like this:
(wrap-cors $handler :a 1 :b 2)
So the easiest way from here would be:
(def cors-policy
[:a 1
:b 2])
(apply wrap-cors $handler cors-policy)
Or if you want to stick with the map (IMHO a good approach), you have to
flatten the map beforehand. e.g.
(apply wrap-cors $handler (into [] cat cors-policy))
But with the use of the threading macro -> this becomes harder to do
now (-> is just a macro and the resulting code would be (apply $handler wrap-cors ...) which is unintended.
So at this point I'd add my own defn that just takes the handler
again. E.g. something like
(defn cors-wrapper
[handler config-map]
(apply wrap-cors handler (into [] cat config-map)))
So I'm trying to make a Clojure macro that makes it easy to interop with Java classes utilizing the Builder pattern.
Here's what I've tried so far.
(defmacro test-macro
[]
(list
(symbol ".queryParam")
(-> (ClientBuilder/newClient)
(.target "https://www.test.com"))
"key1"
(object-array ["val1"])))
Which expands to the below
(.
#object[org.glassfish.jersey.client.JerseyWebTarget 0x107a5073 "org.glassfish.jersey.client.JerseyWebTarget#107a5073"]
queryParam
"key1"
#object["[Ljava.lang.Object;" 0x16751ba2 "[Ljava.lang.Object;#16751ba2"])
The desired result is:
(.queryParam
#object[org.glassfish.jersey.client.JerseyWebTarget 0x107a5073 "org.glassfish.jersey.client.JerseyWebTarget#107a5073"]
"key1"
#object["[Ljava.lang.Object;" 0x16751ba2 "[Ljava.lang.Object;#16751ba2"])
I guess the . is causing something to get evaluated and moved around? In which case the solution would to be to quote it. But how can I quote the results of an evaluated expression?
My goal is to convert maps into code that build the object by have the maps keys be the functions to be called and the values be the arguments passed into the Java functions.
I understand how to use the threading and do-to macros but am trying to make request building function data driven. I want to be able take in a map with the key as "queryParam" and the values as the arguments. By having this I can leverage the entirety on the java classes functions only having to write one function myself and there is enough of a 1 to 1 mapping I don't believe others will find it magical.
(def test-map {"target" ["https://www.test.com"]
"path" ["qa" "rest/service"]
"queryParam" [["key1" (object-array ["val1"])]
["key2" (object-array ["val21" "val22" "val23"])]] })
(-> (ClientBuilder/newClient)
(.target "https://www.test.com")
(.path "qa")
(.path "rest/service")
(.queryParam "key1" (object-array ["val1"]))
(.queryParam "key2" (object-array ["val21" "val22" "val23"])))
From your question it's not clear if you have to use map as your builder data structure. I would recommend using the threading macro for working directly with Java classes implementing the builder pattern:
(-> (ClientBuilder.)
(.forEndpoint "http://example.com")
(.withQueryParam "key1" "value1")
(.build))
For classes that don't implement builder pattern and their methods return void (e.g. setter methods) you can use doto macro:
(doto (Client.)
(.setEndpoint "http://example.com")
(.setQueryParam "key1" "value1"))
Implementing a macro using a map for encoding Java method calls is possible but awkward. You would have to keep each method arguments inside a sequence (in map values) to be a able to call methods with multiple parameters or have some convention for storing arguments for single parameter methods, handling varargs, using map to specify method calls doesn't guarantee the order they will be invoked etc. It will add much complexity and magic to your code.
This is how you could implement it:
(defmacro builder [b m]
(let [method-calls
(map (fn [[k v]] `(. (~(symbol k) ~#v))) m)]
`(-> ~b
~#method-calls)))
(macroexpand-1
'(builder (StringBuilder.) {"append" ["a"]}))
;; => (clojure.core/-> (StringBuilder.) (. (append "a")))
(str
(builder (StringBuilder.) {"append" ["a"] }))
;; => "a"
I have a set of functions that all have the same first parameter.
(defn get-file [dir filename] ...)
(defn write-file [dir filename] ...)
I'd like to partially apply all of them at once, basically. Seems like I could wrap them all in a function like this:
(defn get-fns [dir]
{:get-file (fn [filename] ...)
:write-file (fn [filename] ...)})
But that seems like accessing the functions would be kind of annoying.
(let [fns (get-fns dir-name)]
((fns :get-file) filename)))
I suppose I could use a mutable var as well, but that doesn't seem very, well, functional. Is there a canonical/idiomatic way to do this?
Let's think it through: you've got a list of things, and you want to apply something to each of them, so map. What do you want to apply to them? You want to partially apply the first argument, so partial. Then you want to have a unique reference to each of those values, so use deconstruction on the list.
Adding all that up, assuming dir, get-file, and write-file are all defined, you'd do
(let [[get-file-here write-file-here] (map #(partial % dir) [get-file write-file])]
...)
Here's a full example
(let [[add-to-3 sub-from-3] (map #(partial % 3) [+ -])]
(prn (add-to-3 2)) ; 5
(prn (sub-from-3 5))) ; -2
So we want a series of partial applications that we can use in a local binding context.
(defn get-fns
[dir]
{:get-f (partial get-file dir)
:write-f (partial write-file dir)})
Then, in a local binding, we can use them
(let [{:keys [get-f write-f]} (get-fns dir)]
(get-f file-name))
(you are of course free to use your original keywords, by changing the keywords I make it unambiguous that get-f is coming from get-fns and is not the globally bound var).
My question is about structuring lisp code with side effects. The particular example I have in mind comes from Clojure, but I think it can apply to any lisp.
In this case, I am interacting with an existing library that requires some functions to be called in a particular order. The final function call creates the value I need for the rest of the procedure.
The code looks like this:
(defn foo []
(let [_ procedure-with-side-effect
__ another-procedure-with-side-effect
value procedure-that-creates-the-value]
(do-something value)))
This works and everything is great, except I think the let block looks hideous. Is there a better way to do this?
If you don't need the intermediate values of the function calls, you can just put a bunch of function calls in the body of the defn:
(defn foo []
(procedure-with-side-effect)
(another-procedure-with-side-effect)
(do-something (procedure-that-creates-the-value)))
While this is the best for this code, there are other options. You can also put any number of function calls in the body of a let:
(let [val 3]
(fun-call-1)
(fun-call-2)
(fun-call-3 val))
And if you don't want to bind any values, you can use do:
(do (fun-call-1)
(fun-call-2)
(fun-call-3))
In Lisp every function body is a ordered set of forms. The value(s) of the last form will be returned. If the procedures don't use intermediate result values as arguments, a LET is not necessary. If the procedure-that-creates-the-value does not need to be documented by naming a variable, the LET binding for its value is also not necessary.
So in Lisp the code is just this:
(defun foo ()
(procedure-with-side-effect)
(another-procedure-with-side-effect)
(do-something (procedure-that-creates-the-value)))
I'm not super experienced, but I'd do it this way:
(defn foo []
(procedure-with-side-effect)
(another-procedure-with-side-effect)
(let [value (procedure-that-creates-the-value)]
(do-something value)))
or
(defn foo []
(procedure-with-side-effect)
(another-procedure-with-side-effect)
(-> (procedure-that-creates-the-value)
do-something))
or
(defn foo []
(procedure-with-side-effect)
(another-procedure-with-side-effect)
(do-something (procedure-that-creates-the-value)))
Edit: defn expressions are wrapped with an implicit do.
I just started to learn clojure and I don't have much functional programming experience. Let's say I have a function :
(defn process-seq
[process]
...doing something...)
that takes another function as an argument. This argument should be a function that takes single argument - a sequence. For example :
(defn filter-odd
[sequence]
(filter odd? sequence))
So I can now write :
(process-seq filter-odd)
What I don't like about it is that I had to define filter-odd function. I would like to achieve it without defining it. All I want is to pass filter function with constant predicate : odd?.Something like (just a pseudo code that I made up) :
(process-seq filter(odd?))
Is something like that possible?
You can pass an anonymous function as parameter:
(process-seq (fn [sequence] (filter odd? sequence)))
Or even shorter:
(process-seq #(filter odd? %))
Or as mentioned by A.Webb in the comments, we could use partial:
(process-seq (partial filter odd?))