L0ren2
L0ren2

Reputation: 135

Duplicated case statement in Common Lisp

there has to be a better way to do this here, right?

(format t "Enter your age: ~%")

(defun age-case (age)
  (case age
    (1 (format t "You belong in Kindergarden~%"))
    (2 (format t "You belong in Kindergarden~%"))
    (3 (format t "You belong in Kindergarden~%"))
    (4 (format t "You belong in Kindergarden~%"))
    (5 (format t "You belong in Preschool~%"))
    (6 (format t "Elementary school ~%"))
    (t (format t "Somewhere else"))))

(defvar *age* (read))

(age-case *age*)

In Python I would use a case 1..4 for this, in C++, Java and co. I would maybe use a falltrough switch case where I leave out the break for cases 1 to 3. Is there a neat little trick to do this in clisp w/o the code duplication?

Upvotes: 2

Views: 217

Answers (3)

Samuel Hunter
Samuel Hunter

Reputation: 557

A case clause can accept multiple keys:

(defun age-case (age)
  (case age
    ((1 2 3 4) (format t "You belong in Kindergarden~%"))
    (5 (format t "You belong in Preschool~%"))
    (6 (format t "Elementary school ~%"))
    (t (format t "Somewhere else"))))

Rainer's solution used ranges provided in the integer type with a typecase:

(typecase age
  ((integer 1 4) 'one-to-four)
  ((eql 5)       'five)
  ((eql 6)       'six)
  (t             'something-else)))

Building on this, you can do type checking "for free":

(etypecase age
  ((integer 1 4) 'one-to-four)
  ((eql 5)       'five)
  ((eql 6)       'six)
  ((integer 7 *) 'something-else)))

Alternatively, you can also use cond:

(cond
  ((<= 1 age 100) 'one-to-ahundred)
  ;; ...and so on.
  )

Upvotes: 5

Rainer Joswig
Rainer Joswig

Reputation: 139251

Another option is to use type specifiers:

CL-USER > (let ((age 6))
            (typecase age
              ((integer 1 4) 'one-to-four)   ; integers from 1 to 4
              ((eql 5)       'five)
              ((eql 6)       'six)
              (t             'something-else)))
SIX

Upvotes: 7

Martin Půda
Martin Půda

Reputation: 7568

You can use cond and member like this:

(defun age-test ()
  (format t "Enter your age: ~%")
  (finish-output)
  (let ((age (read)))
    (format t (cond ((member age '(1 2 3 4)) "You belong in Kindergarden~%")
                    ((= age 5) "You belong in Preschool~%")
                    ((= age 6) "Elementary school ~%")
                    (t "Somewhere else")))))

(age-test)

Upvotes: 1

Related Questions