在 Racket 中解决难题 [英] Solving a puzzle in Racket
问题描述
我试图解决这个难题 https://puzzling.stackexchange.com/questions/40094/who-committed-the-crime 使用 Racket.
<块引用>一个人犯罪,有5个嫌疑人.每个在测谎仪下询问嫌疑人他们认为谁犯了罪.
他们的回答如下:
Terry:不是卡尔,是史蒂夫史蒂夫:不是马特,不是卡尔马特:是卡尔,不是特里本:是马特,是史蒂夫卡尔:是本,不是特里
<块引用>
测谎仪显示每个嫌疑人都说了一个谎言和一个真相.谁犯了罪?
以下是我的代码:
(define (oneof a b)(或(和a(不是b))(和b(不是a))))(对于((i 5))(定义临时列表(列表#f #f #f #f #f));制作一个所有虚假的临时清单;(set!templist (list-set templist i #t)) ;在这个循环中一一保持为真;(定义 t (list-ref templist 0)) ;按照上面的名单分配每个人(一个一个地保持真实)(定义 s (list-ref templist 1))(定义 m (list-ref templist 2))(定义 b (list-ref templist 3))(定义 c (list-ref templist 4))(when ; 测试所有语句是否符合上述赋值:(和(其中一个(不是 c) s);特里的声明(oneof (not m) (not c)) ;史蒂夫的声明(一个c(不是t));马特的声明(其中一个);本的声明(一个 b (不是 t))) ;卡尔的声明(println (list "t" "s" "m" "b" "c")) ;如果所有语句都适合,则打印分配;(println 临时表)))
输出表明马特犯了罪:
'("t" "s" "m" "b" "c")'(#f #f #t #f #f)
它可以工作,但代码是命令式的,功能不是很强大(尤其是定义 t、定义 s、...部分).如何改进?感谢您的评论/回答.
这是一个用惯用的 Racket 编写的等效程序 - 避免所有那些讨厌的 set!
和 list-ref
在编写函数式代码时不受欢迎:
<代码>;生成具有可能性的矩阵(定义(生成矩阵 n)(for/list [(i (in-range n))](构建列表 n (λ (j) (= i j)))));迭代每一行(for [(row (make-matrix 5))];将每一行解包成相应的变量(match-let ([(list t s m b c) row]);不要重新发明轮子,`oneof`被称为`xor`(当 (和 (xor (not c) s)(异或(非 m)(非 c))(异或 c(不是 t))(异或毫秒)(xor b (不是 t)))(println '(t s m b c))(println 行)))))
I tried to solve this puzzle https://puzzling.stackexchange.com/questions/40094/who-committed-the-crime using Racket.
A crime has been carried out by one person, there are 5 suspects. Each suspect is asked under polygraph who they think committed the crime.
Their answers are as follows:
Terry : It wasn't Carl, It was Steve
Steve : It wasn't Matt, It wasn't Carl
Matt : It was Carl, It wasn't Terry
Ben : It was Matt, It was Steve
Carl : It was Ben, It wasn't Terry
The polygraph showed that each suspect told one lie and one truth. Who committed the crime?
Following is my code:
(define (oneof a b)
(or (and a (not b)) (and b (not a))))
(for ((i 5))
(define templist (list #f #f #f #f #f)) ; make a temporary list of all false;
(set! templist (list-set templist i #t)) ; one by one keep one as true in this loop;
(define t (list-ref templist 0)) ; allocate each person according to above list (one kept true one by one)
(define s (list-ref templist 1))
(define m (list-ref templist 2))
(define b (list-ref templist 3))
(define c (list-ref templist 4))
(when ; test if all statements fit with above assignment:
(and
(oneof (not c) s) ; Terry's statement
(oneof (not m) (not c)) ; Steve's statement
(oneof c (not t)) ; Matt's statement
(oneof m s) ; Ben's statement
(oneof b (not t))) ; Carl's statement
(println (list "t" "s" "m" "b" "c")) ; print allocation if all statement fit in;
(println templist)))
Output indicates Matt committed the crime:
'("t" "s" "m" "b" "c")
'(#f #f #t #f #f)
It works but the code is imperative and not very functional (especially define t, define s, ... part). How can it can be improved? Thanks for your comments/answers.
This is an equivalent program written in idiomatic Racket - and avoiding all those pesky set!
and list-ref
which are frowned upon when writing functional-style code:
; generate a matrix with possibilities
(define (make-matrix n)
(for/list [(i (in-range n))]
(build-list n (λ (j) (= i j)))))
; iterate over each row
(for [(row (make-matrix 5))]
; unpack each row into the corresponding variables
(match-let ([(list t s m b c) row])
; don't reinvent the wheel, `oneof` is called `xor`
(when (and (xor (not c) s)
(xor (not m) (not c))
(xor c (not t))
(xor m s)
(xor b (not t)))
(println '(t s m b c))
(println row))))
这篇关于在 Racket 中解决难题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!