【问题标题】:scheme: element not removed after for-each / delete方案:for-each / delete 后未删除元素
【发布时间】:2021-01-27 23:31:32
【问题描述】:

使用 mit-scheme 解释器 (v10.1.5-1), 我期待这个循环删除除 '2' 之外的 'ls' 的每个元素:

3 error> (define ls '(1 2 0 5))
;Value: ls
3 error> (for-each (lambda (n) (delq! n ls)) '(0 1 5))
;Unspecified return value
3 error> ls
;Value: (1 2)

为什么“1”没有被删除? 使用删除的结果是一样的!或更改 '(0 1 5) 的顺序。

【问题讨论】:

  • @ÓscarLópez 被迭代的列表与正在修改的列表不同。

标签: functional-programming scheme side-effects


【解决方案1】:

据此,不允许修改文字数据。 R7RS-small (PDF) 中的第 31 页:

由于修改常量对象(由文字表达式返回的对象)是错误的,因此实现可以在适当的情况下在常量之间共享结构。因此 eqv 的值? on 常量有时取决于实现。

MIT Scheme 是一个 R5RS,但是这部分没有改变。唯一改变的是,虽然 R7RS 应该失败,但 R5RS 实现可以做任何事情作为公认的解决方案,因为代码不被认为是 Scheme 开始的。因此这也是可以接受的场景:

(定义 ls '(1 2 0 5)) (for-each (lambda (n) (delq!n ls)) '(0 1 5)) ls ; ==> “BaNaNa!”

但是我知道大多数 Scheme 实现都会改变数据,并产生后果。例如。这是极有可能的情况:

(define two '(1 2))
(define test '(3 4 1 2))

(set-car! two 9)
two  ; ==> (9 2)
test ; ==> (3 4 9 2) 

因为它是字面量实现允许共享结构。

delq! 以良好的 MIT 方案风格返回结果。这样,如果第一个元素是要删除的元素,它将具有要反弹的对象。

(define ls (list 1 2 0 5))
(for-each (lambda (n) (set! ls (delq! n ls))) '(0 1 5))
ls ; ==> (2)

对于不是第一个被删除的每个元素,它返回与以前相同的值,但是在您删除第一个元素 1 的一次迭代中,没有办法绕过第一个元素,因为绑定点在需要去的那对。

【讨论】:

    【解决方案2】:

    您不应该对 Scheme 中的文字数据进行破坏性操作(强调我的):R5RS 3.4 Storage Model

    在许多系统中,希望常量...驻留在 只读内存.... 在这样的系统中,文字常量和字符串 symbol->string 返回的是不可变对象,而所有对象 由本报告中列出的其他程序创建是可变的。 它 尝试将新值存储到一个位置是错误的 由不可变对象表示。

    但是发布的代码还有另一个根本问题。 MIT 方案参考手册提到了 delq!delv!delete! 的过程:

    返回由 list 的顶级元素组成的列表,所有 等于 element 的条目已删除。

    不是说原始列表被修改为所需的状态;它说程序返回一个已修改为所需状态的列表。手册继续建议:

    因为list的结果可能不是eq?,所以最好这样做 类似(set! x (delete! x))

    您可能想知道,当您仍然必须使用set! 时,为什么还要使用破坏性操作。无损程序deldelvdelete 返回原始列表的新分配副本以及适当的删除。这些分配具有破坏性操作避免的成本。

    可以修改发布的代码以避免使用列表文字并使用set!

    1 ]=> (define ls (list 1 2 0 5))
    
    ;Value: ls
    
    1 ]=> ls
    
    ;Value: (1 2 0 5)
    
    1 ]=> (for-each (lambda (n) (set! ls (delq! n ls))) '(0 1 5))
    
    ;Unspecified return value
    
    1 ]=> ls
    
    ;Value: (2)
    

    【讨论】:

      猜你喜欢
      • 2011-06-27
      • 2020-09-02
      • 2018-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-14
      相关资源
      最近更新 更多