Call/cc and linear update procedures Bradley Lucier (09 Jan 2024 23:49 UTC)
Re: Call/cc and linear update procedures Marc Nieper-Wißkirchen (08 Feb 2024 11:30 UTC)

Call/cc and linear update procedures Bradley Lucier 09 Jan 2024 23:49 UTC

I found the following "linear update" procedures that take procedural
arguments:

  append-map! f clist1 clist2 ... -> value
  map! f list1 clist2 ... -> list
  filter!    pred list -> list
  partition! pred list -> [list list]
  remove!    pred list -> list
  take-while! pred clist -> list
  span!  pred list  -> [list list]
  break! pred list  -> [list list]
  delete! x list [=] -> list
  delete-duplicates! list [=] -> list
  alist-delete! key alist [=] -> alist
  lset-union!             = list1 ... -> list
  lset-intersection!      = list1 list2 ... -> list
  lset-difference!        = list1 list2 ... -> list
  lset-xor!               = list1 ... -> list
  lset-diff+intersection! = list1 list2 ... -> [list list]

I looked at the implementation of filter! in the sample implementation,
which is very elegant:

(define (filter! pred lis)
   (check-arg procedure? pred filter!)
   (let lp ((ans lis))
     (cond ((null-list? ans)       ans)			; Scan looking for
	  ((not (pred (car ans))) (lp (cdr ans)))	; first cons of result.

	  ;; ANS is the eventual answer.
	  ;; SCAN-IN: (CDR PREV) = LIS and (CAR PREV) satisfies PRED.
	  ;;          Scan over a contiguous segment of the list that
	  ;;          satisfies PRED.
	  ;; SCAN-OUT: (CAR PREV) satisfies PRED. Scan over a contiguous
	  ;;           segment of the list that *doesn't* satisfy PRED.
	  ;;           When the segment ends, patch in a link from PREV
	  ;;           to the start of the next good segment, and jump to
	  ;;           SCAN-IN.
	  (else (letrec ((scan-in (lambda (prev lis)
				    (if (pair? lis)
					(if (pred (car lis))
					    (scan-in lis (cdr lis))
					    (scan-out prev (cdr lis))))))
			 (scan-out (lambda (prev lis)
				     (let lp ((lis lis))
				       (if (pair? lis)
					   (if (pred (car lis))
					       (begin (set-cdr! prev lis)
						      (scan-in lis (cdr lis)))
					       (lp (cdr lis)))
					   (set-cdr! prev lis))))))
		  (scan-in ans (cdr ans))
		  ans)))))

This sample implementation can be screwed up if pred captures and
replays its continuation.

My understanding of the term "linear update" (and I have to admit I
haven't found very many references to this term other than in SRFI 1) is
that having pred capture and replay its continuation is a violation of
the "linear update" assumption that the only pointer to the list
argument lis (and presumably all following pairs in the list, although I
don't remember whether this is stated explicitly in SRFI 1) is lis
itself, so having the pred procedure capture and replay its continuation
violates the "linear update" assumption, and a user doing such a thing
can go pound sand.

My question: Is this analysis correct?

My secondary question: Should one restrict the programming of filter! to
be the same as filter just to "save" someone who decides to use call/cc
in pred?

Brad