I am working on SICP's exercise 1.6 which rewrite the demonstration case
#+begin_src emacs-lisp :session sicp :results output
(defun sqrt(x)
(sqrt-iter 1.0 x))
(defun sqrt-iter(guess x)
(if (good-enough-p guess x)
guess
(sqrt-iter (improve guess x)
x)))
(defun good-enough-p(guess x)
(< (abs (- (square guess) x)) 0.001))
(defun improve(guess x)
(average guess (/ x guess)))
(defun average(x y)
(/ (+ x y) 2))
#+end_src
It works and get the output
#+begin_src emacs-lisp :session sicp :lexical t :results output
(print (sqrt 11))
(print (sqrt (+ 100 37)))
(print (sqrt (+ (sqrt 2) (sqrt 3))))
#+end_src
#+RESULTS:
:
: 3.3166248052315686
:
: 11.704699917758145
:
: 1.7739279023207892
Thus come to Exercise 1.6 which rewrite it with cond
#+begin_src emacs-lisp :session sicp :lexical t
(defun sqrt-iter-cond(guess x)
(cond ((good-enough-p guess x) guess)
(t (sqrt-iter-cond (improve guess x) x))
)
)
(sqrt-iter-cond 1 10)
#+end_src
It report errors:
ob-async-org-babel-execute-src-block: Lisp nesting exceeds ‘max-lisp-eval-depth’
After reading various explanations, more confusions I immersed in and even raise an implicit fear to employ cond
afterwords. Because It seem clearly logical correct.
Could please give any hints?
There's nothing wrong with the cond
version, start with an empty buffer and try this, it'll work:
(defun sqrt (x)
(sqrt-iter-cond 1.0 x))
(defun sqrt-iter-cond (guess x)
(cond ((good-enough-p guess x) guess)
(t (sqrt-iter-cond (improve guess x) x))))
(defun good-enough-p (guess x)
(< (abs (- (square guess) x)) 0.001))
(defun improve (guess x)
(average guess (/ x guess)))
(defun average(x y)
(/ (+ x y) 2))
(print (sqrt 11))
=> 3.3166247903554
But the exercise is not about rewriting the procedure with cond
, it's supposed to show you that you can't write your own version of if
using procedures, and that you need a special form with special evaluation rules - because evaluation rules of procedures will evaluate both the consequent and the alternative parts at the same time, and that won't work! Look at this simple example to see what I mean:
(if t 'ok (/ 1 0))
The above will return 'ok
, even though there's a division by zero there: that part never got executed. But if we try to do it with our own if
implemented as a normal procedure, it'll fail with a division by zero error:
(defun my-if (condition consequent alternative)
(cond (condition consequent)
(t alternative)))
(my-if t 'ok (/ 1 0))
Now go back to your code and try it, of course it'll also fail, but this time with an infinite recursion error (that's what the "Lisp nesting exceeds ‘max-lisp-eval-depth’" message means):
(defun sqrt-iter (guess x)
(my-if (good-enough-p guess x)
guess
(sqrt-iter (improve guess x)
x)))