您好我正在学习Scheme new。我有疑问。让我们认为我已经定义了一个函数,如果它是空的,它会将元素添加到列表中。如果列表中有一个元素,则将新元素作为第二列添加到列表中去像这样。例如
>(add a) ; here list is empty
'(a)
>(add b) ; here a is in the list
'(a b)
>(add c) ; here a and b is in the list
(a b c)
列表是这样更新的。如何编写这样的函数。我每次使用我的代码都将元素添加到空列表中。我的意思就像我的那样。
>(add a)
'(a)
>(add b)
'(b)
>(add c)
'(c)
如何为此目的编写正确的代码? 这是我的代码
#lang racket
(define addToList
(lambda (a b)
(cond ((null? a) b)
((null? b) a)
((cons (car a) (addToList (cdr a) b))))))
(addToList '(1 2 3) '())
答案 0 :(得分:1)
就像任何其他语言一样,有两种方法可以改变一个值。您可以改变变量指向的内容(绑定),也可以通过更改对象的某些部分来改变目标对象。最后一个要求对象不是原始对象。
使用变量绑定:
#!r6rs
(import (rnrs))
(define lst '())
(define (add element)
(set! lst (append lst (list element))) ; adding to front is much cheaper
lst)
使用变异:
#!r6rs
(import (rnrs)
(rnrs mutable-pairs))
(define lst (list 'head))
(define tail lst) ; keep the last cons so we can add O(1)
(define (add element)
(set-cdr! tail (list element))
(set! tail (cdr tail))
(cdr lst))
你的程序看起来更像是功能类,因为它实际上并没有改变任何东西,但是如果你保留了你得到的结果并且修复了它没有扩展列表而是将元素添加到尾部作为点缀的事实它会工作名单。
(define addToList
(lambda (a b)
(cond ((null? a) (list b)) ; result needs to be a list
((null? b) a)
((cons (car a) (addToList (cdr a) b))))))
(define lst '())
(set! lst (addToList lst 1))
(set! lst (addToList lst 2))
(set! lst (addToList lst 3))
lst ; ==> (1 2 3)
我会这样写它让它看起来更像是scheme:
(define (add-to-end lst e)
(if (null? lst)
(list e)
(cons (car lst)
(add-to-end (cdr lst) e)))))
当然,添加到前面的便宜得多,并且使用普通的cons
。如果添加一些元素并且实际上想要将其添加到最后,则在添加元素后通过反转列表来获得相同的效果。
答案 1 :(得分:0)
你不能添加"在任何Lisp方言中的空列表,因为在所有Lisp方言中,空列表是一个特殊的,不可变的值。
在Racket中,不仅空列表是不可变的,而且所有列表也是如此。操纵列表的代码需要写入" functional"风格工作正常。
"添加"在add
函数意义上的列表意味着创建一个包含一个元素的全新列表,然后将其绑定到与以前相同的变量:
;;; This implementation of add would behave just like
;;; the examples at the top of your question.
(define add
(let ((the-list '()))
(lambda (new-item)
(set! the-list
(append the-list (list new-item)))
the-list)))
上面的函数运行得越慢the-list
越长,因为它必须
在添加新元素之前复制每个元素。添加到列表的开头而不是结尾更快:
(define add
(let ((the-list '()))
(lambda (new-item)
(set! the-list
(cons new-item the-list))
the-list)))
出于这个原因,大多数球拍程序都会向后构建他们的列表
尽可能晚地使用reverse
来创建列表的正向版本。