【问题标题】:(let (next (f guess)) vs (let ((next (f guess)))(让(下一个(f猜测))vs(让((下一个(f猜测)))
【发布时间】:2020-04-16 09:36:49
【问题描述】:

sicp中的定点实践

#+BEGIN_SRC scheme
(define tolerance 0.00001)

(define (fixed-point f first-guess)
  (define (close-enough? v1 v2)
    (< (abs (- v1 v2)) tolerance))
  (define (try guess)
    (let ((next (f guess)))
      (if (close-enough? guess next)
          next
          (try next))))
  (try first-guess))
(fixed-point cos 1.0)
#+END_SRC

#+RESULTS:
: 0.7390822985224024

参考线

(let ((next (f guess)))

我假设添加了额外的括号,并将其更改为

(let (next (f guess))

再次运行但拒绝工作

#+BEGIN_SRC scheme
(define tolerance 0.00001)

(define (fixed-point f first-guess)
  (define (close-enough? v1 v2)
    (< (abs (- v1 v2)) tolerance))
  (define (try guess)
    (let (next (f guess))
      (if (close-enough? guess next)
          next
          (try next))))
  (try first-guess))
(fixed-point cos 1.0)
#+END_SRC

#+RESULTS:

有什么问题?

【问题讨论】:

  • “我假设添加了额外的括号”。不,你不应该假设书中的代码有比需要更多(或更少)的括号。如有必要,请检查所使用的每种特殊形式的文档页面,以阐明语法。

标签: syntax scheme lisp let sicp


【解决方案1】:

方案

我假设添加了额外的括号

在方案中不能假设。括号通常不是可选的,而是表达式语法的必要部分。

Scheme(R5RS、R6RS、R7RS)中let的语法为:

(let <bindings> <body>) 

Syntax: <Bindings> should have the form

((<variable1> <init1>) ...)

因此,在您的示例中,next 是变量,(f guess) 是初始化形式。

您尝试省略一定级别的括号导致语法错误。以下表格不是有效的方案。

(let (next          ;  a symbol is not allowed, only (var init) lists
      (f guess))    ;  variable 'f' and init form 'guess'
  ...
  )

语法与其他一些 Lisp 语言略有不同。

Emacs Lisp

参见例如 Emacs Lisp:3.6.1 The Parts of a let Expression

因此在 Emacs Lisp 中可以只写一个变量,这样它将绑定到nil

(let ((var1 init1)
      var2
      (var3 init3)
      var4
      ...)
  ...)

普通 Lisp

Common Lisp 也允许省略 init 形式。语法:

let ({var | (var [init-form])}*) declaration* form*

因此在 Common Lisp 中我们也可以有

CL-USER > (let ((a 10)     ; a bound to 10
                b          ; b bound to NIL 
                (c))       ; c bound to NIL
            (list a b c))
(10 NIL NIL)

但不是在标准方案中...

【讨论】:

  • Common Lisp 和 Emacs Lisp 中的 IOW (let (next (f guess)) ... == (let ((next NIL) (f guess)) ... 有两个绑定,nextf
【解决方案2】:

这只是语法问题,您应该查看let 的文档。它需要一个 list 绑定和一个主体,其中每个投标都是一个包含两个元素、一个变量名和一个表达式的列表 - 所以这是正确的方法(添加了额外的换行符以进行解释,但是你永远不要像这样缩进):

(let ( ; start list of bindings
      ( ; start binding
       next ; binding name
       (f guess) ; binding value
      ) ; end binding
     ) ; end list of bindings
  <body>)

你的尝试失败了:

(let (next (f guess))
  ...)

...因为它缺少在正文部分之前分隔绑定列表的外部()。现在应该很明显了,我们可以将多个绑定作为let 的一部分,这就是绑定列表的外部() 是强制性的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-24
    • 1970-01-01
    • 2022-11-07
    • 1970-01-01
    • 2018-07-13
    相关资源
    最近更新 更多