[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

subst-if-not and nsubst-if-not, programming folk-lore



These are really neat functions, and counterintuitive to boot.  One of
our documentation people tried this:

    (let* ((item-list '(numbers (1.0 2 5/3) symbols (foo bar)))
	   (new (subst-if '3.1415 #'numberp item-list)))
      (values new item-list))
    => (NUMBERS (3.1415 3.1415 3.1415) SYMBOLS (FOO BAR))
       (NUMBERS (1.0 2 5/3) SYMBOLS (FOO BAR))

which is correct, numbers were substituted.  Similarly, nsubst-if works
as expected:

    (let* ((item-list '(numbers (1.0 2 5/3) symbols (foo bar)))
	   (new (nsubst-if '3.1415 #'numberp item-list)))
      (values new item-list))
    => (NUMBERS (3.1415 3.1415 3.1415) SYMBOLS (FOO BAR))
       (NUMBERS (3.1415 3.1415 3.1415) SYMBOLS (FOO BAR))

Now, when one tries subst-if-not, one gets a small surprise until one
thinks about it a bit:

    (let* ((item-list '(numbers (1.0 2 5/3) symbols (foo bar)))
	   (new (subst-if-not '3.1415 #'numberp item-list)))
      (values new item-list))
    => 3.1415
       (NUMBERS (1.0 2 5/3) SYMBOLS (FOO BAR))

and nsubst-if-not gives the same thing

    (let* ((item-list '(numbers (1.0 2 5/3) symbols (foo bar)))
	   (new (nsubst-if-not '3.1415 #'numberp item-list)))
      (values new item-list))
    => 3.1415
       (NUMBERS (1.0 2 5/3) SYMBOLS (FOO BAR))

, i.e., the list is NOT destructed.  A careful reading explains why: the
item-list is indeed not a number, and therefore it gets substituted (but
you can't substitute the entire list, so you don't modify it).

What the person probably wanted is to replace the non-null atomic
leafs.  I'm not sure what to think.  One thing I'm thinking is that
(n)subst-if-not is too counter-intuitive to be worth having in the
language, even for completeness.  At the very list, I think the
book/manual should carefully discuss this issue to people don't get
confused for years.