Hi everyone,
I have a question about programming style. Before Lisp, I used R, where
almost all arguments to a function are deeply copied, eg
> f <- function(a) {
+ a[2] <- 9
+ a
+ }
> a1 <- 1:3
> a1
[1] 1 2 3
> f(a1)
[1] 1 9 3
> a1
[1] 1 2 3
Initially, I tried to imitate this in Lisp, and wrote my programs with
the following "contract" in mind: a function that uses a non-atomic
argument has to copy it.
For example, think about a function that calculates a (univariate) spline
at arbitrary real numbers, where this function is returned by another
function and the information about the spline (the polynomials) is
captured in an array, which is in the closure. Skeleton code:
(defun make-spline-function (knots polynomials)
;; [check knots and polynomials]
(let ((knots (array-copy knots))
(polynomials (array-copy polynomials)))
(lambda (x)
;; [calculate spline at x]
)))
The assumption here is that I need to copy, because the user may make
changes to knots and polynomials after make-spline-function is called,
which can lead to a mess. For example, knots may not be weakly
increasing anymore, so the function inside would need to check for that
each time.
Now I am drifting towards the opposite style, where I do not make copies:
the assumption is that whoever calls the function should not mess with
the arrays afterwards. If the user needs to change the structure, he
should make a copy and change that.
I think that both styles can be consistent. The latter seems elegant,
but less "secure". OTOH, when I write this code as a library, I guess I
can just document the fact that arrays are not copied and the user should
act accordingly.
Which style is more "natural" in Lisp? What do you use?
Do you worry about "consistency checks" because the data structures that
are not copied could have changed since when they were captured?
Thanks,
Tamas
On Aug 24, 10:09 am, Tamas K Papp <······@gmail.com> wrote:
> Hi everyone,
>
> I have a question about programming style. Before Lisp, I used R, where
> almost all arguments to a function are deeply copied, eg
>
> > f <- function(a) {
>
> + a[2] <- 9
> + a
> + }> a1 <- 1:3
> > a1
> [1] 1 2 3
> > f(a1)
> [1] 1 9 3
> > a1
>
> [1] 1 2 3
>
> Initially, I tried to imitate this in Lisp, and wrote my programs with
> the following "contract" in mind: a function that uses a non-atomic
> argument has to copy it.
This is why I wrote my functional collections library FSet. See:
http://common-lisp.net/project/fset/
FSet gives you the functional semantics you want with the efficiency
you need.
* (defun f (a) (setf (@ a 1) 9) a)
F
* (setq a1 (seq 1 2 3))
#[1 2 3]
* (f a1)
#[1 9 3]
* a1
#[1 2 3]
To be honest, I don't think anyone is using FSet but me. I know, it
could use more and better documentation -- though what's there is
already well beyond what most open-source projects have. But I have
other things to work on, and it's just not clear how many users FSet
could attract even if I wrote reams more about it.
Besides, with no feedback it's hard to know what aspects the docs need
to explain better.
The lack of enthusiasm is certainly understandable -- Lisp already has
several kinds of collection primitives, and of them, lists can even be
used functionally (though it sometimes takes a little effort and isn't
efficient for large collections). It's hard to explain the benefits
of efficient functional collections against that background.
But the benefits of FSet go beyond the functional semantics. Where CL
just gives you the bare data structures and lets you use them as you
wish, FSet collections are semantically loaded -- sets and sequences,
for instance, are different types and support different operations.
This allows code using them to be written more abstractly, and thus
more elegantly.
Well, that's my opinion, anyway. I hope you'll give it a try. I'd
love to hear what you think about it, whether you wind up using it or
not.
-- Scott
Scott Burson wrote:
> But the benefits of FSet go beyond the functional semantics. Where CL
> just gives you the bare data structures and lets you use them as you
> wish, FSet collections are semantically loaded -- sets and sequences,
> for instance, are different types and support different operations.
> This allows code using them to be written more abstractly, and thus
> more elegantly.
Is there a comparison between FSet and cl-containers?
Thanks,
Daniel
On Aug 24, 8:10 pm, D Herring <········@at.tentpost.dot.com> wrote:
> Scott Burson wrote:
> > But the benefits of FSet go beyond the functional semantics. Where CL
> > just gives you the bare data structures and lets you use them as you
> > wish, FSet collections are semantically loaded -- sets and sequences,
> > for instance, are different types and support different operations.
> > This allows code using them to be written more abstractly, and thus
> > more elegantly.
>
> Is there a comparison between FSet and cl-containers?
I don't have a detailed comparison, but I can see right off that the
cl-containers classes have imperative semantics. It appears
furthermore that the projects have rather different design goals. CL-
containers gives you ways to make certain kinds of imperative
algorithms more efficient, and (perhaps secondarily) easier to write.
FSet's goal, on the other hand, is to make it easier (and efficient
_enough_) to write programs in a more functional and more abstract
style, which will be more elegant and thus easier to write and
understand.
Also, it appears that the emphasis of cl-containers is to provide a
broad choice of data structures, where FSet is more about providing a
rich interface to each of four fundamental types: sets, bags, seqs
(sequences), and maps.
So don't think of FSet primarily as a way to make your code faster.
Think of it as enabling you to write in a functional style, at least
where collection operations are concerned.
-- Scott
Scott Burson <········@gmail.com> writes:
> To be honest, I don't think anyone is using FSet but me. I know, it
> could use more and better documentation -- though what's there is
> already well beyond what most open-source projects have. But I have
> other things to work on, and it's just not clear how many users FSet
> could attract even if I wrote reams more about it.
(and remembering Kenny complaining about the lack of Cell followers).
So it would seem the problem of Lisp is not so much the lack of
libraries than the lack of library users...
--
__Pascal Bourguignon__ http://www.informatimago.com/
"Klingon function calls do not have "parameters" -- they have
"arguments" and they ALWAYS WIN THEM."
Scott Burson <········@gmail.com> writes:
> To be honest, I don't think anyone is using FSet but me. I know, it
> could use more and better documentation -- though what's there is
> already well beyond what most open-source projects have. But I have
> other things to work on, and it's just not clear how many users FSet
> could attract even if I wrote reams more about it.
Well, I tried to use it. Found a couple of bugs, but no way of
reporting bugs. I gave up on using it.
Common-lisp.net kinda sucks. I got as far as to a trac page that
didn't even mention bugs. Much less how to create a bug report.
--
Lennart Staflin <·····@lysator.liu.se>
On Aug 25, 12:33 am, Lennart Staflin <·····@lysator.liu.se> wrote:
> Scott Burson <········@gmail.com> writes:
> > To be honest, I don't think anyone is using FSet but me. I know, it
> > could use more and better documentation -- though what's there is
> > already well beyond what most open-source projects have. But I have
> > other things to work on, and it's just not clear how many users FSet
> > could attract even if I wrote reams more about it.
>
> Well, I tried to use it. Found a couple of bugs, but no way of
> reporting bugs. I gave up on using it.
>
> Common-lisp.net kinda sucks. I got as far as to a trac page that
> didn't even mention bugs. Much less how to create a bug report.
Oh! Well, you could have emailed them to the FSet-devel list, or even
just posted them here -- I probably would have seen them. I see what
you mean about the Trac page not explaining itself very well -- I've
just added a sentence that should help.
Do you recall what the bugs were?
-- Scott
On Aug 25, 8:34 am, Scott Burson <········@gmail.com> wrote:
> On Aug 25, 12:33 am, Lennart Staflin <·····@lysator.liu.se> wrote:
>
> > Scott Burson <········@gmail.com> writes:
> > > To be honest, I don't think anyone is using FSet but me. I know, it
> > > could use more and better documentation -- though what's there is
> > > already well beyond what most open-source projects have. But I have
> > > other things to work on, and it's just not clear how many users FSet
> > > could attract even if I wrote reams more about it.
>
> > Well, I tried to use it. Found a couple of bugs, but no way of
> > reporting bugs. I gave up on using it.
>
> > Common-lisp.net kinda sucks. I got as far as to a trac page that
> > didn't even mention bugs. Much less how to create a bug report.
>
> Oh! Well, you could have emailed them to the FSet-devel list, or even
> just posted them here -- I probably would have seen them. I see what
> you mean about the Trac page not explaining itself very well -- I've
> just added a sentence that should help.
Whoops, it's worse than that -- you have to have a common-lisp.net
account to submit Trac tickets. My error was in recommending Trac on
the FSet page as the default bug submission mechanism. Sorry for
that. I have changed it to recommend the mailing list.
I do hope you can remember what the bugs were.
-- Scott
On Mon, 25 Aug 2008 09:19:17 -0700, Scott Burson wrote:
> Whoops, it's worse than that -- you have to have a common-lisp.net
> account to submit Trac tickets. My error was in recommending Trac on
> the FSet page as the default bug submission mechanism. Sorry for that.
> I have changed it to recommend the mailing list.
you just need to do:
trac-admin /project/fset/trac/ permission add anonymous TICKET_CREATE
TICKET_APPEND
--
Stelian Ionescu a.k.a. fe[nl]ix
Quidquid latine dictum sit, altum videtur.
On Aug 25, 11:36 am, Stelian Ionescu <········@common-lisp.net> wrote:
> you just need to do:
> trac-admin /project/fset/trac/ permission add anonymous TICKET_CREATE
> TICKET_APPEND
Thanks. I may leave it as is, though -- now that I stop to think
about it, I think it's probably better if bug reports go to the
mailing list first.
> Quidquid latine dictum sit, altum videtur.
Hoc amo :)
-- Scott
>>Scott Burson <········@gmail.com> writes:
>>
>>>To be honest, I don't think anyone is using FSet but me.
I have added it to my toolbox. No current requirement, but I am sure
there will be. I think it is a solid hack and all round Good Thing to
have at one's disposal.
kt
Kenny wrote:
>
>>> Scott Burson <········@gmail.com> writes:
>>>
>>>> To be honest, I don't think anyone is using FSet but me.
>
>
> I have added it to my toolbox. No current requirement, but I am sure
> there will be. I think it is a solid hack and all round Good Thing to
> have at one's disposal.
Ah, hello requirement! for maps, specifically.
But I need ISAM (start with an indexed read (equal, >, or >=), then
continue sequentially from there) and all I can find are do-map and
iterator that traverse the whole collection. And no lookup with the comp
(gt, ge, lt, le, eq) specifiable.
Did I miss these? I can see how I would create them given the existing
code but will not bother until I am sure they do not already exist.
I agree, btw, that more doc will not help spread the word, but my
attempts to surf the code -- boy, there is a lot of it! One thing that
might have helped was having all code specific to a collection type in
its own source.
kt
On Aug 27, 1:00 pm, Kenny <·········@gmail.com> wrote:
> Ah, hello requirement! for maps, specifically.
>
> But I need ISAM (start with an indexed read (equal, >, or >=), then
> continue sequentially from there) and all I can find are do-map and
> iterator that traverse the whole collection. And no lookup with the comp
> (gt, ge, lt, le, eq) specifiable.
You're right -- things like this are needed. Here's how I think about
them. In unreleased code I have a class called `interval-set', which
implements sets of intervals; each interval can be open or closed at
either end. One of these could be intersected with an ordinary set to
yield the set of those members of the ordinary set that are within one
of the intervals. Similarly the `restrict' operation (q.v.) on a map
and an interval set would give you the portion of the map with keys
within one of the intervals. (Am I correctly understanding that this
is what you want?)
I don't think the interval-set code is really ready to release, but I
could make it more of a priority and have something out in a month or
two, I guess. If you need anything like this before then, there are
certainly simpler ways to do it -- maybe you can undertake one of
them.
> I agree, btw, that more doc will not help spread the word, but my
> attempts to surf the code -- boy, there is a lot of it! One thing that
> might have helped was having all code specific to a collection type in
> its own source.
Okay, maybe I'll break it up a little. (In general, I like large
source files.)
-- Scott
Scott Burson wrote:
> On Aug 27, 1:00 pm, Kenny <·········@gmail.com> wrote:
>
>>Ah, hello requirement! for maps, specifically.
>>
>>But I need ISAM (start with an indexed read (equal, >, or >=), then
>>continue sequentially from there) and all I can find are do-map and
>>iterator that traverse the whole collection. And no lookup with the comp
>>(gt, ge, lt, le, eq) specifiable.
>
>
> You're right -- things like this are needed. Here's how I think about
> them. In unreleased code I have a class called `interval-set', which
> implements sets of intervals; each interval can be open or closed at
> either end. One of these could be intersected with an ordinary set to
> yield the set of those members of the ordinary set that are within one
> of the intervals. Similarly the `restrict' operation (q.v.) on a map
> and an interval set would give you the portion of the map with keys
> within one of the intervals. (Am I correctly understanding that this
> is what you want?)
That sounds super-powerful and expressive. I like it. But all we need is
a lookup on a map that returns a new map that is a subset of the
original containing only keys optionally GE or GT the lookup value. ie,
we want to do ISAM (index-sequential access) on a map: start with a
lookup GE or GT that returns a map, not a member, and then do-map the
result. Application code would decide when to stop, but a nice touch
would be to optionally specify a count or end value, or in the case of
strings to return a submap of those keys starting with that string --
what we used to call generic keys back in my DEC RMS days where the
keywords were FIND to set a cursor and GET to read one record and
advance the cursor.
I started on hacking this out of the existing code and it looked like a
couple hours work (just a matter of finding the node in the btree GE or
GT the lookup value and returning a map with the node or roght branch as
the root I am guessing) so I thought I would make sure it was not
already there.
>
> I don't think the interval-set code is really ready to release, but I
> could make it more of a priority and have something out in a month or
> two, I guess. If you need anything like this before then, there are
> certainly simpler ways to do it -- maybe you can undertake one of
> them.
I'll give it a shot if the existing mechanism used by the project for
such browsing comes up short.
>
>
>>I agree, btw, that more doc will not help spread the word, but my
>>attempts to surf the code -- boy, there is a lot of it! One thing that
>>might have helped was having all code specific to a collection type in
>>its own source.
>
>
> Okay, maybe I'll break it up a little. (In general, I like large
> source files.)
Oh, then don't mind me. Until you have a few contributors your
productivity is all that matters. My2.
thx, ken
Scott Burson <········@gmail.com> writes:
> Do you recall what the bugs were?
One was a missing function definition. map-merge isn't defined, but
used in map reader syntax.
--
Lennart Staflin <·····@lysator.liu.se>
On Aug 25, 2:23 pm, Lennart Staflin <·····@lysator.liu.se> wrote:
> Scott Burson <········@gmail.com> writes:
> > Do you recall what the bugs were?
>
> One was a missing function definition. map-merge isn't defined, but
> used in map reader syntax.
Gack! Thank you :)
-- Scott
From: Marcus Breiing
Subject: Re: copy or not? (style question)
Date:
Message-ID: <w5exec4dcy94v@breiing.com>
* Scott Burson
> Gack! Thank you :)
While we're at it... I noticed that
(fset:compare (make-symbol "FOO") (make-symbol "FOO"))
--> :EQUAL
--
Marcus
On Aug 26, 3:36 am, Marcus Breiing <······@2008w34.mail.breiing.com>
wrote:
> * Scott Burson
>
> > Gack! Thank you :)
>
> While we're at it... I noticed that
>
> (fset:compare (make-symbol "FOO") (make-symbol "FOO"))
> --> :EQUAL
Well... What should (FSET:COMPARE (+ 2.0 40) (* 2.0 21)) return?
I'd
bet it returns :EQUAL as well (I have not tried it and I am just
reading Scott's mind here :) )
Cheers
--
Marco
On Aug 26, 8:24 am, Marco Antoniotti <·······@gmail.com> wrote:
> On Aug 26, 3:36 am, Marcus Breiing <······@2008w34.mail.breiing.com>
> wrote:
>
> > * Scott Burson
>
> > > Gack! Thank you :)
>
> > While we're at it... I noticed that
>
> > (fset:compare (make-symbol "FOO") (make-symbol "FOO"))
> > --> :EQUAL
>
> Well... What should (FSET:COMPARE (+ 2.0 40) (* 2.0 21)) return?
> I'd
> bet it returns :EQUAL as well (I have not tried it and I am just
> reading Scott's mind here :) )
Yes, but (compare (+ 2.0 40) (* 2 21)) returns :UNEQUAL, as the
numbers are of equal value but different types. This is also what
Marco's example should return.
-- Scott
On Aug 26, 12:36 am, Marcus Breiing <······@2008w34.mail.breiing.com>
wrote:
> * Scott Burson
>
> > Gack! Thank you :)
>
> While we're at it... I noticed that
>
> (fset:compare (make-symbol "FOO") (make-symbol "FOO"))
> --> :EQUAL
Yes, I already have a fix for that one that I haven't released yet.
I'll try to release some of these bug fixes this weekend.
-- Scott
On Sun, 24 Aug 2008 19:22:09 -0700, Scott Burson wrote:
> But the benefits of FSet go beyond the functional semantics. Where CL
> just gives you the bare data structures and lets you use them as you
> wish, FSet collections are semantically loaded -- sets and sequences,
> for instance, are different types and support different operations. This
> allows code using them to be written more abstractly, and thus more
> elegantly.
>
> Well, that's my opinion, anyway. I hope you'll give it a try. I'd love
> to hear what you think about it, whether you wind up using it or not.
Hi Scott,
I looked at your library, and I find the idea nice, but I won't be using
it. Mostly because I use matrices and vectors, and don't want to deal
with the overhead and possible bugs. Also, when I call foreign
functions, I would have to convert, which would be a large PITA.
Best,
Tamas
On Aug 25, 4:43 am, Tamas K Papp <······@gmail.com> wrote:
> On Sun, 24 Aug 2008 19:22:09 -0700, Scott Burson wrote:
> > But the benefits of FSet go beyond the functional semantics. Where CL
> > just gives you the bare data structures and lets you use them as you
> > wish, FSet collections are semantically loaded -- sets and sequences,
> > for instance, are different types and support different operations. This
> > allows code using them to be written more abstractly, and thus more
> > elegantly.
>
> > Well, that's my opinion, anyway. I hope you'll give it a try. I'd love
> > to hear what you think about it, whether you wind up using it or not.
>
> Hi Scott,
>
> I looked at your library, and I find the idea nice, but I won't be using
> it. Mostly because I use matrices and vectors, and don't want to deal
> with the overhead and possible bugs.
Overhead? Yes, there is some, but compared with frequently making
copies, it's probably faster.
And obviously nobody wants to use a collections package that's going
to lose data -- which is why I tested FSet very thoroughly before I
released it. (I'm using it too, and I certainly don't want it to
screw up!)
> Also, when I call foreign
> functions, I would have to convert, which would be a large PITA.
Ah yes, well, that could be an annoyance.
Oh well, thanks for taking a look at it anyway.
-- Scott
Tamas K Papp <······@gmail.com> writes:
> Now I am drifting towards the opposite style, where I do not make copies:
> the assumption is that whoever calls the function should not mess with
> the arrays afterwards. If the user needs to change the structure, he
> should make a copy and change that.
>
> I think that both styles can be consistent. The latter seems elegant,
> but less "secure". OTOH, when I write this code as a library, I guess I
> can just document the fact that arrays are not copied and the user should
> act accordingly.
>
> Which style is more "natural" in Lisp?
Both.
In CL, there are functions that are specified not to change the
arguments, and others that are allowed to change them.
For example:
(let ((a (list 1 2 3 2 4 2 5 2)))
(print (remove 2 a))
a)
prints:
(1 3 4 5)
--> (1 2 3 2 4 2 5 2)
On the other hand:
(let ((a (list 1 2 3 2 4 2 5 2)))
(print (delete 2 a))
a)
prints:
(1 3 4 5)
--> (1 3 4 5)
For a lot of functions there's a pair F / NF, F doesn't modify its
arguments, while NF must avoid consing, and therefore is allowed to
modify its arguments. ((substitute nsubstitute) (reverse nreverse) ...)
However, in a programming language without a garbage collector it's
rather hard to manage structure sharing and functions returning new
structures, so it is customary in these programming languages to make
a lot of copies. But in Lisp we have a garbage collector, so we can
on the contrary optimize out time and space, by sharing structures.
Therefore I would rather advise using pure functions, that won't
modify their arguments, and for which it is useless to copy them.
> What do you use?
Both. See above.
--
__Pascal Bourguignon__ http://www.informatimago.com/
Cats meow out of angst
"Thumbs! If only we had thumbs!
We could break so much!"
On Sun, 24 Aug 2008 20:28:05 +0200, Pascal J. Bourguignon wrote:
> For a lot of functions there's a pair F / NF, F doesn't modify its
> arguments, while NF must avoid consing, and therefore is allowed to
> modify its arguments. ((substitute nsubstitute) (reverse nreverse) ...)
>
> However, in a programming language without a garbage collector it's
> rather hard to manage structure sharing and functions returning new
> structures, so it is customary in these programming languages to make a
> lot of copies. But in Lisp we have a garbage collector, so we can on
> the contrary optimize out time and space, by sharing structures.
> Therefore I would rather advise using pure functions, that won't modify
> their arguments, and for which it is useless to copy them.
For me, the issue is not really about optimization, but enforcing some
consistency on shared structures. Imagine that a closure uses shared
structure, which is required to satisfy some condition. One could
1) check the structure at the time of the closure's creation,
2) check the structure each time the closure is called,
3) both,
4) neither
1) catches obvious misunderstandings (eg the function expecting a vector
of weakly increasing numbers, but called with one that does not satisfy
this), and is reasonably fast. But the shared structure can be modified
in the meantime.
2) always catches inconsistencies, but it is slow and mostly
unnecessary. 3) ditto.
4) can be bad. Some inconsistencies are caught as an error (such as
division by 0). But with numerical computations, errors can creep in
unnoticed, and are hard to debug. The worst-case scenario is having an
inconsistency that influences computation but is not noticed at all.
I think that there is another way: make error checking dependent on
something, possibly the safety declaration, for example. If I recall
correctly, Eiffel compilers had a feature like this which you could turn
off after the code has been tested. How could I do this in CL? Suppose
(declaim (optimize (safety 3)))
was used. How can I make code dependent on the safety level?
But even this would be a compilation-time feature, not something I can
toggle at runtime - that's OK I guess.
I wonder if this is the way to go, opinions and suggestions are welcome.
Thanks,
Tamas
In article <··············@mid.individual.net>,
Tamas K Papp <······@gmail.com> wrote:
> On Sun, 24 Aug 2008 20:28:05 +0200, Pascal J. Bourguignon wrote:
>
> > For a lot of functions there's a pair F / NF, F doesn't modify its
> > arguments, while NF must avoid consing, and therefore is allowed to
> > modify its arguments. ((substitute nsubstitute) (reverse nreverse) ...)
> >
> > However, in a programming language without a garbage collector it's
> > rather hard to manage structure sharing and functions returning new
> > structures, so it is customary in these programming languages to make a
> > lot of copies. But in Lisp we have a garbage collector, so we can on
> > the contrary optimize out time and space, by sharing structures.
> > Therefore I would rather advise using pure functions, that won't modify
> > their arguments, and for which it is useless to copy them.
>
> For me, the issue is not really about optimization, but enforcing some
> consistency on shared structures. Imagine that a closure uses shared
> structure, which is required to satisfy some condition. One could
>
> 1) check the structure at the time of the closure's creation,
> 2) check the structure each time the closure is called,
> 3) both,
> 4) neither
>
> 1) catches obvious misunderstandings (eg the function expecting a vector
> of weakly increasing numbers, but called with one that does not satisfy
> this), and is reasonably fast. But the shared structure can be modified
> in the meantime.
>
> 2) always catches inconsistencies, but it is slow and mostly
> unnecessary. 3) ditto.
>
> 4) can be bad. Some inconsistencies are caught as an error (such as
> division by 0). But with numerical computations, errors can creep in
> unnoticed, and are hard to debug. The worst-case scenario is having an
> inconsistency that influences computation but is not noticed at all.
>
> I think that there is another way: make error checking dependent on
> something, possibly the safety declaration, for example. If I recall
> correctly, Eiffel compilers had a feature like this which you could turn
> off after the code has been tested. How could I do this in CL? Suppose
>
> (declaim (optimize (safety 3)))
>
> was used. How can I make code dependent on the safety level?
>
> But even this would be a compilation-time feature, not something I can
> toggle at runtime - that's OK I guess.
>
> I wonder if this is the way to go, opinions and suggestions are welcome.
>
> Thanks,
>
> Tamas
It is relatively simple. If you need to protect
data against modifications then do it.
* let routines hand out copies of the original data
* let routines hand out shallow objects (value objects)
with just the necessary data set
* let routines hand out data that only it knows how to
change. For example in CLOS you could use slot names
that are not global symbols. So slots could
be read with a reader function, but there would be
no writer and no way to set the SLOT-VALUE (without
knowing the private slotname).
* if there is some concurrent access the use locks
(or similar) to protect the data against concurrent
changes
* in some cases you might want to make sure that the
changing operations are atomic
* some routines might want to make copies of argument data first
If your software needs to check the integrity of some data,
the write assertions (see ASSERT and CHECK-TYPE).
If your needs are more demanding, then you might think
about some kind of transaction handling.
--
http://lispm.dyndns.org/