方案,有人可以解释我是如何使用set-car的!错误?

时间:2017-05-14 12:59:13

标签: scheme

我想制作一个程序,破坏性地增加列表的奇数。我以为我会通过它来解决问题而只是使用'定车'!每当'奇怪?'是真的。

以下是代码:

+--------------+-----------+--------------+------------+
| Code_Project | Code_Name | Project_Name | GrandTotal |
+--------------+-----------+--------------+------------+
| 17-0004      | A         | ABC          |       3700 |
| 17-0004      | B         | DEF          |       1600 |
+--------------+-----------+--------------+------------+

我不确定为什么它不起作用,我想我不懂套装车!和set-cdr! 有人能解释一下吗谢谢。

3 个答案:

答案 0 :(得分:1)

问题可能在于您的口译员,或者您定义程序的语言,或者您调用它的方式。例如,在DrRacket中,这很好用:

#lang r5rs

(define (test lst)
  (cond ((null? lst) lst) ; this is the '() returned by the recursion
        ((odd? (car lst)) (set-car! lst (+ (car lst) 1))
                          (test (cdr lst)))
        (else (test (cdr lst)))))

请记住,您的过程将返回空列表,因为这是递归的基本情况,这是一个尾递归过程,它返回基数的值案件作为最终结果。但不要担心,输入列表已就地修改,您可以在过程返回其值后进行检查。

(define lst (list 1 2 3 4))
(display (test lst))
=> ()
(display lst)
=> (2 2 4 4)

看看可变性如何令人困惑?一个过程返回一个值,但其输入已被修改并且现在具有不同的值。这是函数式编程(有利于不可变数据)更简洁易懂的原因之一,也说明了为什么在过程中改变输入参数是个坏主意;)

如果您绝对希望该过程返回变异列表,请按@ sepp2k建议,但请记住 - 输入列表修改,实际上,与结果返回的列表相同:

(define (test lst)
  (cond ((null? lst) lst)
        ((odd? (car lst)) (set-car! lst (+ (car lst) 1))
                          (test (cdr lst))
                          lst) ; add this line
        (else (test (cdr lst)))))

亲眼看看:

(define lst (list 1 2 3 4))
(display (test lst))
=> (2 2 4 4)
(display lst)
=> (2 2 4 4)

答案 1 :(得分:1)

  

期待包含(2 2 4 4)的列表返回

您定义函数的方式,它将在空列表上调用时返回空列表,并在所有其他情况下返回递归结果。因此,由于唯一的基本情况是空列表,因此您将始终返回空列表。

如果要返回修改后的列表,则需要在递归后执行此操作。这是在(test (cdr lst))之后,添加lst以返回lst的值。

答案 2 :(得分:1)

您使用set-car!正确无误。以下是您告诉它的工作原理:

(define (test lst)
  (cond ((null? lst) lst)
        ((odd? (car lst)) (set-car! lst (+ (car lst) 1))
                          (test (cdr lst)))
        (else (test (cdr lst)))))

(define test-list (list 1 2 3 4))
(test test-list)
test-list ; ==> (2 2 4 4)

您希望函数返回修改后的列表是错误的。要做到这一点,您需要第一个递归步骤来返回参数。你需要把它包起来:

(define (inc-odds lst)
  (define (test lst)
    (cond ((null? lst) lst)
          ((odd? (car lst)) (set-car! lst (+ (car lst) 1))
                            (test (cdr lst)))
          (else (test (cdr lst)))))
  (inc-odds lst) ; do the stuff
  lst)           ; return the list

(inc-odds (list 1 2 3 4)) ; ==> (2 2 4 4)
(inc-odds '(1 2 3 4)) ; ==> "pigs flying"

注意最后一个。在RNRS up到R5RS中,将引用的文字传递给set-car!会产生一个未定义的行为,这意味着任何事情都可以,因为从技术上讲,代码不是Scheme。在R6RS中,需要提出异常。