我想制作一个正方形列表。我可以使用以下代码来完成:
(define (makelistsq n)
(define outlist '())
(for ((i n))
(set! outlist (append outlist (list (* i i))))
)
outlist
)
(makelistsq 5)
输出:
'(0 1 4 9 16)
但是,我已经看到,通常使用cons和car关键字来创建和添加列表。这种方法是否比上述附加方法有任何优势?因此,遵循更好或与上述相同:
(define (makelistsq2 n)
(define outlist '())
(for ((i n))
(set! outlist (cons (* i i) outlist))
)
(reverse outlist)
)
感谢您的回答/评论。
编辑:在此页Cons element to list vs cons list to element in Scheme上提到所有使用追加都是错误的:
在极少数情况下,您需要在最后添加一个元素 (并且相信我,这样做通常意味着你在想 算法错误)你可以使用追加
答案 0 :(得分:4)
我不会重复我自己的回答:P。是的,使用append
通常是构建输出列表的错误方法。但是你的实现都不正确 - 大多数时候,你必须忘记set!
和循环。
递归是最佳选择,最后使用cons
和(如果需要)reverse
是构建列表的首选方法。实际上,使用内置过程可以更简洁地表达问题中的函数,这是编写函数式代码时的推荐方法:
(define (makelistsq2 n)
(map (lambda (x) (* x x))
(range n)))
为了完整起见,让我们看看我们如何从头开始编写程序,使用cons
来构建输出 - 适用于没有内置过程可以满足您需要的极少数情况。这会生成一个递归过程,请注意,我们从零到n-1
:
(define (makelistsq2 n)
(define (helper i)
(if (= i n)
'()
(cons (* i i)
(helper (add1 i)))))
(helper 0))
上述解决方案很好,适用于小型列表。如果(且仅当)输出列表很大,您可能希望使用尾递归来构建它;这样更有效,因为它不需要额外的内存来进行迭代 - 我们将使用一个名为let
,并注意这会产生一个迭代过程,从n-1
变为零:
(define (makelistsq2 n)
(let loop ((i (sub1 n)) (acc '()))
(if (negative? i)
acc
(loop (sub1 i) (cons (* i i) acc)))))
无论您选择哪种实施方式,结果现在都符合预期:
(makelistsq2 5)
=> '(0 1 4 9 16)
答案 1 :(得分:2)
cons
是一对的构造函数。列表不是由空列表cons
终止的()
链以外的其他任何内容。
append
是一个在实现中使用cons
的函数。以下是两个参数append的实现:
(define (append lst1 lst2)
(if (null? lst1)
lst2
(cons (car lst1)
(append (cdr lst1) lst2))))
简单地说,它为每对lst1
创建一对新对,然后附加lst2。它不是非常有效,所以在你的第一个例子中,除了为每个步骤明确指定的一个元素列表之外,它还必须创建一个4,3和2个元素列表。
使用列表时,它按照从头到尾的顺序进行迭代,但列表的创建从头到尾进行。通常它不可能反过来做某事,因此最终需要反转结果,但在你的情况下,它很容易倒计时而不是向上。
(define (make-square-list end)
(let loop ((n (sub1 end)) (acc '()))
(if (< n 0)
acc
(loop (sub1 n)
(cons (* n n) acc)))))
使用更高阶函数可以消除样板,但#!racket
有一个替代方案可以使更短的代码称为for/list
。
(define (make-square-list end)
(for/list ((n (range end)))
(* n n)))
for/list
与map
基本相同,但作为一种特殊形式。
答案 2 :(得分:0)
我的版本:
#lang racket
(define (make-square-list n)
(let loop ([count 1]
[result_list '()])
(if (<= count n)
(loop (add1 count) (cons (* count count) result_list))
(reverse result_list))))
(make-squqre-list 10)
(1 4 9 16 25 36 49 64 81 100)