This is a collection of blog entries written while learning Lisp. It is posted in the order written so you probably want to jump to the first post.

Wednesday, October 24, 2007

Exercise problems

After yesterdays chapter I have gone a number of chapters without really coding anything, let alone trying to code up something from scratch. Looking around for some problems to try I found to my horror that I wasn't sure how to code the first test on Project Euler in Lisp. I kept fumbling with syntax and trying to remember what functions to use or their side effects. In the end I ended up just searching for someone's solution and learning from them. A bit of a wake up call. Even though I am learning concepts by going through and reading the book and typing in the examples and messing with them a little there is nothing to match simple exercises to learn new concepts. I might be able to read a bunch of Lisp code now, but I sure couldn't write it. So tonight I did a quick google to find some sample problems from courses and did the following one. Feel free to present your own better way to solve this problem.

Define (has-number-p s-exp) to return true if the s-expression is or contains a number.

(has-number-p '(a (b (c d) ((3)))))
T

And my solution:

(defun has-number-p (s-exp)
(if (and
(listp s-exp)
(< 0 (list-length s-exp)))
(or
(has-number-p (first s-exp))
(has-number-p (rest s-exp)))
(numberp s-exp)))

3 comments:

Γιώργος said...

I am also a beginner in Lisp who is reading through the Practical Common Lisp book. I do not know if the following solution to yout problem is "better", but it feels somewhat "lispier". :-)

(defun has-number-p (s-exp)
(cond ((null s-exp) nil)
((atom s-exp) (numberp s-exp))
(t (or (has-number-p (car s-exp))
(has-number-p (cdr s-exp))))))

Benjamin Meyer said...

Yah my solution wasn't very elegant. Especially that call to length. I could change it to this:

CL-USER> (defun has-number-p (s-exp)
(if (null s-exp)
nil
(if (atom s-exp)
(numberp s-exp)
(or
(has-number-p (first s-exp))
(has-number-p (rest s-exp))))))

But using cond rather then nested if's is much nicer as you suggested.

Jeff said...

I'm also a beginning lisp'er and I think I've solved this problem using the suggested "some" function, which makes it rather neat:

(defun has-number-p (x)
(cond ((atom x) (numberp x))
( 'T (some #'has-number-p x))
)
)

So what this does is first test to see if the input is an atom. If yes, return whether it's a number or not.

If the input is a list, the 'some' method will run a test on each item in the list, essentially or'ing the results. The test I want to run is the very function I'm writing, so I just call it recursively. I haven't tested this very rigorously but I think it works. The pound-singleQuote (#') construct is a way of passing a function without actually calling it right then and there.