python-3.x - `fixed-point` 中的内部 `try` 交互
问题描述
我正在阅读fix-point
SICP:
#+begin_src emacs-lisp :session sicp :lexical t
(defvar tolerance 0.00001)
(defun fixed-point(f first-guess)
(defun close-enoughp(v1 v2)
(< (abs (- v1 v2)) tolerance))
(defun try(guess) ;;
(let ((next (funcall f guess)))
(if (close-enoughp guess next)
next
(try next))))
(try first-guess))
(fixed-point #'cos 1.0)
#+end_src
#+RESULTS:
: 0.7390822985224024
从上面的案例中,我了解到,一个本质while
是抽象概念“尝试”
#+begin_src ipython :session sicp :results output pySrc/sicp_fixedpoint2.py
import math
def fixed_point(f, guess):
while True:
nex = f(guess)
if abs(guess-nex) < 0.0001:
return nex
else:
guess = nex #local assignment is nature of lambda
print(fixed_point(math.cos, 1))
#+end_src
#+RESULTS:
: 0.7390547907469174
所以我可以用有效的函数抽象思维在 python 中编写迭代。
反思时try
,不仅仅是“尝试是迭代中的一段时间”,它教会了我什么?
它可以在没有的情况下重新构建try
,但return fixed_point(f, nex)
直接返回。
#+begin_src ipython :session sicp :results output :tangle pySrc/sicp_fixedpoint.py
import math
tolerance = 0.00001
def fixed_point(f, guess):
def good_enoughp(a, b):
return abs(a-b) < tolerance
nex = f(guess)
if good_enoughp(guess, nex):
return nex
else:
return fixed_point(f, nex)
print(fixed_point(math.cos, 1))
#+end_src
#+RESULTS:
: 0.7390822985224024
那么为什么try
在这里介绍SICP,我猜效率可能不是作者的主要考虑因素。
用 elisp 测试
#+begin_src emacs-lisp :session sicp :lexical t
(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)))
)
;;(trace-function #'fixed-point)
(fixed-point #'cos 1.0)
#+end_src
#+RESULTS:
: 0.7390822985224024
它按预期工作。
似乎 returnfixed-point f next
比带有 try 的内部迭代更干净一些。
SICP在这里的考虑是什么,打算教什么?
解决方案
恰恰相反:它更清洁、更高效,try
因为它不需要重新定义good-enough-p
.
(另外,你不应该在 Python 中使用递归)。
的版本try
优于调用顶部函数的版本fixed-point
,因为fixed-point
包含函数good-enough-p
和的内部定义try
。一个头脑简单的编译器会编译它,以便在每次调用时它实际上在每次调用时一次又一次地重新定义这些定义。try
没有这样的担忧,因为它已经在已经定义fixed-point
的内部环境中good-enough-p
,因此try
可以运行。
(更正/澄清:上面将您的代码视为Scheme,使用 internal define
s 而不是带有defun
s 的 Common Lisp,毕竟 SICP 是 Scheme。在 Common Lisp / ELisp 中甚至没有问题 -在每次调用封闭函数时,将始终执行internal defun
s,只是一遍又一遍地(重新)在顶层定义相同的函数。)
顺便说一句,我喜欢你的 Python 循环翻译,它是对 Scheme 的尾递归循环的逐字翻译,一对一。
鉴于您问题中的第一个尾递归方案代码,您的while
翻译正是方案编译器应该做的事情。两者完全相同,下至“可怕while True ...
的逃脱”,就我个人而言,我非常喜欢它的直接性和清晰性。意思是,我不需要跟踪哪个值被分配给哪个变量以及最终返回哪个变量——相反,一个值只是返回,就像它在 Scheme 中一样。
推荐阅读
- javascript - 在 react-native-web 图像中设置背景位置
- matlab - 无法在 Jupyter 中查看 Matlab 笔记本
- json - Django 视图连接到 json 或配置文件而不是 db
- python - 为什么 np.mean(x.flatten()==y) 的结果与 np.mean(x==y) 不同?
- hibernate - 启动 Micronaut 服务器时出错:无法加载 Bean 定义 [org.hibernate.SessionFactory]
- testing - Gradle 无法在 Windows 10 上运行我的项目测试(读取 executionHistory.lock 时出错;多进程锁定文件)
- apache - 将 {query}.m3u8 重写为 m3u8.php?v={query}
- react-native - 如何将隐式流密钥斗篷与本机反应一起使用?
- xcode - Distill 因未知原因失败 - 无法获取 first.imageset/first.pdf 的图像尺寸...
- sql - 多个连接和计数语句的 SQL 查询