The problem is that you are using map in two different ways here. In
the multiplication-row and multiplication-table functions you are
using it correctly as a function that applies a given function to all
of the values in a collection, returning the results in a new
collection. In the pretty-printing function you do not care about the
results like you did in the above two functions, you care about the
side-effects. For this, you can use doseq:
1:1 user=> (defn multiplication-row [n k]
(map (partial * k) (range 1 (inc n))))
#'user/multiplication-row
1:3 user=> (defn multiplication-table [n]
(map (partial multiplication-row n) (range 1 (inc n))))
#'user/multiplication-table
1:5 user=> (defn pretty-print-row [row]
(doseq [v row] (print v \space)) (print \newline))
#'user/pretty-print-row
1:7 user=> (defn print-multiplication-table [n]
(doseq [row (multiplication-table n)] (pretty-print-row row)))
#'user/print-multiplication-table
1:9 user=> (print-multiplication-table 3)
1 2 3
2 4 6
3 6 9
nil
1:10 user=> (print-multiplication-table 5)
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25
nil
HTH,
- J.
Looks to me like you're doing pretty well.
> I came that far:
>
> (defn multiplication-row [n k]
> (map (partial * k) (range 1 (inc n))))
>
> (defn multiplication-table [n]
> (map (partial multiplication-row n) (range 1 (inc n))))
>
> (println (multiplication-table 3)) ; => ((1 2 3) (2 4 6) (3 6 9))
Nothing wrong there, though the #() reader macro is handy for building
map functions:
(defn multiplication-table [n]
(let [r (range 1 (inc n))]
(map (fn [x] (map #(* x %) r)) r)))
When to get to nesting small functions, 'for' can be a nice
alternative:
(defn multiplication-table [n]
(let [r (range 1 (inc n))]
(for [x r] (for [y r] (* x y)))))
So many fun ways to do this! But anyway, what you had is fine.
> Now, how to pretty print this?
>
> This does not work - prints nothing - why?:
> (defn pretty-print-row [row]
> (map print row))
Because 'map' is lazy, and won't evaluate 'print' on any of the items
sequence unless necessary. For functions with side-effects (like
'print') you'll generally need 'doseq', loop/recur, or 'dorun'.
> This also does not work - throws
> java.lang.UnsupportedOperationException: Can only recur from tail
> position (hello_world.clj:47) - why?:
>
> (defn pretty-print-row [row]
> (if (first row)
> ((print (first row))
> (recur (rest row)))))
>
> Once I remove print expression, exception is not thrown (what the
> heck?)
You probably mean:
(defn pretty-print-row [row]
(if (first row)
(do
(print (first row))
(recur (rest row)))))
Without the 'do', you had (foo bar) where foo is the return value of
'print' and bar is the return value of 'recur'. Using the "return
value of recur" in any way other than as your own functions return
value is not allowed, hence the exception. But even if that hadn't
complained, 'print' returns nil and trying to call nil as a function
would also throw an exception.
Another approach would be to build the whole table as a string, then
print just once:
(defn multiplication-table-string [n]
(apply str (for [row (multiplication-table n)]
(apply str (concat (for [i row] (format "% 3d" i))
["\n"])))))
user=> (print (multiplication-table-string 9))
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54
7 14 21 28 35 42 49 56 63
8 16 24 32 40 48 56 64 72
9 18 27 36 45 54 63 72 81
nil
I'm not sure building the nested seqs separately is much of a win.
This combines the entire operation into a single function:
(defn multiplication-table-string [n]
(let [r (range 1 (inc n))]
(apply str (for [y r]
(apply str (concat (for [x r] (format "% 3d" (* x y)))
["\n"]))))))
--Chouser
Yup! I am using Stephen Gilardi's repl_ln from clojure-contrib. You
can find the original announcement of it here:
> If so, what did you do to get those? Also if those are line numbers how
> come only odd
> numbers are printed? What does the '1:' stand for? Thanks.
Line 1:2 was "(map (partial * k) (range 1 (inc n))))", line 1:4 was
"(map (partial multiplication-row n) (range 1 (inc n))))", etc. I.e.
line numbers aren't printed when a line is a continuation of the
expression from the line above it. It just so happened that in these
examples, I was using two lines per expression, so all of the
even-numbered were skipped.
The "1:" stands for the nesting level, so if I started a new REPL from
within this one, it would have changed to "2:".
Check out repl_ln.clj if you are interested:
http://code.google.com/p/clojure-contrib/source/browse/trunk/src/clojure/contrib/repl_ln.clj
- J.
(dotimes [x 10]
(dotimes [y 10]
(print (format "%3d " (* (inc x) (inc y)))))
(println))
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
The above is from http://blog.thinkrelevance.com/2008/9/18/pcl-clojure-chapter-7