How to code a variadic defmulti/defmethod in clojure - clojure

I have a defmulti/defmethod group that take pairs of arguments like so...
(defmulti foo "some explanation" (fn [arg1 arg2] (mapv class [arg1 arg2])))
(defmethod foo [N P] (->L 1 2 3))
(defmethod foo [L P] (->N 5))
(defmethod foo [P N] (->L 6 7 8))
...
Which are called in the way you might expect.
(foo (->N 9) (->P 9))
What I would like is to call 'foo' with more than 2 arguments.
I know how to do this with functions and I suppose I could use some wrapper function that split the args into pairs and then combined the result (or just use 'reduce') but that seems wrong.
My question then is...
What is the idiomatic way to define a variadic multi-function in clojure?

There's nothing wrong with giving the defmulti dispatch function and defmethod bodies variadic signatures, and this is perfectly idiomatic:
(defmulti bar (fn [x & y] (class x)))
(defmethod bar String [x & y] (str "string: " (count y)))
(defmethod bar Number [x & y] (str "number: " (count y)))
(bar "x" 1 2 3) ;=> "string: 3"
(bar 1 2 3) ;=> "number: 2"

Related

Compact way in Clojure to print a variable number of command line arguments?

I'm a newbie to Clojure. I think I'm trying to solve this procedurally and there must be a better (more functional) way to do this in Clojure...
The -main function can receive a variable number of 'args'. I would like to print them out but avoid an IndexOutOfBoundsException. I thought I could mimic Java and use a case fall-through to minimize the code involved, but that didn't work:
(defn -main [& args]
(println "There are" (str (count args)) "input arguments.")
(println "Here are args:" (str args))
(let [x (count args)]
(case x
(> x 0) (do
(print "Here is the first arg: ")
(println (nth args 0)))
(> x 1) (do
(print "Here is the 2nd arg: ")
(println (nth args 1)))
(> x 2) (do
(print "Here is the 3rd arg: ")
(println (nth args 2))))))
(doseq [[n arg] (map-indexed vector arguments)]
(println (str "Here is the argument #" (inc n) ": " (pr-str arg))))
map-indexes is like map but adds index number in the beginning.
So it goes item by item through arguments, packs index and item into a vector and by destructruing index number and item are mapped to [n arg].
Since clojure begins counting from 0, you use (inc n) to begin counting from 1. pr-str is pretty print string. The str joins all string components together.
there is also a handy formatting facility in clojure's core library: cl-format, which is the port of common lisp's format syntax. It includes a nice way to print out collections:
(require '[clojure.pprint :refer [cl-format]])
(let [args [:a :b :c :d]]
(cl-format true "~{here is the ~:r arg: ~a~%~}"
(interleave (rest (range)) args)))
;; here is the first arg: :a
;; here is the second arg: :b
;; here is the third arg: :c
;; here is the fourth arg: :d
some more information about what format can do is here

Clojure threading macro

I'm not sure this is the best place to post, but why doesn't 2) work? Doesn't the threading macro pass the result of seq into (map str)?
;; 1
(map str (seq (str (* 8 8)))) -> ("6" "4")
;; 2
(defn a [x y]
(-> (* x y)
str
seq
(map str)))
(a 8 8) -> Don't know how to create ISeq from: clojure.core$str
You're using the thread-first macro, which inserts each form as the second item of the next, like this:
(-> (* x y) str seq (map str))
(-> (str (* x y)) seq (map str))
(-> (seq (str (* x y))) (map str))
(map (seq (str (* x y))) str)
What you want is the thread-last macro:
(defn a [x y]
(->> (* x y) str seq (map str)))
(a 8 8) ;=> ("6" "4")
as Elogent points out the macro is putting the arguments in the wrong place. In general when working with macros (and especially writing them) it helps to know about macroexpand-1 and combine it with clojure.pprint/pprint to get a clear view of what is actually running:
user> (clojure.pprint/pprint
(macroexpand-1
'(-> (* x y)
str
seq
(map str))))
(map (seq (str (* x y))) str)
nil
Which we can see doesn't quite look right. So next we fiddle with it until it expands to what we expect:
user> (clojure.pprint/pprint
(macroexpand-1
'(->> (* x y)
str
seq
(map str))))
(map str (seq (str (* x y))))
nil
There are a variety of threading macros to help with situations like this, especially as-> which lets you give an explicit name to the threaded value when you need to thread functions that alternate using the first and last argument for the important input:
user> (as-> (* 7 42) x
(str x)
(seq x)
(map str x))
("2" "9" "4")
Here is an alternative that is good to know (it's read from right to left):
(defn a [x y]
((comp (partial map str) seq str *)
x y))
This might be useful in contexts where you want to separate the transformations to apply, from the data they're applied to (I would welcome criticism on the subject 😃).
You might also consider using the it-> threading form from the Tupelo library, which is designed to avoid thread-first vs thread-last worries. Consider this code:
(ns clj.core
(:use tupelo.core))
(defn a [x y]
(it-> (* x y)
(str it)
(seq it)
(map str it)))
(spyx (a 8 8))
(defn -main [] )
Which produces:
(a 8 8) => ("6" "4")
The it-> macro uses the placeholder it to explicitly choose where to place the result of each successive form. This is an easy way to simplify code and avoid this type of error.

Conditional threading through expressions

I was trying to do something like below,
val = initValue;
if (test1(val)) { val = fn1(val); }
if (test2(val)) { val = fn2(val); }
return val;
The only way I found within clojure core was using cond->. I was hoping I should be able to do this
(cond-> initValue
test1 fn1
test2 fn2)
However, the condition in cond-> is not a function. It doesn't seem to allow me to pass the result of fn1 to test2.
What's the idiomatic way to do this?
Okay. Well you have a data dependency between the function results and your predicates, so the "nicest" thing I came up using only clojure.core is to compose as-> and cond->
(as-> initValue data
(cond-> data (test1 data) (f1 data))
(cond-> data (test2 data) (f2 data)))
Another approach would be my own update-when helper...
(defn ->when-update
"Function of a value, a predicate, an updater and optional
varargs. If the predicate is true of the value, returns (apply f x
args), otherwise returns x.
Example:
(-> 1 (->when-update #(<= 0 %) inc))"
[x pred f & args]
(if (pred x)
(apply f x args)
x))
which lets us write
(-> initValue
(->when-update test1 f1)
(->when-update test2 f2))
Will this do?
(defmacro cond-chain [init & stuff]
(let [pairs (partition 2 stuff)
step-form (fn [[test func]]
`((fn [x#] (if (~test x#) (~func x#) x#))))]
(list* '->> init (map step-form pairs))))
For example,
(cond-chain 7, even? inc, odd? #(* 2 %))
;14
(cond-chain 7, odd? inc, odd? #(* 2 %))
;8
(cond-chain 7, zero? inc, even? #(* 2 %))
;7
As you can see, it constructs a form that conditionally applies each of a series of functions.
Or, without resorting to macros:
(defn cond-chain [init & stuff]
(let [pairs (partition 2 stuff)]
(reduce (fn [acc [test func]] (if (test acc) (func acc) acc)) init pairs)))

How to increment by a number in Clojure?

I would like to know how to increment by X amount a number, in other languages I used to do
foo += 0.1;
but I have not idea how it can be done in Clojure
Variables are immutable in Clojure. So you should not try to change the value of foo, but instead, "create" a new foo:
(def foo2 (+ foo 0.1))
...or, if in a loop, recur with a new value:
(loop [foo 5.0]
(when (< foo 9)
(recur (+ foo 0.1))))
...or, if foo is an atom, swap! it with a new value:
(def foo (atom 5.0))
(swap! foo (partial + 0.1))
I recommend you start by reading the rationale of Clojure.
Blacksad's answer covers defining vars so I would just like to add the other scopes in which you may wish to have a value that is incremented from another value:
within a function's local scope:
user> (defn my-function [x]
(let [y (inc x)
z (+ x y)]
[x y z]))
#'user/my-function
user> (my-function 4)
[4 5 9]
and If you want to build a value incrementally to make the process more clear:
user> (defn my-function [x]
(let [y (inc x)
z (+ x y)
z (+ z 4)
z (* z z)]
[x y z]))
#'user/my-function
user> (my-function 4)
[4 5 169]
This can make the process more presentable, though it is not a "way to get variables back" and is really only useful in limited contexts. This pattern is used in clojure.core's threading macros.

Piping data through arbitrary functions in Clojure

I know that the -> form can be used to pass the results of one function result to another:
(f1 (f2 (f3 x)))
(-> x f3 f2 f1) ; equivalent to the line above
(taken from the excellent Clojure tutorial at ociweb)
However this form requires that you know the functions you want to use at design time. I'd like to do the same thing, but at run time with a list of arbitrary functions.
I've written this looping function that does it, but I have a feeling there's a better way:
(defn pipe [initialData, functions]
(loop [
frontFunc (first functions)
restFuncs (rest functions)
data initialData ]
(if frontFunc
(recur (first restFuncs) (rest restFuncs) (frontFunc data) )
data )
) )
What's the best way to go about this?
I must admit I'm really new to clojure and I might be missing the point here completely, but can't this just be done using comp and apply?
user> (defn fn1 [x] (+ 2 x))
user> (defn fn2 [x] (/ x 3))
user> (defn fn3 [x] (* 1.2 x))
user> (defn pipe [initial-data my-functions] ((apply comp my-functions) initial-data))
user> (pipe 2 [fn1 fn2 fn3])
2.8
You can do this with a plain old reduce:
(defn pipe [x fs] (reduce (fn [acc f] (f acc)) x fs))
That can be shortened to:
(defn pipe [x fs] (reduce #(%2 %1) x fs))
Used like this:
user> (pipe [1 2 3] [#(conj % 77) rest reverse (partial map inc) vec])
[78 4 3]
If functions is a sequence of functions, you can reduce it using comp to get a composed function. At a REPL:
user> (def functions (list #(* % 5) #(+ % 1) #(/ % 3)))
#'user/my-list
user> ((reduce comp functions) 9)
20
apply also works in this case because comp takes a variable number of arguments:
user> (def functions (list #(* % 5) #(+ % 1) #(/ % 3)))
#'user/my-list
user> ((apply comp functions) 9)
20