I'd like to write a function to remove subsets of a string by using
destructive updates internally, but then returning the new updated
version of the string, so the function still operates without any side-
effects. This is what I have right now:
(defun remove-subsets (subsets string)
(mapcar #'(lambda (sub) (setf (subseq string (car sub) (cdr sub))
""))
subsets)
string)
Unfortunately, it seems as though this function isn't having any
effect, eg:
(setf x "abcdef")
(remove-subsets (list (cons 1 2)) x) => "abcdef"
So, my question is, why are the calls to setf in remove-subsets
seemingly doing nothing? I assume it has something to do with the
fact that they're being called from within a lambda, but since the
variable string is free in the lambda, shouldn't it be modifying the
copy of the string that is available to the whole function?
Thanks for any help.
On 2009-06-27 13:50:40 +0100, Jimmy Miller <··············@gmail.com> said:
> I'd like to write a function to remove subsets of a string by using
> destructive updates internally, but then returning the new updated
> version of the string, so the function still operates without any side-
> effects. This is what I have right now:
>
> (defun remove-subsets (subsets string)
> (mapcar #'(lambda (sub) (setf (subseq string (car sub) (cdr sub))
> ""))
> subsets)
> string)
If this function worked, it would have side-effects: in particular it
would side-effect the string which is its argument, since (SETF SUBSEQ)
is defined to do that. However, if you check the specification you
will find this:
setf may be used with subseq to destructively replace elements of a
subsequence with elements taken from a sequence of new values. If the
subsequence and the new sequence are not of equal length, the shorter
length determines the number of elements that are replaced. The
remaining elements at the end of the longer sequence are not modified
in the operation.
Or in other words, since, for your function, "the shorter length" is
zero, no elements are modified.
The right approach do do what you want to do is almost certainly to cop
the bits of the string you *do* want.
On Jun 27, 9:07 am, Tim Bradshaw <····@tfeb.org> wrote:
> On 2009-06-27 13:50:40 +0100, Jimmy Miller <··············@gmail.com> said:
>
> > I'd like to write a function to remove subsets of a string by using
> > destructive updates internally, but then returning the new updated
> > version of the string, so the function still operates without any side-
> > effects. This is what I have right now:
>
> > (defun remove-subsets (subsets string)
> > (mapcar #'(lambda (sub) (setf (subseq string (car sub) (cdr sub))
> > ""))
> > subsets)
> > string)
>
> If this function worked, it would have side-effects: in particular it
> would side-effect the string which is its argument, since (SETF SUBSEQ)
> is defined to do that. However, if you check the specification you
> will find this:
>
> setf may be used with subseq to destructively replace elements of a
> subsequence with elements taken from a sequence of new values. If the
> subsequence and the new sequence are not of equal length, the shorter
> length determines the number of elements that are replaced. The
> remaining elements at the end of the longer sequence are not modified
> in the operation.
>
> Or in other words, since, for your function, "the shorter length" is
> zero, no elements are modified.
>
> The right approach do do what you want to do is almost certainly to cop
> the bits of the string you *do* want.
Well, that certainly clears things up. Thanks for the advice.
Jimmy Miller <··············@gmail.com> writes:
> I'd like to write a function to remove subsets of a string by using
> destructive updates internally, but then returning the new updated
> version of the string, so the function still operates without any side-
> effects. This is what I have right now:
> [...]
You can more easily implement this function without side-effect if you
concentrate on keeping the sub-sequence that are not to be removed.
--
__Pascal Bourguignon__