On Mon, Dec 22, 2008 at 10:23 AM, Piotr 'Qertoip' Włodarek
<qert...@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

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to