【问题标题】:Possible to use a let within an if/cond?可以在 if/cond 中使用 let 吗?
【发布时间】:2021-06-01 20:30:39
【问题描述】:

我经常发现自己想要使用列表中的当前元素,而不是总是需要对其运行程序来获取它,例如每次我想引用时都使用elem 而不是(car sequence)到序列中的当前元素。这有效...除非序列为空,因此我不能将let 放在null 检查之前。这是我试图做的“模式”:

(define (filter sequence)
  ; return a list of only those items where the filter predicate returns true
  (cond ((null? sequence) nil)
        ; now that we know we have an active sequence, I want to short-hand 'elem' and 'rest'
        (let (elem car sequence) 
              (rest cdr sequence))
          (display elem)))

然后我收到一条错误消息let: bad syntax。有没有办法以某种方式实现上述模式?

更新:也许最好的方法就是在顶部加上一个let 并用一个简单的if 检查?比如:

(define (filter sequence)
  (let ((elem (if (null? sequence) nil (car sequence)))
       (rest (cdr sequence)))
    (cond ((null? sequence) nil)
          (display elem))))
  

【问题讨论】:

  • 你的方法是正确的,但是你的括号在 let 绑定中是关闭的
  • @coredump 下面的答案看起来好吗?
  • 您还应该看到Pattern Matching

标签: scheme lisp racket sicp


【解决方案1】:

[这是我昨晚开始写的 coredump 答案的附录(我认为这是正确的),所以我会把它留给后代。]

从您的代码开始:

(define (filter sequence)
  (cond ((null? sequence) nil)
        (let (elem car sequence) 
              (rest cdr sequence))
          (display elem)))

这里至少有三个问题:首先你搞砸了cond的语法,它是(部分)

(cond (<test> <expr> ...)
      ...
      (else <expr> ...))

因此,要修复此问题,您需要添加明确的else 子句:

(define (filter sequence)
  (cond ((null? sequence) nil)
        (else
         (let (elem car sequence) 
           (rest cdr sequence))
         (display elem))))

现在的问题(这个问题的错误是由于某种原因掩盖了cond 中的错误)是你搞砸了let 的语法,即(再次,部分地):

(let ((<var> <val>) ...) <expr> ...)

您在这里犯了两个单独的错误:您错过了绑定表单周围的括号,并且表达式根本不在 let 的正文中。所以,修复那些:

(define (filter sequence)
  (cond ((null? sequence) nil)
        (else
         (let ((elem car sequence)
               (rest cdr sequence))
           (display elem)))))

我们现在得到了最终的错误:对carcdr 的调用没有括号。所以修复那些:

(define (filter sequence)
  (cond ((null? sequence) nil)
        (else
         (let ((elem car sequence)
               (rest cdr sequence))
         (display elem))))

好吧,现在这仍然不正确,那是因为你错过了对 carcdr 的调用的括号:

(define (filter sequence)
  (cond ((null? sequence) nil)
        (else
         (let ((elem (car sequence))
               (rest (cdr sequence)))
           (display elem)))))

这现在有效,但实际上并没有过滤序列。为此,它需要递归:

(define (filter sequence)
  (cond ((null? sequence) nil)
        (else
         (let ((elem (car sequence))
               (rest (cdr sequence)))
           (if (null? elem)
               (filter rest)
               (cons elem (filter rest)))))))

将内部条件提升到cond 可能会更好:

(define (filter sequence)
  (cond ((null? sequence) nil)
        ((null (car sequence)) (filter (cdr sequence)))
        (else (cons (car sequence) (filter (cdr sequence))))))

尽管现在您遇到了多次调用carcdr 的问题,我认为您想避免这种情况。

如果你使用完整的 Racket,一个很好的表达方式是使用匹配,它可以很好地结合检查和绑定:

(define (filter sequence)
  (match sequence
    ['() '()]
    [(cons '() tail)
     (filter tail)]
    [(cons head tail)
     (cons head (filter tail))]))

【讨论】:

    【解决方案2】:

    您的第一个代码 sn-p 的括号格式不正确。在这里使用if 而不是cond,可以如下修复:

    (define (filter sequence)
      ; return a list of only those items where the 
      ; filter predicate returns true
      (if (null? sequence) 
          'nil
          ; now that we know we have an active sequence, 
          ; I want to short-hand 'elem' and 'rest'
          (let ((elem (car sequence)) 
                (rest (cdr sequence)))
            (display elem)
            (filter rest))))
    

    还请注意,我以递归方式调用 filter。您需要修改它以接受谓词参数并实际过滤元素。

    【讨论】:

      【解决方案3】:

      这样做的一个 hack-ish 方法是将 let 放在顶部 -- 在条件之前并添加 if 检查每个 let 变量,例如:

      (define (filter test sequence)
        (let ((elem (if (null? sequence) nil (car sequence)))
              (rest (if (null? sequence) nil (cdr sequence))))
          (cond ((null? sequence) nil)
                ((test elem) (cons elem (filter test rest)))
                (else (filter test rest)))))
      
      (filter (lambda (x) (> x 2)) '(1 2 3 4 5))
      ; (3 4 5)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-22
        • 1970-01-01
        • 1970-01-01
        • 2022-06-29
        • 2018-09-16
        • 2017-11-02
        • 2021-03-25
        • 1970-01-01
        相关资源
        最近更新 更多