簡體   English   中英

我將如何在 Dr. Racket 中編寫一個 function,它使用 2 個可能的符號列表並將它們替換為其他符號?

[英]How would I write a function in Dr. Racket which consumes a list of 2 possible symbols and replaces them with something else?

我如何在 Dr. Racket 中編寫一個 function,它使用 2 個可能的符號列表('c 或 'v)並將它們替換為其他符號? 如果符號是 'c,那么它會被替換為 'c 'v 如果符號是 'v,那么它會被替換為 'v 'c

到目前為止,這是我的代碼:

(define (awesome c)
  (cond
    [(equal? c 'c) (list 'c 'v)]  
    [else (list 'v 'c)]))

(define (substitute los)
  (map awesome los))

如果我輸入:

(substitute (list 'c 'v 'c 'c))

我想要的 output 是

(list 'c 'v 'v 'c 'c 'v 'c 'v)

相反,我得到:

(list (list 'c 'v) (list 'v 'c) (list 'c 'v) (list 'c 'v))

為什么會這樣? 如何更正我的代碼以獲得正確的 output? 謝謝。

一個簡單的解決方案

輸入中的每個符號都生成 output 中兩個符號的列表。使用append組合列表,例如:

scratch.rkt> (append '(c v) '(v c) '(c v) '(c v))
'(c v v c c v c v)

由於map正在創建一個包含子列表的列表,請使用applyappend應用於子列表:

(define (substitute los)
  (apply append (map awesome los)))

示例交互:

scratch.rkt> (substitute (list 'c 'v 'c 'c))
'(c v v c c v c v)

增加一些靈活性

您可以通過使用術語重寫規則列表來采取更靈活的方法。 這將允許您在不更改代碼的情況下更改替換規則。 術語重寫規則可以表示為列表的列表,用箭頭將輸入術語與重寫分開:

(define cv-rules '((c -> c v)
                   (v -> v c)))

定義幾個函數來獲取術語的規則和規則的重寫列表很有用。 將這些操作抽象為函數使得以后更改規則的表示更容易,並有助於保持代碼清晰:

(define (get-rule term rules)
  (assoc term rules))

(define (get-rewrites rule)
  (cddr rule))

這個get-rewrites rewrites function 可以用在另一個 function 中,它根據規則重寫一個術語。 在這里,任何沒有特定規則的符號僅在列表中單獨返回:

(define (rewrite-term x rules)
  (let ((rule (get-rule x rules)))
    (if rule
        (get-rewrites rule)
        (list x))))

現在可以將rewrite-term function 與重寫規則一起映射到輸入上。 和以前一樣,映射結果是一個子列表列表,因此在返回之前將append應用於結果:

(define (rewrite terms rules)
  (apply append (map (lambda (x) (rewrite-term x rules)) terms)))

現在,您可以通過定義一組新的重寫規則輕松更改替換的方式。

示例交互:

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)

遞歸重寫

通過對rewrite-term function 的小改動,您可以將重寫規則遞歸地應用於嵌套的術語列表。 當要重寫的術語本身是一個沒有重寫規則的非空列表時,將對該術語調用rewrite 請注意,所有重寫在返回之前都包含在列表中。 這個新的 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)))))

示例交互:

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)))

你的方法很好。 您所要做的就是將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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM