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:
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))))))
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.
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.
Post a Comment