1

I've got this function

(defun mt ()
    (dotimes (x 20)
      (dotimes (y 20)
        (format "%3d " (* (1+ x) (1+ y))))
      (format "\n")))

in my *scratch*. a Ctr-= prints back mt. But then evaluating (mt) only prints back nil. How would I get it to print out the multiplication table? This works in Common Lisp at the REPL. I know I'm missing something basic here...

4

format generates a string, but it doesn't do anything with it. You probably want to pass the result of format on to something that does:

(defun mt ()
  (dotimes (x 20)
    (dotimes (y 20)
      (insert (format "%3d " (* (1+ x) (1+ y)))))
    (insert (format "\n"))))

UPDATE

I think you're also confused about how dotimes works. From the doc string:

(dotimes (VAR COUNT [RESULT]) BODY...)

:around advice: ‘cl--wrap-in-nil-block’

Loop a certain number of times. Evaluate BODY with VAR bound to successive integers running from 0, inclusive, to COUNT, exclusive. Then evaluate RESULT to get the return value (nil if RESULT is omitted).

Without a results argument, dotimes will only produce side-effects (modifying variables or state) if you explicitly tell it to, as I have above by adding the insert forms. If you add a results argument, you can use that variable to return a value.

To get the behaviour you expect, we need to add result and some code to modify it:

(defun mt ()
  (let ((res ""))
    (dotimes (x 20 res)
      (dotimes (y 20)
        (setq res
              (concat res (format "%3d " (* (1+ x) (1+ y))))))
      (setq res
            (concat res (format "\n"))))))

This form will return the table you have constructed, which you can then do what you like with.

  • This worked. Thanks. But why does something like this (format "%5d is padded on the left with spaces" (+ 1 3)) produce output in scratch and my mt function not? – 147pm Aug 2 '17 at 22:28
  • @147pm What typing C-j in the scratch buffer does is evaluate the previous expression, convert that value to a string and then insert the string into the scratch buffer. So it's C-j that does the actual adding of text to the scratch buffer; merely evaluating (format ...) (as happens when a function calls format) just makes a string (in your computer's memory somewhere) but doesn't insert the string in any buffer. – Omar Aug 3 '17 at 20:17
  • 1
    Oh right. I have rebound C-j in scratch, so I don't get the default behaviour anymore. I've been using eval-last-sexp, not eval-print-last-sexp. – Tyler Aug 3 '17 at 20:23
  • Yes, this is probably the closest we'll get, Omar and Tyler. Not sure the logic of having eval-last-sexp and eval-print-last-sexp but someone must have considered keeping the behaviors separate important and useful... – 147pm Aug 4 '17 at 1:25
2

I'd probably use a different approach, using mapconcat to apply the function and concatenate the results:

(let ((range (number-sequence 1 20)))
  (mapconcat
   (lambda (y)
     (mapconcat
      (lambda (x)
        (format "%03d" (* x y)))
      range " "))
   range "\n"))

This returns the string that you can insert or whatever else.

  • Again, this plugged into scratch or the REPL prints out the table just fine. What's the difference between this code and my mt function other than mine's a function? – 147pm Aug 3 '17 at 0:03
  • dotimes returns the value of the third element of its first argument after finishing the iterations, it doesn't evaluate it for each iteration. – choroba Aug 3 '17 at 5:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.