[英]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)))
我需要定義f
和g
使得兩個rev1
和rev2
產生給定列表的反向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產生與參數列表相反的方式定義f
和g
。
這是一個相當虛構的練習,但是無論如何-這些程序應該起作用:
(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
得到一個新的,一樣xs
與a
在其結束?
= (append [n,...,c,b] (list a))
因此, f == list
和(gxy) == (append yx)
。 我們已經得出了ÓscarLópez答案中的定義!
現在我們必須看看rev22
發生了rev22
。 如果它的f
和g
不同,則表示原始問題無解。
(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])
= ...
顯而易見,相同的f
和g
在這里也起作用。
巧合的是, rev22
等效於append-reverse
或Common 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.