1

newton-method在elisp中写了从Scheme示例中查找root

#+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 的问题是否有替代解决方案?(我猜它贬低了闭包)

4

2 回答 2

2

newton-transform中,(funcall #'deriv g)与 相同(deriv g),因此您可以消除 3 中funcall的一个。其他两个确实是必要的。

相同newton-method:替换(funcall #'newton-transform g)(newton-transform g)

附言。我强烈建议defun close-enoughp移出defun fixed-point或将其转换为cl-flet. Lisp 不是 Scheme。

聚苯乙烯close-enoughp应该是close-enough-p

于 2019-12-26T18:20:32.170 回答
1

可以简化几个函数调用,我们应该实现@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请注意,我们在调用之前定义和命名的函数时不需要使用derivnewton-transform

于 2019-12-26T20:53:58.133 回答