Let's do this using the same approach, "find indices and assign over them in a copy of the sequence": This is the TXR Lisp interactive listener of TXR 259.
Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
Do not operate heavy equipment or motor vehicles while using TXR.
1> (defun subst-select-* (list)
(let ((indices (where (op starts-with '(select *))
(cons nil (conses list)))))
(if indices
(let ((list (copy list)))
(set [list indices] (repeat '(_)))
list)
list)))
subst-select-*
2> (subst-select-* '(foo bar * select * fox select * bravo))
(foo bar * select _ fox select _ bravo)
(conses list) gives us a list of the list's conses: e.g in (1 2 3) the conses are (1 2 3), (2 3) and (3), so the list of them is ((1 2 3) (2 3) (3)).where applies a function to a sequence, and returns the 0-based indices of where the function yields true. (op starts-with '(select *)) yields a lambda which tests whether its argument starts with (select *). No brainer. If we naively applied that to the conses, we would get thew rong indices: the indices of the select symbols, not of the asterisks. The workaround for that is (cons nil (conses list)): we cons an extra dummy nil element to shift the positions, and process the resulting list. Once we have the indices list, if it isn't empty, we copy the original input, and assign underscore symbols into the indicated positions. To do that we generate an infinite lazy list of underscores; the assignment takes elements from this list and puts them into the specified index positions. |
But I'm not a fetishist: I didn't learn k because it was cute, and I don't wake up every day looking for ways to rewrite other people's code so that it is slower and bigger. Do you? Or is today special?
[1]: Measured in source-code bytes.