4

私はラケットを初めて使用し、変更可能な数値変数が必要なインスタンスに遭遇しました

以下は、ビットの文字列 (101011....) を介して機能する関数で、1 に遭遇した場合は「値」という名前の数値変数を変更し、0 に遭遇した場合は同じ変数「値」を変更する必要があります。したがって、文字列の最後に到達すると、「値」の合計になります。

(define (implode bstr value)
        (for ([c (string-length bstr)])
           (display (string-ref bstr c))
      (if (eqv? (string-ref bstr c) #\1) (displayln (+ (/ value 3) 17))
          (displayln (/ value 3)))))

mtauble 変数なしで、プログラムの実行中にこの変数を変更するにはどうすればよいですか?

4

3 に答える 3

6

ラケットはミューテーション対応。例えば:

#lang racket

;; count-whales: (listof string) -> number
;; Returns a count of the number of whales in lst.
(define (count-whales lst)
  (define c 0)
  (for ([thing lst])
    (when (equal? thing "shamu")
      (set! c (add1 c))))
  c)

;; Example:
(count-whales '("shamu" "donald duck" "shamu"))

おそらく、このようにループを見るのに慣れているでしょう。突然変異により、実行中の値を記録することができます。ミューテーションで書くことに支障はありません。しかし、そうは言っても、上記の機能はラケット特有のものではありません。Racketeer は代わりに、ミューテーションを使用するのではなく、値を蓄積できるループを使用します。

アキュムレータを使用して記述した場合、上記の関数は次のようになります。

#lang racket

;; count-whales: (listof string) -> number
;; Returns a count of the number of whales in lst.
(define (count-whales lst)
  (for/fold ([c 0])
            ([thing lst])
    (if (equal? thing "shamu")
        (add1 c)
        c)))

;; Example:
(count-whales '("shamu" "donald duck" "shamu"))
于 2012-12-17T21:27:09.943 に答える
5

示唆されているように、この問題は可変変数を使用せずに再帰を使用して簡単に解決できます。これは、Scheme でプロシージャを記述するための推奨される方法です。

(define (implode bstr value)
  (let loop ((value value)
             (lst (string->list bstr)))
    (cond ((null? lst)
           value)
          ((char=? (car lst) #\1)
           (loop (+ (/ value 3) 17) (cdr lst)))
          ((char=? (car lst) #\0)
           (loop (/ value 3) (cdr lst)))
          (else (error "unexpected char" (car lst))))))
于 2012-12-16T04:42:52.447 に答える
4

関数の目的が何かはimplodeわかりませんが、確かにミューテーションを使用する必要はありません。Racket は末尾呼び出しの除去を備えた高水準言語です。つまり、Óscar の例で行われたローカル関数を介したループは、後でコンパイラがミューテーションまたは必要なものを使用する効率的なコードに変換するものです。

しかし、それ以上に、より簡潔で、おそらくミューテーションのメンタル モデルに近い Racket コードの書き方を示すのは良いことです。ここでの主な要素はfor/fold、「for ループ」を実行しているが、ループ全体で「状態変数」を使用する です。ここでの「状態」は、実際には存在しないため引用されています。実際には、Óscar の例と同様の種類のループに展開されるマクロです。また、コードの他の部分についても、マイナーではあるが知っておくと役立ついくつかの方法で改善しました。文字列を直接反復処理でき、インデックスは必要ありません。はin-string実際には必要ありませんが、繰り返しの種類がより明確になり、高速になりbstr、文字列でない場合はエラーがスローされます。あなたが使用することができますcaseあなたが乗っているキャラクターを確認するには; それを使用している限り、文字が「0」でも「1」でもない場合はエラーをスローすることをお勧めします。

これがどのように見えるかです:

(define (implode bstr)
  (for/fold ([value 0]) ([c (in-string bstr)])
    (case c
      [(#\0) (+ (/ value 3) 17)]
      [(#\1) (/ value 3)]
      [else (error 'implode "bad character: ~e" c)])))

それでも、これはいくつかの奇妙な結果を生成しますが、繰り返しますが、この関数が何をすべきかはわかりません...

于 2012-12-16T04:58:39.863 に答える