Create function by making argument of another function constant (clojure,newbie) - clojure

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?))

Related

Side effects in Lisp/Clojure

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.

Idiomatic way to proxy named parameters in Clojure

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.)

Clojure: How does filter interact with logic?

I'm trying to learn Clojure, so I figured a good way to start would be to work through the project Euler challenges with it, and the first challenge is summing all of the number below 1000 that are divisible by 3 or 5.
My original code was:
(defn div3 [input-no] (zero? (mod input-no 3)))
(defn div5 [input-no] (zero? (mod input-no 5)))
(reduce + (filter (or div3 div5) (range 1 1000)))
But that didn't work, and it turned out that the filter would just return a list of numbers divisible by 3, and not those divisible by 5.
I changed my code to:
(defn div3or5 [input-no] (or (div3 input-no) (div5 input-no)))
(reduce + (filter div3or5 (range 1 1000)))
Which got the right result, but I don't know why my original code didn't work.
Could anyone shed some light on this?
The problem you are running into is that filter expects a predicate (a function taking an input and returning true or false) as its first argument. But while div3 and div5 are functions you can't simply combine them with or. You need to construct a new function that takes one argument and feeds this to both div3 and div5 and calls or and the results of both.
Fortunately this is easy to do in Clojure, try
(filter #(or (div3 %) (div5 %)) (range1 1000))
#() is shorthand for defining a function inline (also called a lambda) and you can get to the first argument with %1 to the second with %2 and so on. If there is only one argument then you can use % for %1 see this question.
You may also want to understand that #() is just syntactic sugar for the fn form which
looks like this: (fn [arg1 arg2 ... & restArgs] (forms)). #() has some limitations (for example it can't be nested).
If you just evaluate (or div3 div5) in the REPL you can see what is happening:
=> (or div3 div5)
#<user$div3 user$div3#73305c>
That is, or is evaluating to the function div3 (which filter is then using, giving the behaviour you describe).
The reason for this is or will return its first non-falsy argument (i.e. the first argument that isn't nil or false); in this case, the arguments are two function objects and a function object is not nil or false.
To put it another way, the or is happening on the functions themselves, not the results of the functions. As Paul said, you can use an anonymous function to make or act on the results rather than the functions themselves.

Clojure: returning a vector from an anonymous function

I wrote a small anonymous function to be used with a map call. The function returns a vector containing a column name and column value from a SQL result set query.
Here is the function (input is the column name):
(fn [name] [(keyword name) (.getObject resultset name)])
This works fine, however when I tried to use a "simplified" version of the anonymous function, I got an error:
#([(keyword %) (.getObject resultset %)])
java.lang.IllegalArgumentException: Wrong number of args (0) passed to: PersistentVector
Here is the map call:
(into {} (map (fn [name] [(keyword name) (.getObject resultset name)]) column-names))
Is it possible to use the simplified syntax for this function? If so, how?
Thanks.
Your problem is that the simple syntax is trying to evaluate the vector as a function call.
You can insert an "identity" function to make it work, as this is just a simple function that will return the vector unchanged:
#(identity [(keyword %) (.getObject resultset %)])
You need to use vector function to do this:
#(vector (keyword %) (.getObject resultset %))
P.S. there are also functions for maps, sets, etc.
Yeah, Clojure should really support a #[...] construct, just for this case.
I would recommend the following as the best alternative:
#(vector (keyword %) (.getObject resultset %))

Clojure: Generating functions from template

I have the following code for a generic conversion library:
(defn using-format [format] {:format format})
(defn- parse-date [str format]
(.parse (java.text.SimpleDateFormat. format) str))
(defn string-to-date
([str]
(string-to-date str (using-format "yyyy-MM-dd")))
([str conversion-params]
(parse-date str (:format (merge (using-format "yyyy-MM-dd") conversion-params)))))
I need to be able to call it like this:
(string-to-date "2011-02-17")
(string-to-date "2/17/2011" (using-format "M/d/yyyy"))
(string-to-date "2/17/2011" {})
The third case is somewhat problematic: the map does not necessarily contain the key :format which is critical for the function. That's why the merge with default value.
I need to have a dozen of similar functions for conversions between all other types. Is there a more elegant way that would not require me to copy-paste, use merge etc. in every single function?
Ideally, looking for something like this (macro?):
(defn string-to-date
(wrap
(fn [str conversion-params]
(parse-date str (:format conversion-params))) ; implementation
{:format "yyyy-MM-dd"})) ; default conversion-params
... that would produce an overloaded function (unary and binary), with binary having a merge like in the first example.
So to define this a little more strictly, you want to create a macro that creates converter functions. A converter function is a function with two arities, one argument and two arguments. The first argument to a converter function is the object to be converted. The second argument is a map of options, that will somehow affect the conversion (like a format string in your example.)
A default parameter map can be specified. When called with one argument, a converter function will use the default parameter map. When called with two arguments, a converter function will merge the default parameter map with the passed in parameter map, such that the passed in parameters override the defaults if they exist.
Let's call this macro def-converter. Def converter will take three arguments, the first is the name of the function to be created. The second is an anonymous function of two arguments that implements the two-arity converter, without the default parm merging. The third argument is the default parm map.
Something like this will work:
(defmacro def-converter [converter-name converter-fn default-params]
(defn ~converter-name
([to-convert#]
(let [default-params# ~(eval default-params)]
(~converter-fn to-convert# default-params#)))
([to-convert# params#]
(let [default-params# ~(eval default-params)]
(~converter-fn to-convert# (merge default-params# params#))))))
Then you can use it like:
(def-converter
string-to-date
(fn [to-convert conversion-params]
(parse-date to-convert conversion-params))
(using-format "yyyy-MM-dd"))
But you have to make a change to one of your helper functions:
(defn- parse-date [str params]
(.parse (java.text.SimpleDateFormat. (:format params)) str))
This is because the macro needs to be general enough to handle arbitrary maps of parameters, so we can't count on. There are probably ways around it, but I can't think of one offhand that's not messier than just pushing that off onto a helper function (or the anonymous function that needs to be passed into def-converter).
clojure.contrib.def/defnk is handy if you need functions with default keyword arguments:
(use 'clojure.contrib.def)
...
(defnk string-to-date [str :format "yyyy-MM-dd"]
(parse-date str format))
(string-to-date "2011-02-17")
(string-to-date "2/17/2011" :format "M/d/yyyy")
For the record, here's what I figured out later at night:
(defmacro defconvert [name f default]
`(defn ~name
([v#] (~name v# ~default))
([v# conversion-params#] (~f v# (merge ~default conversion-params#)))))
It seems to work and generate exactly the definition I had up there. I it possible with defnk or some other built-in mechanism, having a map of default values and accepting override of some but not necessarily all?