【问题标题】:Not able to use let in Racket无法在球拍中使用 let
【发布时间】:2017-01-07 11:06:44
【问题描述】:

我正在尝试修改 http://home.adelphi.edu/~siegfried/cs270/270rl10.html 上的排序代码,我将 let 用于插入函数:

(define (mysort alon ) 
  (let insert ((n n) (alon  alon)) 
    (cond 
      [(empty? alon) (cons n empty)] 
      [else (cond 
              [(< n (first alon)) (cons n alon)] 
              [else (cons (first alon) 
                          (insert n (rest alon))])])
  (cond 
    [(empty? alon) empty] 
    [(cons? alon) (insert (first alon) 
                           (mysort (rest alon)))])))

(mysort (list 1 2 3 4 5 6 2 3 1 4 5 2 10))

但是,它在“let”变量声明的级别上不起作用:

n: unbound identifier in module in: n

我在这里 (https://docs.racket-lang.org/reference/let.html) 看到“让”需要具有变量的初始值。我们可以在不初始化变量的情况下使用'let'吗?上面的代码如何改正?


编辑:我尝试使用 lambda 但它不起作用:

(define (mysort4 alon ) 
  (let ([insert4
         (lambda (n alon) 
           (cond 
             [(empty? alon) (cons n empty)]
             [(< n (first alon)) (cons n alon)] 
             [else (cons (first alon) 
                         (insert4 n (rest alon) ))]))])
    (cond 
      [(empty? alon) empty] 
      [(cons? alon) (insert4 (first alon) 
                             (mysort4 (rest alon) ) )])))

(mysort4 (list 1 2 3 4 5 6 2 3 1 4 5 2 10))

错误是:

insert4: unbound identifier in module in: insert4

【问题讨论】:

  • 命名let 没有变量的初始值将只是一个lambda。
  • 我无法在上面的代码中插入 lambda 关键字。 "(let insert (lambda (n alon") 和 "(let insert lambda (n alon") 都不起作用。
  • "(let ([insert4 (lambda (n alon) ... ])" 也不起作用。

标签: scheme racket let


【解决方案1】:

当你用let创建东西时

(define test 10)

(let ((test (lambda (x) 
              (list x test))))
  (test 'result))
; ==> (result 10)

显然,lambda 中的test 是全局变量,而不是“本身”,但为什么。 let 只是一个匿名函数的语法糖,它会立即被调用,因此我们可以将其重写为:

(define test 10)
((lambda (test)
   (test 'result))
 (lambda (x) 
   (list x test)))

在这里您看到第一个 lambda 具有 test 作为绑定变量,因此始终是第一个操作数,但第二个 lambda 除了全局绑定之外没有 test

在递归过程中不能使用let,因为在创建闭包时绑定不在环境中(评估lambda)。为了解决这个问题,我们使用letrec 来解决这个问题:

(define test 10)    
(letrec ((test (lambda (x) 
              (list x test))))
  (test 'result))
; ==> (result #<procedure:test>)

要了解为什么可以查看此表单的扩展:

(let ((test 'undefined)) 
  (let ((newtemp (lambda (x) (list x test)))) 
    (set! test newtemp)) 
  (test 'result))))
; ==> (result #<procedure:test>)

我不会在这里展开 let 表单,但请看一下 test 在创建 lambda 时存在的事实。 lambda 成为值,但绑定是相同的。

不是顶级的define被重写*为letrec,所以下面的代码完全相同:

(let () ; this is to make `define` local and not global
  (define test (lambda (x) 
                 (list x test))
  (test 10))
; ==> (result #<procedure:test>)

在命名let 中,名称绑定在letrec 中,但其他值没有。修复第一个:

(define (mysort alon)   
  (cond 
    [(empty? alon) empty] 
    [(cons? alon)
     (let insert ((n (first alon))
                  (alon  (rest alon))) 
       (cond 
         [(empty? alon) (cons n empty)] 
         [(< n (first alon)) (cons n alon)] 
         [else (cons (first alon) (insert n (rest alon)))]))]))

请注意,我将嵌套的 cond 展平,因为 cond 的全部意义在于不必嵌套它们。它相当于其他语言中的if-elseif*-else。该代码不起作用,因为它只放置第一个元素。也许从一个空列表开始插入一个列表中的所有元素会起作用。

第二个只适用于从let 更改为letrec。该代码与仅根据其余元素插入第一个元素的相同功能相同,但递归将适用于该元素。

如果您查看您链接到的页面,您会发现您insert 进入的列表已经排序。 IE。你在那里遗漏了一些东西..

insertion-sort 不是一种有效的算法。 #lang racket 使用合并排序并针对较小的列表进行调整。试图以速度击败它将是愚蠢的差事。

* 或反之亦然。球拍使用letrec(准确地说是letrec-values

【讨论】:

    【解决方案2】:

    当您需要内部辅助函数时,使用内部定义而不是 let。 通过最小的更改(使用define 而不是let),您将获得:

    #lang racket
    (define (mysort alon )
      (define (insert n alon)
        (cond 
          [(empty? alon) (cons n empty)]
          [else          (cond 
                           [(< n (first alon)) (cons n alon)] 
                           [else               (cons (first alon) 
                                                     (insert n (rest alon)))])]))
      (cond 
        [(empty? alon) empty]
        [(cons?  alon) (insert (first alon) 
                               (mysort (rest alon)))]))
    
    (mysort (list 1 2 3 4 5 6 2 3 1 4 5 2 10))
    

    【讨论】:

    • 我知道定义有效,但我想知道在这种情况下是否有任何方法可以使用“让”。显然,我不能。
    • 那么您真正想问的是“named let 是如何工作的”?
    猜你喜欢
    • 2018-05-18
    • 2015-04-08
    • 2017-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 1970-01-01
    • 2016-07-29
    相关资源
    最近更新 更多