1

コードを書こうとしていますが、返信手順に問題があります。最初の 2 つの 3 の乱数の手順は無視しますが、問題は手順elseを呼び出すときpick-randomです。コードは次のとおりです。

(define earlier-responses '()) 

(define (doctor-driver-loop name earlier-responses)
  (newline)
  (write '**)
  (let ((user-response (read)))
    (cond 
      ((equal? user-response '(goodbye))
         (write-line (list 'goodbye name))
         (write-line '(see you next week)))
      (else 
         (list user-response earlier-responses)                    
         (write-line (reply user-response earlier-responses))
         (doctor-driver-loop name earlier-responses)))))

(define (reply user-response earlier-responses)
  (cond 
    ((= (random-of-three) 0)
      (append (qualifier)
              (change-person user-response)))
    ((= (random-of-three) 1)
      (hedge))
    (else
      (append (write-line '(earlier you said that))
              (pick-random earlier-responses)))))

(define (random-of-three)
  (random 3))

(define (pick-random lst)
  (nth (+ 1 (random (length lst))) lst))

ハイライト

            (random (length lst))) lst)) 

次のエラーがスローされます。

  ランダム: 契約違反
  予想: (または/c (integer-in 1 4294967087) pseudo-random-generator?)
  与えられた: 0

このエラーの意味や修正方法がわかりません...

4

5 に答える 5

2

このエラーは、リストの長さが 0 であり、random1 から 4294967087 までの値が必要であることを示しているだけです。 を呼び出すときに、空でないリストを渡しpick-randomます。これが起こっていることです:

(random 0)

=> random: contract violation expected: (or/c (integer-in 1 4294967087)
   pseudo-random-generator?) given: 0

earlier-responses先頭に空でないリストを定義してみてください。

于 2013-02-27T01:57:01.427 に答える
2

Oscar はあなたの質問に正しく答えますが、あなたがまだ気づいていないさらに悪い間違いがあります: 各条件節で乱数を再計算するのではなく、条件式に入る前に一度乱数を計算する必要があります。この方法では、3 つの可能性のそれぞれを同じ確率で選択することはできません。最初の選択肢は約 1/3 の確率で選択され、2 番目の選択肢は残りの 2/3 の約 1/3、または 2/9 の確率で選択され、3 番目の選択肢は残りの 4/ で選択されます。 9回目。おそらく、3 つの選択肢すべてが同じ確率で発生することを望むでしょう。

于 2013-02-27T05:01:25.193 に答える
1

何時かご存知だと思います。

[コードレビューハットを着用/]

まず、他のことを始める前に、どのバージョンのラケットを使用していますか?

ここには5.2.1があるので、少し遅れているかもしれませんが、nthここwrite-lineでは関数が定義されていないようです。私はあなたが欲しいものはlist-refとだと思いますwritelist-ref引数の順序が異なり、リストへのゼロインデックス参照が必要であることに注意してください。言い換えれば(list-ref (list 1 2 3) 0) => 1。したがって、おそらく次のように定義する必要がありpick-randomます

(define (pick-random lst)
  (list-ref lst (random (length lst))))

また、プログラムの他の場所で定義していると思われる未定義の関数がいくつかあります(、、hedge)。これらは今後のコメントで削除します。qualifierchange-person


オスカーが言及しているようにrandom、1から4294967087の範囲の整数を取ります。これは、数値を渡す前にそれを考慮したいことを意味します。注意として、と(random n)の間の整数を返すように見えるので、リストからランダムな要素を取得するために自分で物を足したり引いたりする必要はありません。0(- n 1)

(define (pick-random lst)
  (if (null? lst)
      lst
      (list-ref lst (random (length lst)))))

user448810が述べているように、再計算する必要はありません。再計算するrandom-of-threeと、各選択の確率が等しくなるわけではないからです。事前に計算するので、おそらくrandom-of-three関数はまったく必要ありません。

(define (reply user-response earlier-responses)
  (let ((rand (random 3)))
    (cond ((= rand 0)
           (append (qualifier)
                   (change-person user-response)))
          ((= rand 1)
           (hedge))
          (else
           (append (write '(earlier you said that))
                   (pick-random earlier-responses))))))

write実際には何も返しません。何かをREPLに出力するだけなので、関数のelse句は、とは根本的に異なることをしない限り、意味するものにはなりません。replywrite-linewrite

(else
 (append (write '(earlier you said that))
         (pick-random earlier-responses)))

あなたはどちらかが欲しい

(else
   (write '(earlier you said that))
   (write (pick-random earlier-responses)))

印刷出力が必要な場合、または

(else
   (let* ((res (list '(earlier you said that) (pick-random earlier-responses))))
     (write res)
     res))

将来の使用のために戻り値をどこかに保存するつもりだった場合。


次に、これはおそらく私が目にする最大のバグであり、Schemeの初心者にとって最も簡単なバグです(したがって、気分が悪くなることはありません)earlier-responses。どこも変わっていません。あなたのelse節doctor-driver-loop

(else (list user-response earlier-responses)                    
      (write (reply user-response earlier-responses))
      (doctor-driver-loop name earlier-responses))

user-responseあなたを頭と尾として新しいリストを作成しますearlier-responsesが、あなたはそれを使って何もしません。また、への次の呼び出しに別の値を渡さないでくださいdoctor-driver-loop。実際に入力履歴を追跡したい場合は、次のようになります。

(else (write (reply user-response earlier-responses))
      (doctor-driver-loop name (list user-response earlier-responses)))

しかし、それはあなたがそれを望んでいるように見えることを完全には行いません。上記は常に2要素のリストをドライバーループの次の反復に渡します。最初の要素は最新の応答であり、2番目の要素はですearlier-responses

> (list '(I need a perscription) '((how are you doing?) (hello))) 
((I need a perscription) ((how are you doing?) (hello)))

> (list '(are you even listening?) '((I need a perscription) ((how are you doing?) (hello))))
((are you even listening?) ((I need a perscription) ((how are you doing?) (hello))))

を使用してランダムな過去の応答を選択できるようにしたい場合、本当に必要pick-randomなのは、すべての応答のフラットリストです。つまりcons、新しい応答を行うのではなく、新しい応答を行うことを意味listします。

> (cons '(I need a perscription) '((how are you doing?) (hello)))
((I need a perscription) (how are you doing?) (hello)))

> (cons '(are you even listening?) '((I need a perscription) (how are you doing?) (hello)))
((are you even listening?) (I need a perscription) (how are you doing?) (hello))

だからあなたのelse条項は

(else (write (reply user-response earlier-responses))
      (doctor-driver-loop name (cons user-response earlier-responses)))
于 2013-02-27T17:08:24.007 に答える
0

(or/c (integer-in 1 4294967087) pseudo-random-generator?)

「or」コントラクトです。つまり、このコントラクトで受け入れられるには、値 ( randomfunctionの引数) が次のいずれかでなければなりません:との間の整数またはを返すようなもの。14294967087object(pseudo-random-generator? object)#t

于 2013-02-27T23:23:28.427 に答える