I'm looking for a XOR to use like I use AND and OR. But the only things
I found in the CLHS are:
BIT-XOR, which works on bit arrays
BOOLE-XOR, which, when used with BOOLE, works on integers
LOG-XOR, which works on integers
CLisp seems to have XOR, but CMUCL and SBCL don't. Isn't there some
standard function for this? Or am I wrong in wanting one?
Background: I need to check that two values are either both null or both
non-null, and not a mix of null and non-null. I'd like to write:
(assert (not (xor (null v1) (null v2))))
Philippe Lorin <············@gmail.com> writes:
> I'm looking for a XOR to use like I use AND and OR. But the only
> things I found in the CLHS are:
> BIT-XOR, which works on bit arrays
> BOOLE-XOR, which, when used with BOOLE, works on integers
> LOG-XOR, which works on integers
>
> CLisp seems to have XOR, but CMUCL and SBCL don't. Isn't there some
> standard function for this? Or am I wrong in wanting one?
I think this works:
(defmacro xor (v1 v2)
`(not (eq (not ,v1) (not ,v2))))
-russ
······@schlund.de (Hannah Schroeter) writes:
> Hello!
>
> Russell McManus <···············@yahoo.com> wrote:
> >[...]
>
> >I think this works:
>
> >(defmacro xor (v1 v2)
> > `(not (eq (not ,v1) (not ,v2))))
>
> Use macros only if functions don't work.
>
> (defun xor (v1 v2)
> (not (eq (not v1) (not v2))))
Incidentally, as a matter of history, after the publication of the
first CLTL in 1984, there was a meeting in 1986 in Monterrey CA to
talk about how to proceed. Steel brought a list of things he thought
were obvious and non-controversial that he wanted to change. Of
the people attending (many of whom were not original designers of
CLTL but new people who had read it and started to use the language
or make implementations and felt they should have a say in how it
moved forward), little concensus was to be had other than that a
lot of people objected to a lot of the things on the list as non-obvious.
One of the items on that list was the addition of xor. As I recall
what made it controversial was precisely this question of whether it
should be a macro or special form (for consistency with AND and OR) or
a function (because it somewhat accidentally is able to be, as an
accident of how it is computed). Of the pre-defined operators by
CLTL, I believe PROG1 is the only one that could have been implemented
as a normal function, but is defined not to be...
Anyway, I just wanted to raise the issue that this is a well-known
issue of somewhat historical nature.
You can probably find out how the Monterrey meeting turned out in Google.
But in short, it's spectacular lack of ability to get consensus led
to a decision to start ANSI subcommittee X3J13...
Kent M Pitman wrote:
> One of the items on that list was the addition of xor. As I recall
> what made it controversial was precisely this question of whether it
> should be a macro or special form (for consistency with AND and OR) or
> a function (because it somewhat accidentally is able to be, as an
> accident of how it is computed). Of the pre-defined operators by
> CLTL, I believe PROG1 is the only one that could have been implemented
> as a normal function, but is defined not to be...
>
> Anyway, I just wanted to raise the issue that this is a well-known
> issue of somewhat historical nature.
Now that CLOS is integrated into the language definition,
is there a similar generic controversy about whether functions
added to the language should be generic?
By the way, it seems to me that an XOR function should be binary,
and should return the true argument in the case where exactly
one of the two arguments is true.
Paul
"Paul F. Dietz" <·····@dls.net> writes:
> Kent M Pitman wrote:
>
> > One of the items on that list was the addition of xor. As I recall
> > what made it controversial was precisely this question of whether it
> > should be a macro or special form (for consistency with AND and OR) or
> > a function (because it somewhat accidentally is able to be, as an
> > accident of how it is computed). Of the pre-defined operators by
> > CLTL, I believe PROG1 is the only one that could have been implemented
> > as a normal function, but is defined not to be...
> > Anyway, I just wanted to raise the issue that this is a well-known
> > issue of somewhat historical nature.
>
> Now that CLOS is integrated into the language definition,
> is there a similar generic controversy about whether functions
> added to the language should be generic?
Yes and no.
This issue pre-dated CLOS integration. That is, it was there as long as
any talk of CLOS.
The reason many operators are not generic is that deciding how to do
them generically is tricky and people disagree on the definition. I
recall the NIL project (JonL White, Jonathan Rees, and Rick Bryan) ran
afoul of a generic definition for LENGTH enough that let us worry. Consider:
(defmethod length ((x cons)) (+ 1 (length (cdr x))))
(defmethod length ((x null)) 0)
(defmethod length ((x string)) (array-dimension x 0))
Now think about
(length '(a b . "foo"))
The point is that often independent definitions invite what I'll call the
"modularity problem" where definitions look ok in isolation but surprising
effects happen in combination. Similar to what
(+ 1 2 "foo")
might do if we allowed + to be generic.
In sum, there is "genericity" and there is "just plain overloading". Lisp
has eschewed overloading. But the main difference is some notion that there
is a dominant conceptual definition that defines identities on these things
such that they behave as something akin to well-formed groups in mathematics,
not merely as rogue mappings going every-which-way. And if you opened
this issue, you'd get all kinds of that kind of thing.
We had a brief squabble over what to do with (append '(a b . c) 'd '(e . f))
in common lisp. I believe NCONC and APPEND differ in their treatment of
these (don't have time to look this up, so could be misremembering) because
NCONC traditionally relied on some things that APPEND didn't, and we came
up with a split theory.
There turns out to be huge debugging value in things being undefined, that
is, in a language being "sparse" in terms of what's defined in what's not.
Adding genericity not only gives power but it gives less ability to get
quick error detection at time of an error. The more coercion that can happen,
the more a program will run along before hitting an error... I've seen
programs run to completion with bad data coerced many ways along the way
to locally plausible choices.
So yes, it's like the other issue in terms of its both seeming obvious
and seeming differently obvious to others, and hence being controversial.
> By the way, it seems to me that an XOR function should be binary,
> and should return the true argument in the case where exactly
> one of the two arguments is true.
I disagree strongly.
The decision to use XOR as a binary truth operator is something you
can do personally without others doing it. That is, the people
wanting to compatibly use a multi-arg situation should not be forced
to "find another name". The generic name should go with the most
generic use; more specific names should go with more specific uses.
(That's just my opinion, but I might as well state it with the same
force that I feel it.)
The function you want is the one that would generalize to multiple
arguments differently than xor does, and the reason you want it in
binary is that only in the binary case do they have somewhat overlapping
meaning. But you really want:
(defun one-of (&rest args)
(some #'identity args))
Kent M Pitman wrote:
> Now think about
> (length '(a b . "foo"))
Intriguing possibility: Is it necessarily the wrong thing for that to
return 5? Maybe it should do just that, while a more specific function
LIST-LENGTH would throw an error.
"Tron3k" <······@gmail.com> writes:
> Kent M Pitman wrote:
>> Now think about
>> (length '(a b . "foo"))
>
> Intriguing possibility: Is it necessarily the wrong thing for that to
> return 5? Maybe it should do just that, while a more specific function
> LIST-LENGTH would throw an error.
Supposing you have a variable *FOO*. You call
(length *foo*)
=> 5
Should (elt *foo* 4) give you an error? What should it return if
*foo* is '(a b . "foo")? Could you SETF it?
What should (length (concatenate 'list *foo* *foo*)) return?
--
~jrm
Joe Marshall <·············@comcast.net> writes:
> "Tron3k" <······@gmail.com> writes:
>
> > Kent M Pitman wrote:
> >> Now think about
> >> (length '(a b . "foo"))
> >
> > Intriguing possibility: Is it necessarily the wrong thing for that to
> > return 5? Maybe it should do just that, while a more specific function
> > LIST-LENGTH would throw an error.
>
> Supposing you have a variable *FOO*. You call
>
> (length *foo*)
> => 5
>
> Should (elt *foo* 4) give you an error? What should it return if
> *foo* is '(a b . "foo")? Could you SETF it?
>
> What should (length (concatenate 'list *foo* *foo*)) return?
One person's intrigue is another's catastrophe. You seem to
implicitly suggest that no one is relying on getting an error message
here and that the change you propose is compatible. Or else that the
compatibility concern is of no consequence. See
http://www.nhplace.com/kent/CL/x3j13-86-020.html
for historical context.
And what should (concatenate 'list *foo* *foo*) return, for that matter.
Just because you expect an output list doesn't mean you mean to treat
the inputs as lists... CL defines their type to be dynamically inspectable.
One reason ELT is interesting is that it's already inefficient for ELT to
worry someone will use it to write some algorithm that supposes random access.
At least now ELT can sniff at the type it's given and select an appropriate
algorithm for doing its work based on that type. If the type can vary
recursively, you take away even that minimal class of dynamic optimization.
Remember that one reason we signal errors about non-homogeneity of type
is to permit programs that assume a local degree of homogeneity at least
in the container structure. This, at least, is the motivation for ENDP.
ENDP makes very little remaining sense in a world where the type of the
object changes as you recurse, since it's all about the intention of it
not changing.
Questions like this affect the whole fabric of the language if you not only
make a random local change but start propagating its implications into
changes around it. That fact--of destabilization of time-tested sets of
operations--is why we didn't originally do the change to generic, and it's
why I stand by that now.
I don't have opposition to a new generic set of operations being written
as a library for those who like that kind of thing. It's easy enough to do.
I don't say languages written with this as a basic premise will fail.
I just say that at some point if you morph the core of CL more than a certain
amount to suit a new community, you sacrifice the original community for
which it is built, most of whom are not clamoring for this change in order
to get their work done.
Build the experiment first. Find out if people use it exclusively and
abandon the old ways. THEN argue that the old unused operators should
fall away and yield their names to the new.
Then again, since you can build a whole new TRON3K-COMMON-LISP package and
seed it with whatever you want without changing CL at all, I'm STILL not sure
why you would sacrifice the ability to cross-call old code without modification
and not just teach people to start compatibly in TRON3K-COMMON-LISP...
"Tron3k" <······@gmail.com> writes:
> Kent M Pitman wrote:
> > Now think about
> > (length '(a b . "foo"))
>
> Intriguing possibility: Is it necessarily the wrong thing for that to
> return 5? Maybe it should do just that, while a more specific function
> LIST-LENGTH would throw an error.
Necessarily? No.
Likely? Yes.
While you can think up uses for it, there are also already tons of non-uses
(that is, errors wanting to be caught). Making those things "work" is the
same as not detecting those errors.
It's so easy to write an operator that does what you suggest you might
in this case that one question is why you would want to perturb
others' existing code by an incompatible definition ...
But the main point is that whether this is right is a matter of "intention"
and any assertion that this is something that is dynamically knowable is
improper. As such, the decision is intrinsically arbitrary, and favoring
compabitility in the arbitrary seems a good plan to me...
See http://www.nhplace.com/kent/PS/EQUAL.html for more exposition on this.
Kent M Pitman wrote:
> "Tron3k" <······@gmail.com> writes:
>>Kent M Pitman wrote:
>>
>>>Now think about
>>> (length '(a b . "foo"))
>>
>>Intriguing possibility: Is it necessarily the wrong thing for that to
>>return 5? Maybe it should do just that, while a more specific function
>>LIST-LENGTH would throw an error.
>
> Necessarily? No.
>
> Likely? Yes.
>
> While you can think up uses for it, there are also already tons of non-uses
> (that is, errors wanting to be caught). Making those things "work" is the
> same as not detecting those errors.
I agree with this, but I do not see how that makes genericizing the
sequence functions any more difficult. Require LENGTH to be passed a
sequence, and not an improper list. If passed an improper list, length
should raise a condition of type type-error, just like it does now.
This disallows the "clever" implementation of length for lists that you
listed:
> (defmethod length ((x cons)) (+ 1 (length (cdr x))))
> (defmethod length ((x null)) 0)
So don't implement it that way!
-- MJF
M Jared Finder wrote:
> This disallows the "clever" implementation of length for lists that you
> listed:
>
>> (defmethod length ((x cons)) (+ 1 (length (cdr x))))
>> (defmethod length ((x null)) 0)
>
>
> So don't implement it that way!
The reason I would like to see functions like LENGTH implemented
as generic functions is not so that this clever (but wrong,
as Kent points out) implementation could be used, but so that
users could add their own sequence types (and, elsewhere, their
own streams, and hash tables, and so on).
Paul
"Paul F. Dietz" <·····@dls.net> writes:
> M Jared Finder wrote:
>
> > This disallows the "clever" implementation of length for lists that
> > you listed:
> >
> >> (defmethod length ((x cons)) (+ 1 (length (cdr x))))
> >> (defmethod length ((x null)) 0)
> > So don't implement it that way!
>
> The reason I would like to see functions like LENGTH implemented
> as generic functions is not so that this clever (but wrong,
> as Kent points out) implementation could be used, but so that
> users could add their own sequence types (and, elsewhere, their
> own streams, and hash tables, and so on).
I don't dispute this. However, I personally think the right way to do
this (in CL--different languages have different sensibilities) is to
provide a protocol hookup to the sequence class.
The problem with allowing different sequence classes without requiring
them to be subclasses of sequence is accidentally allowing other things.
It's bad enough that NIL is sometimes a non-list and sometimes a list.
e.g., consider (string 'nil) vs (coerce nil 'string). It's just plain
hard to get this right. Whereas defining your own operators as you like
is easier.
Kent M Pitman <······@nhplace.com> writes:
> The reason many operators are not generic is that deciding how to do
> them generically is tricky and people disagree on the definition. I
> recall the NIL project (JonL White, Jonathan Rees, and Rick Bryan)
> ran afoul of a generic definition for LENGTH enough that let us
> worry. Consider:
> (defmethod length ((x cons)) (+ 1 (length (cdr x))))
> (defmethod length ((x null)) 0)
> (defmethod length ((x string)) (array-dimension x 0))
> Now think about
> (length '(a b . "foo"))
The fault is not in length being generic, but in the definition of
length for cons or in the existence of improper lists (it's enough
to fix either of them).
> The point is that often independent definitions invite what I'll call the
> "modularity problem" where definitions look ok in isolation but surprising
> effects happen in combination. Similar to what
> (+ 1 2 "foo")
> might do if we allowed + to be generic.
It should be an error: + should work only for numbers, string concatenation
is a sufficiently different operation. But it doesn't mean that + shouldn't
be generic.
--
__("< Marcin Kowalczyk
\__/ ······@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
> * Marcin 'Qrczak' Kowalczyk <······@xaz.bet.cy> [2005-07-20 16:10:41 +0200]:
>
> Kent M Pitman <······@nhplace.com> writes:
>
>> The point is that often independent definitions invite what I'll call the
>> "modularity problem" where definitions look ok in isolation but surprising
>> effects happen in combination. Similar to what
>> (+ 1 2 "foo")
>> might do if we allowed + to be generic.
>
> It should be an error: + should work only for numbers, string
> concatenation is a sufficiently different operation. But it doesn't
> mean that + shouldn't be generic.
this is confusing.
on one hand, you say that "+ should work only for numbers".
since there is no way to create a new kind of numbers,
the implementation can implement + as a non-generic function
without losing any functionality.
on the other hand, you say "it doesn't mean that + shouldn't be generic"
what's the point? you cannot add a method anyway!
you cannot define a new kind of number!
Yeah, you might find it tempting to be able to write
(defclass quaternion (number) ...)
(defmethod + ((x quaternion) (y number)) ...)
But as soon as you do, you need to define also * methods.
note that quaternion multiplication is not commutative, and octonions
are not even associative, so the usual properties of * that many
compilers use will now be broken (unless the compiler can establish
argument types).
yes, the "demo" or "toy" value of CL would increase
if all the functions were generic,
but CL is not a "demo" language.
CL is the tool for solving _hard_ problems.
Why would you want to "overload" + in a large project
(where it will confuse people)?
--
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.honestreporting.com> <http://www.jihadwatch.org/>
<http://ffii.org/> <http://www.memri.org/> <http://www.dhimmi.com/>
Politically Correct Chess: Translucent VS. Transparent.
Sam Steingold <···@gnu.org> writes:
>> It should be an error: + should work only for numbers, string
>> concatenation is a sufficiently different operation. But it doesn't
>> mean that + shouldn't be generic.
>
> this is confusing.
> on one hand, you say that "+ should work only for numbers".
> since there is no way to create a new kind of numbers,
There should be.
> note that quaternion multiplication is not commutative,
I don't mean quaternions, but e.g. decimal fixed point numbers for
currencies (more efficient than rationals), or lazily computed
arbitrary precision approximations of real numbers.
--
__("< Marcin Kowalczyk
\__/ ······@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
> * Marcin 'Qrczak' Kowalczyk <······@xaz.bet.cy> [2005-07-20 17:05:50 +0200]:
>
> I don't mean quaternions, but e.g. decimal fixed point numbers for
> currencies (more efficient than rationals),
neither rationals nor integers (another common advice) are good for
currencies.
numbers can be multiplied by each other.
currencies cannot.
what is (* $10 $15)?
$$150?!
--
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.camera.org> <http://www.openvotingconsortium.org/>
<http://www.dhimmi.com/> <http://www.honestreporting.com>
MS Windows: error: the operation completed successfully.
Ingvar <······@hexapodia.net>:
> I'd say that a currency multiplied with another currency is a domain
> fault.
So how do you compute the variation of the amount of computing power
at a fixed budget (measured in SPECint per square Euro)?
Juliusz
Sam Steingold <···@gnu.org> writes:
> neither rationals nor integers (another common advice) are good for
> currencies.
> numbers can be multiplied by each other.
> currencies cannot.
> what is (* $10 $15)?
> $$150?!
I meant dimensionless decimal fractions, commonly called "decimal" or
"currency" in other languages. See http://www.python.org/peps/pep-0327.html
for example.
Adding units is another story that I never looked at.
--
__("< Marcin Kowalczyk
\__/ ······@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
Marcin 'Qrczak' Kowalczyk <······@knm.org.pl> writes:
> > The point is that often independent definitions invite what I'll call the
> > "modularity problem" where definitions look ok in isolation but surprising
> > effects happen in combination. Similar to what
> > (+ 1 2 "foo")
> > might do if we allowed + to be generic.
>
> It should be an error: + should work only for numbers, string concatenation
> is a sufficiently different operation. But it doesn't mean that + shouldn't
> be generic.
I'm not sure "sufficiently different" is well-formed.
I have always felt like Group Theory held the answer to this terminological
problem, but I never studied it and so was terminologically impaired.
Recently I started a teach yourself Teach Yourself Mathematical Groups and
now I'm armed with just a tiny bit of information, which makes me probably
dangerous because I have a new toy where I've not gotten done reading all the
instructions... ;) [Maybe someone who does know better can set me onto the
right path if I've screwed up my analysis or terminology here.]
But the issue it seems to me is that you want generic functions (and
their range/domain data) to be something like a well-formed group
where possible--certainly you want them not to destroy the well-formedness
of any group that is there before making something generic.
So if + operates on some set S of data such that the usual rules of
commutativity and associativity and whatnot apply and then suddenly you
add string concatenation, it's not the "differentness" of string
concatenation that's the problem, it's the fact that you're defining
coercion from numbers to strings such that
(+ 1 2 "foo")
might mean
(+ (+ 1 2) "foo") => "3foo"
or
(+ 1 (+ 2 "foo")) => "12foo"
If it had been opaque values, (+ x y z), in a runtime-typed world like
Lisp, this is just not acceptable because the compiler is no longer free
to optimize according to normal math optimization rules, turning
(+ 1 2 x)
or
(+ x 1 2)
into something simpler at compile time. It has to compile all the arguments
for passing at runtime just in case + has some very particular order that
it must do things for reproducibility. Making this still clearer:
(defun f (one three)
(= (+ one 2 "three") (+ 1 2 three)))
(f 1 "three")
is going to compile to something that will in all likelihood return NIL
because it's going to optimize it to:
(defun f (one three)
(= (+ one "2three") (+ 3 three)))
(f 1 "three")
If it were the case that these properties were not disturbed, I'd have a lot
less concern about the sameness/differentness.
And I'm pretty sure if I thought hard that I'd I feel the same for the same
reasons about the recursive problem in
(length '(a b . "foo"))
That is, the problem is again that I PREFER the analysis that lets you optimize
(length (the list x))
and when you start saying that a cons could be part of some weird structure
that must be recursively analyzed, you take away the ability to do that,
requiring me to do runtime analysis that is usually unnecessary in the present
semantics, but that would be forced as an additional cost in the proposed
semantics.
Kent M Pitman <······@nhplace.com> writes:
>> It should be an error: + should work only for numbers, string
>> concatenation is a sufficiently different operation. But it doesn't
>> mean that + shouldn't be generic.
>
> I'm not sure "sufficiently different" is well-formed.
>
> I have always felt like Group Theory held the answer to this
> terminological problem, but I never studied it and so was
> terminologically impaired.
Using + for an arbitrary group operation presents a fundamental
problem: the group in question must be inferred from their elements.
You can't consider different group structures over the same set.
And there is no way to refer to the unit element in the same style,
as the meaning of a constant would have to depend on the context
(from languages I know only Haskell/Clean/Mercury can do that).
The natural design of generic groups in a programming language makes
the group an object which consists of the group operation, the unit
element, and the inverse. The group operation can be thus uncurried
to a ternary function, taking the group and the two elements.
Of course we don't want to explicitly say that we are adding integers.
So a generic group framework is one thing, and + is another: + must
be limited to some common cases where the group can be inferred from
the elements. Since it can't denote a fully generic group operation
anyway, restricting it to numbers should not be a big deal.
> So if + operates on some set S of data such that the usual rules of
> commutativity and associativity and whatnot apply and then suddenly
> you add string concatenation, it's not the "differentness" of string
> concatenation that's the problem, it's the fact that you're defining
> coercion from numbers to strings such that
> (+ 1 2 "foo")
> might mean
> (+ (+ 1 2) "foo") => "3foo"
> or
> (+ 1 (+ 2 "foo")) => "12foo"
Yes, but even without the coercion it would be problematic: + couldn't
work for an arbitrary number of arguments, because (+) can't be 0 and
"" at the same time.
A binary (or non-empty) + would work, but it would be pointless:
I can't imagine a useful algorithm which would add numbers or
concatenate strings depending on the values given to it. An algorithm
which works for an arbitrary group should be expressed differently:
it should take the operation from the group structure instead of
inferring it from elements.
> And I'm pretty sure if I thought hard that I'd I feel the same for
> the same reasons about the recursive problem in
> (length '(a b . "foo"))
> That is, the problem is again that I PREFER the analysis that lets
> you optimize (length (the list x))
I never advocated length which would answer 5 to the above. Length
being a generic function can be implemented as efficiently as
currently: the compiler can assume that standard sequence types are
so common that they are checked first, and only as the last resort
the generic function is tried instead of signalling an error.
--
__("< Marcin Kowalczyk
\__/ ······@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
On 9170 day of my life Kent M. Pitman wrote:
> One of the items on that list was the addition of xor. As I recall
> what made it controversial was precisely this question of whether it
> should be a macro or special form (for consistency with AND and OR) or
> a function (because it somewhat accidentally is able to be, as an
> accident of how it is computed).
Why is it so important? What is wrong if XOR is function but OR and
AND macros? If macro/special form evaluates all their arguments
sequentially, why not implement it as a function?
Of course, you can perform more operations with a function than with a
special form (for example, MAPCAR and so on). But it is only an
advantage IMHO.
--
Ivan Boldyrev
Tragedy of programmers is that computer is wonderful toy
and programmers have to use it in their work.
Ivan Boldyrev <···············@cgitftp.uiggm.nsc.ru> writes:
> On 9170 day of my life Kent M. Pitman wrote:
> > One of the items on that list was the addition of xor. As I recall
> > what made it controversial was precisely this question of whether it
> > should be a macro or special form (for consistency with AND and OR) or
> > a function (because it somewhat accidentally is able to be, as an
> > accident of how it is computed).
>
> Why is it so important? What is wrong if XOR is function but OR and
> AND macros? If macro/special form evaluates all their arguments
> sequentially, why not implement it as a function?
It affects whether FUNCALL and APPLY work.
But it also affects regularity of design.
But mostly, if implementations can differ, it's a portability problem.
THAT matters. It should for that reason be clear.
> Of course, you can perform more operations with a function than with a
> special form (for example, MAPCAR and so on). But it is only an
> advantage IMHO.
And so some implementations would do it if they can. Others will fail
to do it to "helpfully" remind you remember that it's not portable.
And in doing so, they will create the non-portability... ;)
On 9173 day of my life Kent M. Pitman wrote:
>> Why is it so important? What is wrong if XOR is function but OR and
>> AND macros? If macro/special form evaluates all their arguments
>> sequentially, why not implement it as a function?
>
> It affects whether FUNCALL and APPLY work.
Yes, but it extends usage, but doesn't limit it.
> But it also affects regularity of design.
(mapcar #'not some-list)
--
Ivan Boldyrev
Your bytes are bitten.
Philippe Lorin <············@gmail.com> writes:
> CLisp seems to have XOR, but CMUCL and SBCL don't. Isn't there some
> standard function for this?
No.
> Or am I wrong in wanting one?
You're not necessarily wrong, but note that AND and OR are macros, not
functions, because they short-circuit; also, they take arbitrary
numbers of arguments, not just two; so it's not clear that XOR
actually fits in with AND and OR.
> Background: I need to check that two values are either both null or
> both non-null, and not a mix of null and non-null. I'd like to write:
> (assert (not (xor (null v1) (null v2))))
(assert (if v1 v2 (not v2)))
This is easily wrapped up into a function if you feel the need.
Christophe
Christophe Rhodes wrote:
> You're not necessarily wrong, but note that AND and OR are macros, not
> functions, because they short-circuit; also, they take arbitrary
> numbers of arguments, not just two; so it's not clear that XOR
> actually fits in with AND and OR.
a nice specification is given by the ext:xor function in CLisp:
| This function checks that exactly one of its arguments is non-NIL and,
| if this is the case, returns its value and index in the argument list
| as multiple values, otherwise returns NIL.
An implementation by me:
(defun xor (&rest list)
(when list
(destructuring-bind (first &rest rest) list
(if first
(when (every #'null rest) first)
(apply #'xor rest)))))
I'm sure it could be done easier :-)
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Frank Buss <··@frank-buss.de> writes:
> a nice specification is given by the ext:xor function in CLisp:
>
> | This function checks that exactly one of its arguments is non-NIL and,
> | if this is the case, returns its value and index in the argument list
> | as multiple values, otherwise returns NIL.
Why is this nice?
Christophe
Christophe Rhodes wrote:
> Why is this nice?
because this is what xor means: the output is true, if exactly one of the
input is true. I think this could be used more often as the other
interpretation with counting the number of nils and checking for odd.
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Frank Buss <··@frank-buss.de> writes:
> Christophe Rhodes wrote:
>
> > Why is this nice?
>
> because this is what xor means: the output is true, if exactly one of the
> input is true. I think this could be used more often as the other
> interpretation with counting the number of nils and checking for odd.
XOR is associative, which is why the n-ary (ODDP (COUNT NIL ..))
version is consistent with the two-arg version. And since the
n-ary version doesn't cons, why wouldn't it be better?
Frank Buss <··@frank-buss.de> writes:
> Christophe Rhodes wrote:
>
>> Why is this nice?
>
> because this is what xor means: the output is true, if exactly one of the
> input is true.
That is not what multiple argument xor means.
> I think this could be used more often as the other interpretation
> with counting the number of nils and checking for odd.
If you had any evidence for this, this might be a good reason, apart
from the fact that this interpretation is counter to the mathematical
definition.
Christophe
Christophe Rhodes wrote:
> Frank Buss <··@frank-buss.de> writes:
>
> > because this is what xor means: the output is true, if exactly one of the
> > input is true.
>
> That is not what multiple argument xor means.
I'm not sure there is a completely unambigous definition for multiple
argument "eXclusive OR."
"One and only one" is an interpretation that emphasizes the "exclusive"
distinction.
A XOR B XOR C is another interpretation, which emphasizes the "addition
mod 2" definition.
For two arguments, these definitions are equivalent; for multiple
arguments, they obviously differ.
Christophe Rhodes wrote:
> That is not what multiple argument xor means.
yes, I know this and logxor works like the mathematical definition, but for
the logical counterpart I think the other definition is more useful. But
perhaps it should be renamed (something like "only-one"), to avoid
confusion.
>> I think this could be used more often as the other interpretation
>> with counting the number of nils and checking for odd.
>
> If you had any evidence for this, this might be a good reason, apart
> from the fact that this interpretation is counter to the mathematical
> definition.
You should ask the CLisp people :-) but a far-fetched example: You have 4
switches for controlling back/forward of 2 motors, but you are not allowed
to turn on back and forward of one motor at the same time, because it is a
push-pull circuit and this would result in a short circuit and you are not
allowed to turn on two motors at once, because this would cause too much
power consumption:
(defun control-motors (up down left right)
(when (xor up down left right)
(set-relay 1 up)
(set-relay 2 down)
(set-relay 3 left)
(set-relay 4 right)))
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Frank Buss <··@frank-buss.de> writes:
> Christophe Rhodes wrote:
>> [Frank Buss]
>>> I think this could be used more often as the other interpretation
>>> with counting the number of nils and checking for odd.
>>
>> If you had any evidence for this, this might be a good reason, apart
>> from the fact that this interpretation is counter to the mathematical
>> definition.
>
> You should ask the CLisp people :-) but a far-fetched example
I don't deny that exactly-one-true has a use; I want to know why you
think it is used more often than odd-number-true, and whether that has
any basis in reality.
Christophe
Frank Buss wrote:
>| This function checks that exactly one of its arguments is non-NIL and,
>| if this is the case, returns its value and index in the argument list
>| as multiple values, otherwise returns NIL.
>
> An implementation by me:
I forgot the index, so some standard loop magic:
(defun xor (&rest list)
(when list
(loop for (first . rest) on list
for i = 0 then (1+ i) do
(if first
(when (every #'null rest) (return (values first i)))))))
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Frank Buss wrote:
> Frank Buss wrote:
> I forgot the index, so some standard loop magic:
If you are already using loop, save typing:
(defun xor (&rest args)
(loop for (a . d) on args
for i from 0
until a
finally (return (and (every 'null d) (values a i)))))
Normally, with the name xor, I would expect something like:
(defun xor (&rest args)
(oddp (count nil args :key 'null)))
^L
Hi,
#|
Frank Buss's wrote:
(defun xor (&rest list)
(when list
(loop for (first . rest) on list
for i = 0 then (1+ i) do
(if first
(when (every #'null rest) (return (values first i)))))))
|#
How is this XOR? I don't get this definition.
(xor t t .... t) returns t,i, where i is the index of the last
argument.
For clarity, I use the definition of XOR with 2 arguments: only one and
at least one of its arguments is t, then it returns t, else nil.
What definition of multiple argument XOR do you use?
Greetings,
Michiel
"Michiel Borkent" <··············@gmail.com> writes:
> For clarity, I use the definition of XOR with 2 arguments: only one and
> at least one of its arguments is t, then it returns t, else nil.
>
> What definition of multiple argument XOR do you use?
a xor b xor c = ( a xor b ) xor c = a xor ( b xor c )
(defun xor (&rest args)
(flet ((xor2 (a b) (not (eq (not a) (not b)))))
(cond ((null args) t)
((null (cdr args)) (car args))
(t (apply (function xor) (xor2 (car args) (cadr args)) (cddr args))))))
(insert (karnaugh '(a b) (list (cons (quote xor) (function xor)))
'("NO" . "YES") '("NO" . "YES")))
+-----+-----+-----+
| a | b | xor |
+-----+-----+-----+
| YES | YES | NO |
| YES | NO | YES |
| NO | YES | YES |
| NO | NO | NO |
+-----+-----+-----+
(insert (karnaugh '(a b c) (list (cons (quote xor) (function xor)))
'("NO" . "YES") '("NO" . "YES")))
+-----+-----+-----+-----+
| a | b | c | xor |
+-----+-----+-----+-----+
| YES | YES | YES | YES |
| YES | YES | NO | NO |
| YES | NO | YES | NO |
| YES | NO | NO | YES |
| NO | YES | YES | NO |
| NO | YES | NO | YES |
| NO | NO | YES | YES |
| NO | NO | NO | NO |
+-----+-----+-----+-----+
(insert (karnaugh '(a b c d) (list (cons (quote xor) (function xor)))
'("NO" . "YES") '("NO" . "YES")))
+-----+-----+-----+-----+-----+
| a | b | c | d | xor |
+-----+-----+-----+-----+-----+
| YES | YES | YES | YES | NO |
| YES | YES | YES | NO | YES |
| YES | YES | NO | YES | YES |
| YES | YES | NO | NO | NO |
| YES | NO | YES | YES | YES |
| YES | NO | YES | NO | NO |
| YES | NO | NO | YES | NO |
| YES | NO | NO | NO | YES |
| NO | YES | YES | YES | YES |
| NO | YES | YES | NO | NO |
| NO | YES | NO | YES | NO |
| NO | YES | NO | NO | YES |
| NO | NO | YES | YES | NO |
| NO | NO | YES | NO | YES |
| NO | NO | NO | YES | YES |
| NO | NO | NO | NO | NO |
+-----+-----+-----+-----+-----+
--
__Pascal Bourguignon__ http://www.informatimago.com/
There is no worse tyranny than to force a man to pay for what he does not
want merely because you think it would be good for him. -- Robert Heinlein
Philippe Lorin wrote:
> Background: I need to check that two values are either both null or both
> non-null, and not a mix of null and non-null. I'd like to write:
> (assert (not (xor (null v1) (null v2))))
what about (eq (null v1) (null v2)) ?
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Philippe Lorin wrote:
> I'm looking for a XOR to use like I use AND and OR. But the only things
> I found in the CLHS are:
> BIT-XOR, which works on bit arrays
> BOOLE-XOR, which, when used with BOOLE, works on integers
> LOG-XOR, which works on integers
>
> CLisp seems to have XOR, but CMUCL and SBCL don't. Isn't there some
> standard function for this? Or am I wrong in wanting one?
>
> Background: I need to check that two values are either both null or both
> non-null, and not a mix of null and non-null. I'd like to write:
> (assert (not (xor (null v1) (null v2))))
Assuming v1 and v2 are boolean:
(xor v1 v2) == (not (eq v1 v2))
(xnor v1 v2) == (eq v1 v2)
So, in your case I would write:
(assert (eq (null v1) (null v2)))
As #'AND and #'OR are both macros that take any number of arguments,
I'm not sure that XOR really does fit in with them. However, it is
trivially implementable as a function because it must evaluate all of
its arguments.
Justin Dubs