球拍开始形式

Racket begin form

(define mystery2 
  (lambda (L)
    (if (null? L)
        L
        (begin
          (displayln L)
          (append (mystery2 (cdr L))
                  (list (car L)))))))

我 运行 它由 (mystery2 '((1 2) (3 4) 5 6))

在这里,我不确定 "begin" 函数的作用。

此外,当我写 "displayln L" 时,它只会给我们 ((1 2) (3 4) 5 6))既然是递归,它不应该打印出递减的值吗?

请帮我理解为什么这里使用 "begin" 并且 displayln 是这样工作的。

代码本身没有问题

首先,让我回答你的问题:

begin 形式(它不是函数)只计算它的子表达式,returns 是最后一个的值。

因此,如果您评估 (begin 3 4 5),它将只是 return 5。如果你评估 (begin (+ 3 4) (+ 9 1)),你将得到 10

所以...您可能会振振有词地问为什么这会有用。答案是某些表达式会导致所谓的 "side effects"。 displayln 是其中之一;它会导致显示一个值。

不过,让我们退后一步。这里的秘诀是:尝试一下! Racket 是一种对实验非常友好的语言;几乎所有值都有直接的 "writable" 形式,您可以提取小表达式并计算它们以查看它们产生的结果。

随时提出后续问题!

使用 begin 形式是因为 if 在每个分支中只允许 1 个表达式。

一个更直观的例子可能是调试。假设您正在编写困难的代码并且您想查看执行了哪个分支。

原代码:

(if (true? some-value)
    (dostuff)
    (dostuff2))

但是您不确定正在执行哪个分支,因此您可能希望在执行任一分支时都打印一条消息。但是由于 Scheme 只允许在每个分支中有一个表达式,所以你不能把它们放在那里。您必须将它们粘合在一个表达式中,使用 begin.

(if (true? some-value)
    (begin
      (display "some-value was true")
      (dostuff))
    (begin 
      (display "some-value was false")
      (dostuff2)))

Begin 获取任意数量的表达式并执行每个表达式,但仅 returns 正文中最后一个表达式的结果。

begin 将几个表达式包装成一个 block。使用 cond 而不是 if 的原因之一是结果自动包装在一个块中。

(define mystery2 
  (lambda (L)
    (cond [(null? L)
           L] 
          [else
            (displayln L)
            (append (mystery2 (cdr L))
                    (list (car L)))])))