微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

可以在 if/cond 中使用 let 吗?

如何解决可以在 if/cond 中使用 let 吗?

我经常发现自己想要处理列表中的当前元素,而不必总是在其上运行一个过程来获取它,例如每次都使用 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))))
  

解决方法

[这是我昨晚开始写的 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))]))
,

您的第一个代码片段的括号格式不正确。在这里使用 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。您需要修改它以同时接受谓词参数并实际过滤元素。

,

一种黑客式的方法是将 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)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。