cond with local binding

时间:2013-02-27 10:07:11

标签: conditional-statements racket letrec

我的问题是将嵌套的if条件重写为具有本地绑定的分支的单个cond。我对Racket很新,只是迈出了我的第一步,所以如果我的问题很愚蠢,请宽容。

简而言之,任务是编写一个带矢量并在其中搜索值的函数。向量包含混合的东西 - 对和非对。感兴趣的价值应该是一对的车。

工作解决方案使用带有嵌套ifs的递归辅助函数

[vlen (vector-length vec)]
[find-in-vector
(lambda (pos)
 (if (= pos vlen)                               ;; if the end of the vector has been reached
     #f                                         ;; then return false
     (let ([el (vector-ref vec pos)])           ;; Otherwise, extract current element from the vector,
       (if (and (pair? el) (equal? v (car el))) ;; if the element is a pair and its car is what we want
           el                                   ;; then return the element
           (find-in-vector (+ 1 pos))))))]      ;; otherwise keep searching the vector

我想重写它,以便它使用看起来更紧凑的cond。 以下代码是一种可能的实现方式。问题是(vector-ref vec pos) 计算好几次,这就是我想重写的内容 它只计算一次,就像之前使用嵌套ifs

的实现一样
[vlen (vector-length vec)]
[find-in-vector
 (lambda (pos)
   (cond [(= pos vlen) #f]
         [(and (pair? (vector-ref vec pos))            ;; one
               (equal? v (car (vector-ref vec pos))))  ;; two
          (vector-ref vec pos)]                        ;; three is too many
         [#t (find-in-vector (+ 1 pos))]))])

这就是我最多取得的成果:在test-expr中调用(vector-ref vec pos) 和result-expr中的另一个调用

(cond
  [(= pos vlen) #f]
  [(letrec ([el (vector-ref vec pos)])      ;; extract current element from the vector
     (and (pair? el) (equal? v (car el))))  ;; and use it in conditionals
   (vector-ref vec pos)]                    ;; again, extract and return. FIXIT
  [#t (find-in-vector (+ 1 pos))]))])       ;; otherwise, keep searching

如何进一步在test-expr和result-expression之间共享el? 我希望el保持在这个特定的cond分支的本地。 以下代码工作不正确。 AFAIU,整个letrec表达式是 被视为cond的文本expr?

(cond
 [(= pos vlen) #f]
 [(letrec ([el (vector-ref vec pos)])
    (and (pair? el) (equal? v (car el)))
    el)]
 [#t (find-in-vector (+ 1 pos))])

1 个答案:

答案 0 :(得分:1)

如果先导入SRFI 61,则可以执行此操作:

(require srfi/61)
(define (find-in-vector vec v)
  (define vlen (vector-length vec))
  (let loop ((pos 0))
    (cond
      ((= pos vlen) #f)
      ((vector-ref vec pos)
       (lambda (el) (and (pair? el) (equal? v (car el))))
       => values)
      (else (loop (add1 pos))))))

SRFI 61提供的重要一点是它允许(<generator> <guard> => <receiver>)子句。这里,生成器是创建一个公共值以供 guard receiver 使用的东西。在这种情况下,我们的接收器只是values,它返回给定的值而不进行任何处理。


更新:目前srfi/61对于使用#lang racket之类的程序无法正常运行(srfi/61正在使用=>的不同绑定和else提供的racket/private/cond。这已经recently fixed,并且应该出现在未来的Racket版本中。