【问题标题】:Why does `rest` return `'(())` instead of `'()` in racket为什么`rest`在球拍中返回`'(())`而不是`'()`
【发布时间】:2021-05-17 05:45:35
【问题描述】:

我遇到了这个关于如何使用可变参数过程来实现任意数量函数的组合的程序

(define compose-n
  (lambda fs
    (cond
      [(null? fs) identity]
      [else (lambda (x)
              ((first fs) ((apply compose-n (rest fs)) x)))])))

但是,当我删除最后一行的apply 并手动执行应用程序时,

(define removed-compose-n
  (lambda fs
    (cond
      [(null? fs) identity]
      [else (lambda (x)
              ((first fs) ((removed-compose-n (rest fs)) x)))])))

这开始循环并消耗所有内存,使我的计算机崩溃。此外,当我尝试打印出fs 以查看发生了什么时

(define removed-compose-n
  (lambda fs
    (printf "fs : ~s\n" fs)
    (cond
      [(null? fs) identity]
      [else (lambda (x)
              ((first fs) ((removed-compose-n (rest fs)) x)))])))

我很惊讶

fs : (#<procedure:id>)
fs : (())
fs : (())
fs : (())
fs : (())
fs : (())
fs : (^C                      
; user break [,bt for context]

这向我表明(rest fs) 的计算结果为'(()),这就是导致removed-compose-n 循环的原因,但compose-n 逃脱了这一点,因为(apply compose-n '(()))(compose-n '()) 相同,这与递归/第一个 cond 子句的基本情况。

为什么(rest fs) 评估'(()) 而不是'(),导致removed-compose-n 循环?还是我完全错过了循环其他内容的原因?

【问题讨论】:

    标签: recursion racket infinite-loop


    【解决方案1】:

    考虑一个简单的案例,您将removed-compose-n 应用于add1

    (removed-compose-n add1)
    

    函数体内的fs 计算结果为(list add1)。由于它不是'(),因此我们评估第二个 cond 子句的 RHS。

    (lambda (x)
      ((first (list add1)) ((removed-compose-n (rest (list add1))) x)))
    

    评估firstrest

    (lambda (x)
      (add1 ((removed-compose-n '()) x)))
    

    当我们评估以下子表达式时:

    (removed-compose-n '())
    

    fs 的值是(list '()),与'(()) 相同。这个无限循环,因为下一个应用程序仍然是(removed-compose-n '())

    使用apply“拼接”参数。第二个例子传入 list 本身 而不拼接它的元素。

    【讨论】:

      【解决方案2】:

      我终于明白发生了什么,可变参数过程语义已经让我忘记了。

      问题不是rest 返回'(())rest 确实返回 '()。然而,像removed-compose-n 这样的可变参数过程将它们的参数收集到一个列表中(实际上,这就是可变参数的实现方式,因为列表的长度不是固定的)。例如,对于应用程序(removed-compose-n identity add1 sub1)fs 的值将是'(identity add1 sub1),对于应用程序(removed-compose-n identity)fs 的值将是'(identity)。同样,对于应用程序(removed-compose-n '())fs 的值将是'(()),这会导致循环。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-20
        • 1970-01-01
        • 1970-01-01
        • 2015-11-02
        • 2021-09-13
        • 2017-06-30
        • 1970-01-01
        • 2012-11-19
        相关资源
        最近更新 更多