Exercise: how to print multiplication table?

163 views
Skip to first unread message

Piotr 'Qertoip' Włodarek

unread,
Dec 22, 2008, 10:23:14 AM12/22/08
to Clojure
Hello,


Being new to Clojure, to Lisp and to functional programming in
general, I have some trouble wraping my head around it.

As the first exercice, I would like to print multiplication table of
specified order, like:
(print-multiplication-table 3)
1 2 3
2 4 6
3 6 9

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

Now, how to pretty print this?

This does not work - prints nothing - why?:
(defn pretty-print-row [row]
(map print row))

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


Regards,
Piotrek

J. McConnell

unread,
Dec 22, 2008, 11:03:30 AM12/22/08
to clo...@googlegroups.com
On Mon, Dec 22, 2008 at 10:23 AM, Piotr 'Qertoip' Włodarek
<qer...@gmail.com> wrote:
>
> Being new to Clojure, to Lisp and to functional programming in
> general, I have some trouble wraping my head around it.
>
> As the first exercice, I would like to print multiplication table of
> specified order, like:
> (print-multiplication-table 3)
> 1 2 3
> 2 4 6
> 3 6 9
>
> 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))
>
> Now, how to pretty print this?
>
> This does not work - prints nothing - why?:
> (defn pretty-print-row [row]
> (map print row))

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.

lpetit

unread,
Dec 22, 2008, 11:08:51 AM12/22/08
to Clojure
Hello,

Not a lot of time to answer, so I'll be straight to the point below :

On 22 déc, 16:23, Piotr 'Qertoip' Włodarek <qert...@gmail.com> wrote:
> Hello,
>
> Being new to Clojure, to Lisp and to functional programming in
> general, I have some trouble wraping my head around it.
>
> As the first exercice, I would like to print multiplication table of
> specified order, like:
> (print-multiplication-table 3)
>  1  2  3
>  2  4  6
>  3  6  9
>
> 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))
>
> Now, how to pretty print this?
>
> This does not work - prints nothing - why?:
> (defn pretty-print-row [row]
>   (map print row))

The objective of map is not initially to go through the list in order
to have side effects (as pretty print would be) : it is to return a
new sequence with new computed values from initial values.
So map has been made, by design, lazy.
To make you example work, you need to wrap the call to map with a call
to dorun which will force the sequence from beginning to end, then
forcing your side effect printing.
See here ( http://clojure.org/api#toc203 ) for more detail on doseq.

> 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 have a bug : you wrote extra enclosing parens around print &
recur -> the right syntax for if is : (if (first row) (print (first
row)) (recur (rest row)))

HTH,

--
Laurent
>
> Regards,
> Piotrek

Brian Doyle

unread,
Dec 22, 2008, 11:13:13 AM12/22/08
to clo...@googlegroups.com


2008/12/22 J. McConnell <jdo...@gmail.com>

This is off topic from the original questions, but are the 1:#'s in your REPL line numbers? 
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.
 



Chouser

unread,
Dec 22, 2008, 11:19:44 AM12/22/08
to clo...@googlegroups.com
On Mon, Dec 22, 2008 at 10:23 AM, Piotr 'Qertoip' Włodarek
<qer...@gmail.com> wrote:
>
> Being new to Clojure, to Lisp and to functional programming in
> general, I have some trouble wraping my head around it.

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

J. McConnell

unread,
Dec 22, 2008, 11:27:09 AM12/22/08
to clo...@googlegroups.com
2008/12/22 Brian Doyle <brian...@gmail.com>:
>
> 2008/12/22 J. McConnell <jdo...@gmail.com>

>>
>> 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
>
> This is off topic from the original questions, but are the 1:#'s in your
> REPL line numbers?

Yup! I am using Stephen Gilardi's repl_ln from clojure-contrib. You
can find the original announcement of it here:

http://groups.google.com/group/clojure/browse_thread/thread/d1b5dfdb7c330f6/a1c3d36c0e157528?lnk=gst&q=repl_ln#a1c3d36c0e157528

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

Tom Faulhaber

unread,
Dec 22, 2008, 12:56:37 PM12/22/08
to Clojure
Here's an alternative, more "mappy" definition using the cl-format
function I posted earlier:

(defn multipication-table [limit]
(let [nums (range 1 (inc limit))]
(cl-format true "~{~{~4d~}~%~}"
(map #(map % nums)
(map #(partial * %) nums))))))


user> (multipication-table 12)
1 2 3 4 5 6 7 8 9 10 11 12
2 4 6 8 10 12 14 16 18 20 22 24
3 6 9 12 15 18 21 24 27 30 33 36
4 8 12 16 20 24 28 32 36 40 44 48
5 10 15 20 25 30 35 40 45 50 55 60
6 12 18 24 30 36 42 48 54 60 66 72
7 14 21 28 35 42 49 56 63 70 77 84
8 16 24 32 40 48 56 64 72 80 88 96
9 18 27 36 45 54 63 72 81 90 99 108
10 20 30 40 50 60 70 80 90 100 110 120
11 22 33 44 55 66 77 88 99 110 121 132
12 24 36 48 60 72 84 96 108 120 132 144

(These line up in columns in a fixed width font :-))

This is nice because there's no loop/recur to think about and the
computation is separated from the printing. It's all first-order.

Tom

P.S. The cl-format post was here: http://groups.google.com/group/clojure/t/cc0b2b0a2cedec40

Piotr 'Qertoip' Włodarek

unread,
Dec 23, 2008, 7:43:11 AM12/23/08
to Clojure

Many thanks to all of you. I have several working implementations
right now and I'm feeling enlightened ;-)


On Dec 22, 5:19 pm, Chouser <chou...@gmail.com> wrote:
> On Mon, Dec 22, 2008 at 10:23 AM, Piotr 'Qertoip' Włodarek
>
> <qert...@gmail.com> wrote:
>
> > (defn multiplication-row [n k]
> Nothing wrong there, though the #() reader macro is handy for building
> map functions:

Nice tip.

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

Exactly.


Regards,
Piotrek

Emeka

unread,
Dec 23, 2008, 8:15:16 AM12/23/08
to clo...@googlegroups.com

(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

Emeka

Reply all
Reply to author
Forward
0 new messages