我正在尝试编写一些代码,但我的回复程序存在问题。忽略前两个三个随机数的过程,但问题出在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))
它抛出了这个错误:
random: contract violation expected: (or/c (integer-in 1 4294967087) pseudo-random-generator?) given: 0
我不确定这个错误意味着什么或如何解决它......
答案 0 :(得分:2)
错误只是说清单' length为零,random
期望值介于1和4294967087之间。调用pick-random
时传递非空列表。这就是发生的事情:
(random 0)
=> random: contract violation expected: (or/c (integer-in 1 4294967087)
pseudo-random-generator?) given: 0
尝试在开头使用非空列表定义earlier-responses
。
答案 1 :(得分:2)
奥斯卡正确回答了你提出的问题,但你有一个更糟糕的错误,你还没有意识到:你应该在进入cond表达式之前计算一次随机数,而不是在每个cond子句中重新计算它。使用您的方法,您不会以相同的概率选择三种可能性中的每一种。第一种选择将在大约1/3的时间内被选择,第二种选择将被选择为剩余的2/3时间的1/3,或2/9,第三种选择将被选择为剩余的4 / 9个时间。您可能希望所有三种选择都以相同的概率发生。
答案 2 :(得分:1)
我想你知道现在几点了。
[dons code-review hat /]
首先,在我们得到其他任何内容之前,您使用的是什么版本的Racket?
我这里有5.2.1,所以我可能有些落后,但nth
和write-line
似乎没有在这里定义函数。我认为你想要的是list-ref
和write
。请注意,list-ref
具有不同的参数顺序,并期望列表中的零索引引用。换句话说(list-ref (list 1 2 3) 0) => 1
。因此,您可能希望将pick-random
定义为
(define (pick-random lst)
(list-ref lst (random (length lst))))
您还有一些未定义的函数,我假设您在程序的其他位置定义了hedge
,qualifier
和change-person
)。我会在进一步的评论中忽略这些。
正如Óscar所提到的,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
函数的reply
子句不能是您的意思,除非write-line
执行与write
根本不同的事情。
(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
。 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)))
但是,这似乎不是你想要的那样。以上内容总是将两个元素的列表传递给驱动程序循环的下一次迭代;第一个元素是最近的响应,第二个元素是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)))
答案 3 :(得分:1)
(定义随机4位数 (foldr(λ(n结果) (cons((map(λ(y)(if(> = y n)(add1 y)y)) 结果))) “() (地图随机'(10 9 8 7))))
答案 4 :(得分:0)
(or/c (integer-in 1 4294967087) pseudo-random-generator?)
是an "or" contract - 意思是,要被此合约接受,价值(random
function的参数)必须是以下之一:an integer between 1
和4294967087
,包括or object
,(pseudo-random-generator? object)
返回#t
。