Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

This common lisp program is an exercise to print an integer and its digits reversed to the screen.

    (defun read-number () (format t "Enter a number: ~%") (read))

    (defun reverse-string (the-string) 
      (if (eq (length the-string) 0) 
        "" 
        (concatenate 'string (reverse-string (subseq the-string 1)) (subseq the-string 0 1))))

    (defun reverse-digits (the-number) (reverse-string (write-to-string the-number)))

    (let ((the-number (read-number)))
      (format t "N->: ~a~%<-N: ~a~%" the-number (reverse-digits the-number)))

Thanks for the feedback, everyone, and thanks too for pointing out that the exercise was to reverse a number - not a string. I wrote a version of this that reverses a number using recursion and would very much like feedback on this version too. Thanks for your time!

;; Write a program to, given an integer, write the number and its digits reversed to the screen.

(defun read-number () (format t "Enter a number: ~%") (read))

(defun reverse-digits-unwrap (fifo multiplier)
  (if (= multiplier 1) (car fifo)
    (+ (* multiplier (car fifo)) (reverse-digits-unwrap (cdr fifo) (/ multiplier 10)))))

(defun reverse-digits (the-number &OPTIONAL fifo multiplier) 
  (let* ((remainder (mod the-number 10)) 
    (next-number (/ (- the-number remainder) 10))
    (fifo (if (null fifo) (list remainder) (append fifo (list remainder))))
    (multiplier (if (null multiplier) 1 (* multiplier 10))))
    (if (= 0 next-number)
      (reverse-digits-unwrap fifo multiplier)
      (reverse-digits next-number fifo multiplier))))


(let ((the-number (read-number)))
  (format t "N->: ~a~%<-N: ~a~%" the-number (reverse-digits the-number)))
share|improve this question
Wow, lots of Lisp exercises. Is this for school, or did you just pick it up for the hell of it? :) – Inaimathi Mar 10 '11 at 2:24
Just picked it up for the heck of it :) I've always heard Lisp is a good language to learn. – jaresty Mar 10 '11 at 6:27

3 Answers

up vote 2 down vote accepted

This problem is more about numbers than strings, so I felt the need to post a non-string-based solution. I've got my original Scheme version, and a Common Lisp adaptation of same.

Scheme version:

(define (reverse-digits n)
  (let loop ((n n) (r 0))
    (if (zero? n) r
        (loop (quotient n 10) (+ (* r 10) (remainder n 10))))))

Common Lisp translation of the Scheme version:

(defun reverse-digits (n)
  (labels ((next (n v)
             (if (zerop n) v
                 (multiple-value-bind (q r)
                     (truncate n 10)
                   (next q (+ (* v 10) r))))))
    (next n 0)))
share|improve this answer
I meanwhile wrote my own version of quotient, idiv. remainder and module seem to be synonyms. – user unknown Mar 10 '11 at 4:16
@user unknown: remainder and modulo have different behaviour if the dividend is negative. (remainder -5 3) => -2, whereas (modulo -5 3) => 1. – Chris Jester-Young Mar 10 '11 at 4:24
Yeah, I didn't test negative values. For such, I would use a wrapper method. (if (< 0 x) (* -1 (redigit (* -1 x) 0))) – user unknown Mar 10 '11 at 7:12
+1 - Just keep in mind that TCO isn't guaranteed in CL the way it is in Scheme. – Inaimathi Mar 10 '11 at 15:18
1  
@Inaimathi: Of course. But how many digits is your number going to have? ;-) – Chris Jester-Young Mar 10 '11 at 15:19

You're talking about digits and integer, but to me, as an non-lisper, it looks as if you operate on Strings.

  • I would take the number, modulo 10, print that digit.
  • If the rest is > 0 recursively call the function with the (number - digit) / 10.

In most languages with integer-arithmetic you can omit the subtraction, since 37/10 => 3 :==: (37-7)/10 => 3

In scala it would look like this:

def redigit (n: Int, sofar: Int = 0) : Int = { 
     if (n == 0) sofar else                     
     redigit (n / 10, sofar * 10 + n % 10)}

redigit (123)
321 

It uses default arguments. First tests with DrScheme didn't succeed. Here is what I came up with:

;; redigit : number number -> number
(define (redigit in sofar)
  (cond [(< in 1) sofar]
      [else (redigit (/ in 10) (+ (* 10 sofar) (modulo in 10)))]) 
)

(redigit 134 0) 

But the division is precise and doesn't cut off the digits behind the floting point. I get this error:

modulo: expects type as 1st argument, given: 67/5; other arguments were: 10

I looked for a function toInt, asInt, floor, round and so on for the term (/ in 10) but I didn't find something useful. Maybe you know it yourself?

share|improve this answer
You need to use quotient and remainder. See my answer. :-) – Chris Jester-Young Mar 10 '11 at 4:08

Meanwhile I wrote my own 'quotient'

;; idiv : number number -> number
;; 17 / 3 => 5, not 5 2/3
(define (idiv zaehler nenner)
 (/ (- zaehler (modulo zaehler nenner)) nenner)
  )

;; redigit : number number -> number
(define (redigitit in sofar)
  (cond [(< in 1) sofar]
      [else (redigitit (idiv in 10) (+ (* 10 sofar) (modulo in 10)))]) 
)

;; red : number -> number
(define (redigit x) (redigitit x 0))
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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