1

私の質問は、ネストされた if 条件をcond、ローカル バインディングを持つブランチを持つ単一の条件に書き換えることについてです。私はラケットに非常に慣れていないので、最初の一歩を踏み出したばかりなので、私の質問がばかげている場合は、寛大にしてください.

簡単に言えば、このタスクは、ベクトルを取り、その中の値を検索する関数を作成することです。ベクトルには、ペアと非ペアの混合物が含まれています。関心のある値は、ペアの車にある必要があります。

実用的なソリューションでは、ネストされた if で再帰ヘルパー関数を使用します

[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) が数回計算されることです。これは、ネストされたifを使用した以前の実装のように、1回だけ計算されるように書き直したいものです

[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))]))])

そして、これが私が達成した最大のものです: (vector-ref vec pos)test-expr での 1 つの呼び出しと、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

eltest-expr と result-expression の間でさらに共有するにはどうすればよいですか? elそして、私はこの特定の cond-branch のローカルにとどまりたいと思っています。以下のコードは正しく動作しません。AFAIU、letrec式全体が cond の text-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))])
4

1 に答える 1

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>)節を許容することです。ここで、ジェネレーターは、ガードレシーバーの両方で使用される共通の値を作成するものです。この場合のレシーバーは単にvaluesであり、何も処理せずに与えられた値を返します。


更新:現在srfi/61、などを使用するプログラムでは正しく動作しません#lang racket(提供するものとsrfi/61は異なるバインディングを使用しています)。これは最近修正されており、将来の Racket リリースで表示されるはずです。=>elseracket/private/cond

于 2013-02-27T10:28:20.677 に答える