0
votes

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?

2
Just out of curiosity: why are you solving SICP's exercises using Elisp? it'll make your life harder, the book was meant to use Scheme.Óscar López
I realized that I know little about programming, about thinking about 'exert mind power on things' before take it seriously to read the Sorcerer Book. However, scheme could be a tool to organize my thoughts in prototype, it stopped there which will prohibit me keeping use it as habtit of thinking in a long run since scheme is not capable of real usage. Try elisp can retain the habit of thinking which I learned from sicp. @ÓscarLópezAbstProcDo
@Algebra "scheme is not capable of real usage" - no. It's of course my opinion, but no. Someone told you a lie, big one. For more than a year now I use Scheme for all my projects and still have to find problem I could not solve using Scheme.rsm

2 Answers

3
votes

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)))
1
votes

sqrt-iter is so named because it's tail recursive. It's intended to be processed by a Scheme implementation which will compile it to iteration. Emacs Lisp isn't tail recursive, and so the code performs actual recursion. It's generating so many function activations that it hits the depth limit.

What we can do is rewrite it to explicit iteration:

(defun sqrt-iter(guess x)
  (while (not (good-enough-p guess x))
    (setq guess (improve guess x)))
  guess))

Another idea is to try using the defun-tco macro provided by this Elisp tail call module.