Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
247 views
in Technique[技术] by (71.8m points)

functional programming - scheme: element not removed after for-each / delete

Using the mit-scheme interpreter (v10.1.5-1), I was expecting this loop to remove each element of 'ls' except '2':

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)

Why has '1' not been removed? The result is the same using delete! or changing the order of '(0 1 5).

question from:https://stackoverflow.com/questions/65928947/scheme-element-not-removed-after-for-each-delete

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You should not do destructive operations on literal data in Scheme (emphasis mine): R5RS 3.4 Storage Model

In many systems it is desirable for constants... to reside in read-only-memory.... In such systems literal constants and the strings returned by symbol->string are immutable objects, while all objects created by the other procedures listed in this report are mutable. It is an error to attempt to store a new value into a location that is denoted by an immutable object.

But there is another fundamental problem with the posted code. The MIT Scheme Reference Manual says of the procedures delq!, delv!, and delete!:

Returns a list consisting of the top-level elements of list with all entries equal to element removed.

This does not say that the original list is modified to the desired state; it says the the procedures return a list that has been modified to the desired state. The manual goes on to suggest:

Because the result may not be eq? to list, it is desirable to do something like (set! x (delete! x)).

You may wonder why you would use a destructive operation at all when you still have to use set! anyway. The non-destructive procedures del, delv, and delete return freshly allocated copies of the original list with the appropriate removals. These allocations have a cost which the destructive operations avoid.

The posted code can be amended to avoid using a list literal and to use 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)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...