[英]How would I write a function in Dr. Racket which consumes a list of 2 possible symbols and replaces them with something else?
How would I write a function in Dr. Racket which consumes a list of 2 possible symbols ('c or 'v) and replaces them with something else?我如何在 Dr. Racket 中编写一个 function,它使用 2 个可能的符号列表('c 或 'v)并将它们替换为其他符号? If the symbol is 'c, then it gets replaced with 'c 'v If the symbol is 'v, then it gets replaced with 'v 'c
如果符号是 'c,那么它会被替换为 'c 'v 如果符号是 'v,那么它会被替换为 'v 'c
Here is my code so far:到目前为止,这是我的代码:
(define (awesome c)
(cond
[(equal? c 'c) (list 'c 'v)]
[else (list 'v 'c)]))
(define (substitute los)
(map awesome los))
If I type in:如果我输入:
(substitute (list 'c 'v 'c 'c))
My desired output is我想要的 output 是
(list 'c 'v 'v 'c 'c 'v 'c 'v)
Instead, I get:相反,我得到:
(list (list 'c 'v) (list 'v 'c) (list 'c 'v) (list 'c 'v))
Why is this happening?为什么会这样? How can I correct my code to achieve the correct output?
如何更正我的代码以获得正确的 output? Thanks.
谢谢。
Each symbol in the input is generating a list of two symbols in the output. Use append
to combine the lists, eg:输入中的每个符号都生成 output 中两个符号的列表。使用
append
组合列表,例如:
scratch.rkt> (append '(c v) '(v c) '(c v) '(c v))
'(c v v c c v c v)
Since map
is creating a list that contains sublists, use apply
to apply append
to the sublists:由于
map
正在创建一个包含子列表的列表,请使用apply
将append
应用于子列表:
(define (substitute los)
(apply append (map awesome los)))
Sample interaction:示例交互:
scratch.rkt> (substitute (list 'c 'v 'c 'c))
'(c v v c c v c v)
You could take a more flexible approach by using a list of term rewriting rules.您可以通过使用术语重写规则列表来采取更灵活的方法。 This would allow you to change the substitution rules without changing your code.
这将允许您在不更改代码的情况下更改替换规则。 The term rewriting rules could be represented as a list of lists, with an arrow separating the input term from the rewrites:
术语重写规则可以表示为列表的列表,用箭头将输入术语与重写分开:
(define cv-rules '((c -> c v)
(v -> v c)))
It is useful to define a couple of functions that get the rule for a term and a list of rewrites from a rule.定义几个函数来获取术语的规则和规则的重写列表很有用。 Abstracting these operations to functions makes it easier to change the representation of a rule later, and helps keep the code clear:
将这些操作抽象为函数使得以后更改规则的表示更容易,并有助于保持代码清晰:
(define (get-rule term rules)
(assoc term rules))
(define (get-rewrites rule)
(cddr rule))
This get-rewrites
function can be used in another function that rewrites a term based on the rules.这个
get-rewrites
rewrites function 可以用在另一个 function 中,它根据规则重写一个术语。 Here, any symbol which does not have a specific rule is just returned in a list by itself:在这里,任何没有特定规则的符号仅在列表中单独返回:
(define (rewrite-term x rules)
(let ((rule (get-rule x rules)))
(if rule
(get-rewrites rule)
(list x))))
Now the rewrite-term
function can be mapped over the input, together with rewrite rules.现在可以将
rewrite-term
function 与重写规则一起映射到输入上。 As before, the mapping results in a list of sublists, so append
is applied to the result before returning:和以前一样,映射结果是一个子列表列表,因此在返回之前将
append
应用于结果:
(define (rewrite terms rules)
(apply append (map (lambda (x) (rewrite-term x rules)) terms)))
Now you can easily change the way that substitutions are made by defining a new set of rewrite rules.现在,您可以通过定义一组新的重写规则轻松更改替换的方式。
Sample interactions:示例交互:
scratch.rkt> (rewrite '(c v c c) cv-rules)
'(c v v c c v c v)
scratch.rkt> (rewrite '(c v c x c) cv-rules)
'(c v v c c v x c v)
With a small change to the rewrite-term
function, you can apply the rewrite rules recursively to nested lists of terms.通过对
rewrite-term
function 的小改动,您可以将重写规则递归地应用于嵌套的术语列表。 When the term to rewrite is itself a nonempty list with no rewrite rule, rewrite
is called on that term.当要重写的术语本身是一个没有重写规则的非空列表时,将对该术语调用
rewrite
。 Note that all rewrites are wrapped in lists before being returned.请注意,所有重写在返回之前都包含在列表中。 This new function behaves as before for the original rules, but allows more complex rules, too:
这个新的 function 对于原始规则的行为与以前一样,但也允许更复杂的规则:
(define (rewrite-term x rules)
(let ((rule (get-rule x rules)))
(cond (rule (get-rewrites rule))
((pair? x) (list (rewrite x rules)))
(else
(list x)))))
Sample interactions:示例交互:
scratch.rkt> (define cv2-rules '((c -> v)
(v -> (c v))))
scratch.rkt> (rewrite '(c v c c) cv2-rules)
'(v (c v) v v)
scratch.rkt> (rewrite '(v (c v) v v) cv2-rules)
'((c v) (v (c v)) (c v) (c v))
scratch.rkt> (rewrite '((c v) (v (c v)) (c v) (c v)) cv2-rules)
'((v (c v)) ((c v) (v (c v))) (v (c v)) (v (c v)))
You approach was quite good.你的方法很好。 All you have to do is to replace
map
by append-map
.您所要做的就是将
map
替换为append-map
。
(define (awesome c)
(cond ((equal? c 'c) (list 'c 'v))
((equal? c 'v) (list 'v 'c))))
(define (substitute los)
(append-map awesome los))
(substitute (list 'c 'v 'c 'c))
;; '(c v v c c v c v)
;; desired: (list 'c 'v 'v 'c 'c' 'v 'c 'v)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.