Найти корень методом Ньютона

Я пишу newton-method найти корень из примера схемы в elisp как

#+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

Это работает, но обратите внимание на скрученный код:

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

Три funcalls, в котором я не мог представить себе плохого, если бы еще глубина замыканий.

Есть ли альтернативное решение проблемы с elisp? (Думаю, закрытие недооценивается)

2 ответа

Решение

Несколько вызовов функций можно упростить, и мы должны реализовать совет @sds относительно имен функций и соглашений - например:

(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))

Обратите внимание, что нам не нужно использовать funcall при вызове ранее определенных и названных функций, таких как deriv а также newton-transform.

В newton-transform, (funcall #'deriv g) идентичен (deriv g), так что вы можете исключить один из 3 funcall с. Остальные 2 действительно необходимы.

То же самое для newton-method: заменить (funcall #'newton-transform g) с (newton-transform g).

PS. Я настоятельно рекомендую либо переехатьdefun close-enoughp снаружи defun fixed-point или превратив его в cl-flet. Лисп - это не схема.

PPS.close-enoughp должно быть close-enough-p.

Другие вопросы по тегам