簡體   English   中英

使用相同的輔助功能使用foldr和foldl反轉列表

[英]Reverse a list with foldr and foldl using the same auxiliary functions

1. (define (rev1 ls) (foldr g '() (map f ls))) 
2. (define (rev2 ls) (foldl g '() (map f ls))) 

我需要定義fg使得兩個rev1rev2產生給定列表的反向ls如下,其中其他定義中

(define (foldl op z ls) 
   (if (null? ls) 
       z 
       (foldl op (op z (car ls)) (cdr ls))))

(define (snoc x y) (cons y x))

(define (foldr op z ls)
     (if (null? ls)
        z
        (op (car ls) (foldr op z (cdr ls)))))

我不確定如何以1和2產生與參數列表相反的方式定義fg

這是一個相當虛構的練習,但是無論如何-這些程序應該起作用:

(define f list)

(define (g e acc)
  (append acc e))

例如:

(rev1 '(1 2 3 4 5))
=> '(5 4 3 2 1)

(rev2 '(1 2 3 4 5))
=> '(5 4 3 2 1)

有趣的問題。 您可以使用遞歸思維和方程式推理(在代碼中將equals替換為equals)對其進行攻擊。

首先,重新編寫:

(rev1 ls) 
 = (letrec ( (rev1 (lambda (ls)
                     (foldr g '() (map f ls)) )) ) 
     (rev1 ls))

 = (letrec ( (rev1 (lambda (ls)
                     (foldr g '() (map f ls)) )) ) 
     (foldr g '() (map f ls)))

 = (letrec ( (rev1  (lambda (ls)
                      (foldr g '() (map f ls)) )) 
             (foldr (lambda (op z ls)
                     (if (null? ls)
                       z
                       (op (car ls) (foldr op z (cdr ls)))) )) ) 
     (foldr g '() (map f ls)))

 = (letrec ( (foldr (lambda (op z ls)
                     (if (null? ls)
                       z
                       (op (car ls) (foldr op z (cdr ls)))) ))
             (rev11 (lambda (ls)
                      (if (null? ls)
                        '()
                        (g (f (car ls)) (foldr g '() (map f (cdr ls))))) )) ) 
     (rev11 ls))

 = (letrec ( (rev11 (lambda (ls)
                      (if (null? ls)
                        '()
                        (g (f (car ls)) (rev11 (cdr ls)))) )) ) 
     (rev11 ls))

因為(map f (cons x xs)) == (cons (fx) (map f xs))

同樣,

(rev2 ls)
 = (letrec ( (rev2 (lambda (ls)
                     (foldl g '() (map f ls)) )) )
     (rev2 ls))

 = (letrec ( (rev2  (lambda (ls)
                      (foldl g '() (map f ls)) ))
             (foldl (lambda (op z ls) 
                      (if (null? ls) 
                        z 
                        (foldl op (op z (car ls)) (cdr ls))) )) )
     (foldl g '() (map f ls)))

 = (letrec ( (rev22 (lambda (z ls) 
                      (if (null? ls) 
                        z 
                        (rev22 (g z (f (car ls))) (cdr ls))) )) )
     (rev22 '() ls))

(請完成第二個推導中缺少的步驟)。

因此,我們得出了新的定義

(define (rev11 ls)    (if (null? ls)    ; (rev1 ls) == (rev11 ls)
                        '()
                        (g (f (car ls)) (rev11 (cdr ls)))) )

(define (rev22 z ls)  (if (null? ls)    ; (rev2 ls) == (rev22 '() ls)
                        z 
                        (rev22 (g z (f (car ls))) (cdr ls))) )

現在我們可以應用一些遞歸思維。 只需假設rev11完成應做的工作即可–反轉給出的列表。 因此,對於列表ls == [a,b,c,...,n]

(rev1 ls)
  = (rev11 ls)
  = (rev11 [a,b,c,...,n])
  = (g (f a) (rev11 [b,c,...,n]))
  = (g (f a) [n,...,c,b])    ; by assumption
  ; must be equal to
  = [n,...,c,b,a]

我們如何結合a和列表xs得到一個新的,一樣xsa在其結束?

  = (append [n,...,c,b] (list a))

因此, f == list(gxy) == (append yx) 我們已經得出了ÓscarLópez答案中的定義!

現在我們必須看看rev22發生了rev22 如果它的fg不同,則表示原始問題無解。

(rev2 ls)
= (rev22 '() ls)
= (rev22 '() [a,b,c,...,n])
= (rev22 (g '() (f a)) [b,c,...,n])
= (rev22 (g (g '() (f a)) (f b)) [c,...,n])
= ...

顯而易見,相同的fg在這里也起作用。

巧合的是, rev22等效於append-reverseCommon Lisp的revappend ,具有倒置的參數順序。

編寫這兩個定義的另一種偽編碼方式是,其中[]代表'(){x}代表(fx)x + y代表(gxy)

(rev1 [a,b,...,n]) = {a} + ({b} + ({c} + (... + ({n} + [])...)))
                   = {a} + (rev1 [b,...,n])

(rev2 [a,...,m,n]) = (...((([] + {a}) + {b}) + {c}) + ...) + {n}
                   = (rev2 [a,...,m]) + {n}

現在解決方案似乎不言而喻!

請注意,您的foldl定義對g運算符使用Haskell的參數順序。 在Racket中 ,順序被翻轉z作為最后一個參數而不是first出現 因此,方程將變為

(rev1 [a,b,...,n]) = {a} + (rev1 [b,...,n])
(rev2 [a,...,m,n]) = {n} + (rev2 [a,...,m])

對於第二個等式+ == g == append而不翻轉參數順序。 然后,修改后的難題似乎無法解決。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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