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)))))
我不确定如何定义f
和g
,以便1和2都生成参数列表的反向。
答案 0 :(得分:0)
这是一个相当人为的练习,但无论如何 - 这些程序应该有效:
(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)
答案 1 :(得分:0)
有趣的问题。你可以用递归思维和等式推理来攻击它(在代码中用等于等于等号)。
首先,重写:
(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 (f x) (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
的{{1}}结尾相同?
a
因此 = (append [n,...,c,b] (list a))
和f == list
。我们已经达到了Óscar López's answer中所见的定义!
现在我们必须看看(g x y) == (append y x)
发生了什么。如果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
相当于append-reverse
或Common Lisp's revappend
,具有翻转的参数顺序。
编写这两个定义的另一种更多伪编码方式,其中rev22
代表[]
,'()
代表{x}
和{{1} } (f x)
,是
x + y
现在解决方案似乎几乎是不言而喻的!
请注意,您的(g x y)
定义使用了(rev1 [a,b,...,n]) = {a} + ({b} + ({c} + (... + ({n} + [])...)))
= {a} + (rev1 [b,...,n])
(rev2 [a,...,m,n]) = (...((([] + {a}) + {b}) + {c}) + ...) + {n}
= (rev2 [a,...,m]) + {n}
运算符的Haskell's个参数顺序。 In Racket订单被翻转 - foldl
作为 last 参数,而不是 first 。因此,方程将成为
g
并且没有翻转参数顺序的第二个等式z
。然后修改后的拼图似乎无法解决。