1

I write the newton-method to find root from Scheme example in elisp as

#+begin_src emacs-lisp :session sicp :lexical t
(defun deriv(g)
  (lambda (x)
    (/ (- (funcall g (+ x dx)) (funcall g x))
       dx)))

(defvar dx 0.00001)
(defvar tolerance 0.00001)

(defun fixed-point(f guess)
  (defun close-enoughp(v1 v2)
    (< (abs (- v1 v2)) tolerance))
  (let ((next (funcall f guess)))
    (if (close-enoughp guess next)
        next
      (fixed-point f next))))

(defun newton-transform(g)
  (lambda (x)
    (- x (/ (funcall g x) (funcall (funcall #'deriv g) x)))))

(defun newton-method(g guess)
  (fixed-point (funcall #'newton-transform g) guess))

(defun curt(x)
  (newton-method (lambda (y) (- (* y y y) x))
                  1.0))

(curt 12)
#+end_src

#+RESULTS:
: 2.2894284851069058

It works but observe the twisted code:

(defun newton-transform(g)
  (lambda (x)
    (- x (/ (funcall g x) (funcall (funcall #'deriv g) x)))))

Three funcalls, in which I could not imagine bad if more depths of closures.

Is there an alternative solution to the problem with elisp? (I guess it de-appreciates closures)

Will Ness
  • 70,110
  • 9
  • 98
  • 181
AbstProcDo
  • 19,953
  • 19
  • 81
  • 138

2 Answers2

2

In newton-transform, (funcall #'deriv g) is identical to (deriv g), so you can eliminate one of the 3 funcalls. The other 2 are, indeed, necessary.

Same for newton-method: replace (funcall #'newton-transform g) with (newton-transform g).

PS. I strongly recommend either moving defun close-enoughp out of defun fixed-point or turning it into a cl-flet. Lisp is not Scheme.

PPS. close-enoughp should be close-enough-p.

sds
  • 58,617
  • 29
  • 161
  • 278
  • My Emacs claims that `flet` is obsolete (in elisp, not CL obviously) and you should use one of `cl-flet` or `cl-letf`. I don't know modern elisp well enough to know the difference between these (or why `flet` is not the fight thing any more). –  Dec 28 '19 at 14:16
1

A couple of the functions calls can be simplified, and we should implement @sds's advice regarding function names and conventions - like this:

(defvar dx 0.00001)
(defvar tolerance 0.00001)

(defun deriv (g)
  (lambda (x)
    (/ (- (funcall g (+ x dx)) (funcall g x))
       dx)))

(defun close-enough-p (v1 v2)
  (< (abs (- v1 v2)) tolerance))

(defun try (f guess)
  (let ((next (funcall f guess)))
    (if (close-enough-p guess next)
      next
      (try f next))))

(defun fixed-point (f first-guess)
  (try f first-guess))

(defun newton-transform (g)
  (lambda (x)
    (- x (/ (funcall g x)
            (funcall (deriv g) x)))))

(defun newton-method (g guess)
  (fixed-point (newton-transform g) guess))

(defun curt (x)
  (newton-method (lambda (y) (- (* y y y) x))
                 1.0))

Notice that we don't need to use funcall when invoking functions previously defined and named, such as deriv and newton-transform.

Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • ty, I got the idea of separated 'try', more than 'write little function to work together", a helper function as try "abstraction" is perspicuous than cumbersome "comments" inside to facilitate a second reading. – AbstProcDo Dec 27 '19 at 02:37