predicate n. a function that returns a generalized boolean as its
first value.
Is that really supposed to be "generalized boolean" (nil and not-nil)
and not boolean (nil and t)?
Dutchman who Flies:
It makes sense to use generalized Booleans because they serve two purposes:
1) non-nils evaluate to 't'; and, at the same time,
2) non-nils do not destroy information.
It's common to use the result of a predicate if it evaluates to true, and the most efficient way to make that happen is to pass the value that causes the predicate to evaluate to true back to the calling function.
An example will illustrate. The 'member' function doesn't simply return 't' if it finds its key; it does this so that you can also get associated information. If the behavior of 'member' were coded more prosaically (by returning 't') then two member functions would have to be written to do the job of one, or the member function would have to have an additional flag argument indicating whether 't' should be returned or the non-nil found value. [Yes, I know 'member' is not a pure predicate function but CL is largely functional and there is large overlap between predicates and functions.]
Keep in mind that returning the non-nil value can be as efficient as returning 't'. In the above example, an (obfuscated) pointer is returned which takes up the same amount of space as 't' (i.e., one register). So there is no penalty in using this design.
I would be more befuddled if this design decision were *not* chosen.
> Is that really supposed to be "generalized boolean" (nil and not-nil)
> and not boolean (nil and t)?
Yes, it is. There is often useful information which can be returned in
the case when the result is non-NIL.
However, a lot of predicates are defined in CL to return a generalized
boolean without specifying anything more specific.
For these predicates, a conforming program cannot count on any specific
non NIL value.
IMO, generalized boolean should be seen, in general, as an optimization
device. They allow implementations to generate very efficient code for
predicates, notably on architectures that are register-deprived, since
the accumulator will generally contain a non NIL value when it should
return true.
More over, for operators such as <, an implementation that returns one
of the extrema parameters can use this fact for further optimize
expressions using it such as: (if (< a b) a b)
if (< a b) returns in the accumulator either a or b, then either branch
if the if form can be empty.
--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.
> However, a lot of predicates are defined in CL to return a generalized
> boolean without specifying anything more specific.
>
> For these predicates, a conforming program cannot count on any specific
> non NIL value.
I'm unclear why this could ever matter.
> More over, for operators such as <, an implementation that returns one
> of the extrema parameters can use this fact for further optimize
> expressions using it such as: (if (< a b) a b)
> if (< a b) returns in the accumulator either a or b, then either branch
> if the if form can be empty.
(if (< a b) a b)) is otherwise known as (min a b)
Yes. So the standard allow for efficient implementations of MIN :-)
Try to understand the wider message.
> Yes. So the standard allow for efficient implementations of MIN :-)
As it would if < was specified to return T/NIL, since a CL
implementation is free to use any tricks it wants in the implementation
of the function.
>
> Try to understand the wider message.
I have no idea what the wider message is. Obviously not insisting on
T/NIL but allowing generalised booleans is a good thing, even when the
specific non-NIL value is not specified.
Yes. So you can use that equivalent definition:
prediacte n, a function the name of which either ends with the
letter p or ends with some other character.
Well there might be a subtle difference:
min is defined for reals and returns reals
< is defined for numbers and can be used for complex numbers, too.
But that might not be a difference, and I might be unaware of other
subleties according to which that subtle difference does not exist.
A function returning no values would match your definition but not the
one of the spec.
Björn Lindberg
> < is defined for numbers and can be used for complex numbers, too.
Is that correct? The standard certainly says that, but it seems to me
a bit mad. It doesn't really give any semantics for complex numbers,
and I'm not sure what the semantics should be (I think comparing
absolute values would be wrong - perhaps comparing real parts?).
Well, this could be disputed: A function returning no value returns nil as
its primary value. I know that "first value" and "primary value" are not
exactly the same, but this doesn't make a difference in practice.
Suggestion:
predicate n, a function that returns a value and the name of which ends
with the character #\P or some other character.
Lots of times I'd hope the compiler could do the optimization even if
the function is specified to return an actual bool.
Yes.
CLHS on <:
Exceptional Situations:
Might signal type-error if some argument is not a real.
Might signal arithmetic-error if otherwise unable to fulfill its contract.
I guess, the imaginary part must then be zero.
When I asked the question I was just thinking about the fact that
other Lisps (I believe Clojure, Emacs Lisp, Scheme and ISLisp all
qualify) seem to reserve the term "predicate" for functions which
return either t or nil (or #t or #f or true or false). But as you
point out, since every value returned falls into the set of values of
a "generalized boolean" (nil or not-nil) it could be argued that every
Common Lisp function is a predicate. Or you could argue that any
function that could potentially return nil and any other value is a
predicate such as car, cdr, and even - (append). If "returns t or nil"
is not part of the definition then it seems like "makes a decision as
to whether some condition is true or false" should be.
> CLHS on <:
> Exceptional Situations:
> Might signal type-error if some argument is not a real.
> Might signal arithmetic-error if otherwise unable to fulfill its contract.
>
> I guess, the imaginary part must then be zero.
When playing with this I discovered something I never knew: #c(5 0) and
5 are the same (EQL) object and are RATIONALs.
Case in point: #'digit-char-p. I just remembered this function this
morning, after having written my own code for turning a hex character
into its corresponding integer value. A simple call to digit-char-p is
*obviously* better than the 8 lines of nicely-formatted, conventional
and ultimately completely unneccessary code that I came up with.
> But as you point out, since every value returned falls into the set of
> values of a "generalized boolean" (nil or not-nil) it could be argued
> that every Common Lisp function is a predicate.
This stems directly from CL treating NIL as false and any other value as
true. Since a predicate is just a function that returns a truth value,
every CL function *can* be seen as a predicate. But I don't see anything
wrong with that. (C does the same, only there 0 is the false value.)
> If "returns t or nil" is not part of the definition then it seems like
> "makes a decision as to whether some condition is true or false"
> should be.
But this is always an implication anyway, for any function capable of
returning NIL.
--
A change in perspective is worth 80 IQ points. --- Alan Kay
Well. I'd bet it *will* serve a purpose. You can post the code, and
come back to the thread 5 or 6 years from now to see what WJ has come
up with in Ruby, clojure, guile, scheme, or SLDJ :)
Cheers
--
Marco
I bet in a hundred years, some data archeologist will find his
posts and it'll be like a rosetta stone. "Oh, so THAT's how Ruby
was written!"
To which the next logical comment would be. "Eeewww".
:)
-pete
P.S. Try the veal.
"predicate" is clearly a human-oriented concept, not a machine-oriented
one. The definition is trying to use the technical term (boolean) to
indicate that the function answers a true/false question. And then adds
the "generalized" qualifier to clarify that true is not necessarily
indicated using T.
MEMBER is both a predicate and a searching function. You can use it
simply for its truth value, e.g. (if (member ...) ...), or you can use
it to find the tail of the list beginning with the element being
searched for.
--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
Ah, yezz... Good ol' "12.1.5.3 Rule of Canonical Representation for
Complex Rationals":
If the result of any computation would be a complex number whose
real part is of type rational and whose imaginary part is zero,
the result is converted to the rational which is the real part.
But while we are reviewing such minutia, it's good to remember that
this applies *only* if the real part is a rational, *not* a float:
This rule does not apply to complex numbers whose parts are floats.
For example, #C(5 0) and 5 are not different objects in Common Lisp
(they are always the same under EQL); #C(5.0 0.0) and 5.0 are always
different objects in Common Lisp they are never the same under EQL,
although they are the same under equalp and =).
And as "Function COMPLEX" points out, even a zero float imaginary part
is enough to trigger contagion on the entire number:
Examples:
...
(complex 3/2 0.0) => #C(1.5 0.0)
Similarly:
(read-from-string "#c(0 0.0)") => #C(0.0 0.0)
(read-from-string "#c(0.0 0)") => #C(0.0 0.0)
-Rob
-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <http://rpw3.org/>
San Mateo, CA 94403
>> [CL] MEMBER is both a predicate and a searching function.
>>
>Am I wrong in saying that in Scheme documentation they would not refer
>to a function like "member" as a predicate?
I think that's probably correct ... Scheme predicates return #T or #F,
but member returns a list if the object is found. It is potentially
confusing, though, because member returns #F if the object is not
found.
George
Yes, at least, Common Lisp is consistent here, and returns () when the
element is not found... But in scheme, () is true.
:) :)
>
> -pete
>
> P.S. Try the veal.
:) I'll do. But I don't understand the reference :)
I'm not sure either, but "Fawlty Towers" has an episode dealing
intensively with veal.
http://en.wikipedia.org/wiki/Basil_the_Rat
http://www.youtube.com/watch?v=VPP4P3gKGss
Warning: watch it only of a floor with a thick rug under you.
> Am I wrong in saying that in Scheme documentation they would not refer
> to a function like "member" as a predicate?
R^6RS says:
"A predicate is a procedure that always returns a boolean value (#t or #f)."
(so, no, you are not wrong)
>>
>> P.S. Try the veal.
>
> :) I'll do. But I don't understand the reference :)
People doing acts that approximate stand up comedy at mediocre hotels,
restaurants, or lounges often add the tag line "try the veal" because
in such restaurant acts the proprietor often has the comedian push
certain menu items. The fuller version is more like: "Thank you! I'll
be here all week; try the veal."
So the suggestion is that your line:
"I'd bet it *will* serve a purpose. You can post the code, and
come back to the thread 5 or 6 years from now to see what WJ has come
up with in Ruby, clojure, guile, scheme, or SLDJ :)"
is akin to a stand up comic's one-liner.
BTW, one also comonly hears "ba-dum ching" or sees <rimshot> [1] in the
same contexts, because the drummer in the band at these sorts of places
often plays a rimshot to punctuate each joke.
warmest regards,
Ralph
[1] apparently more properly referred to as a "sting" - who knew?
<http://en.wikipedia.org/wiki/Rimshot>
<http://en.wikipedia.org/wiki/Sting_(percussion)>
--
Raffael Cavallaro
Ok. I am a bad stand-up comedian :{
Cheers
--
Marco
> Ok. I am a bad stand-up comedian :{
Not bad - at least I thought your joke was very funny!
Nowadays the whole meme has been appropriated even by good comedians
when telling any joke that has the structure or format commonly used by
such lounge comedians - any pun or quick one-liner.
warmest regards,
Ralph
--
Raffael Cavallaro
Thanks :) I will be off to watch some "Big Bang Theory" :)
Cheers
--
Marco
>George Neuner <gneu...@comcast.net> writes:
>
>> On Mon, 28 Feb 2011 20:00:03 -0800 (PST), TheFlyingDutchman
>> <zzbb...@aol.com> wrote:
>>
>>>> [CL] MEMBER is both a predicate and a searching function.
>>>>
>>>Am I wrong in saying that in Scheme documentation they would not refer
>>>to a function like "member" as a predicate?
>>
>> I think that's probably correct ... Scheme predicates return #T or #F,
>> but member returns a list if the object is found. It is potentially
>> confusing, though, because member returns #F if the object is not
>> found.
>
>Yes, at least, Common Lisp is consistent here, and returns () when the
>element is not found... But in scheme, () is true.
Personally, I think CL handles booleans wrong too. I really like the
notion that boolean is a distinct type with distinct true and false
values ... it occasionally forces an explicit test to satisfy the
compiler, but it avoids a whole host of semantic problems in the most
common case of dealing with binary YES/NO logic.
I just wish Scheme actually followed through on its own design advice.
IMO, functions such as member should multiple return the boolean
result, found or not found, and the list, empty or not. But the basic
library functions - in Scheme at least - predate (values). Of course
R6RS is mostly incompatible with previous versions anyway, so IMO the
committee should have taken the opportunity to redefine stupid library
functions.
George
OK, that sounds reasonable at first glance...
> ... it occasionally forces an explicit test to the compiler
Yeah, that. (See below.)
> but it avoids a whole host of semantic problems in the most common
> case of dealing with binary YES/NO logic.
Can you provide some more details about what "semantic problems" you
have in mind?
Cause mostly, it just makes me think of this wonderful poem from a
couple of decades ago (appended below).
-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org/ d...@geddis.org
-------------------------------------------------------------------------------
A Short Ballad Dedicated to the Growth of Programs
Date: 28 Jan 86 06:22:59 EST (Tue)
From: ram@yale-ring
Subject: Of growing code and diminishing hacks...
Sender: ram%yale-ring%arpa...@edu.mit.lcs.mc
To: t-disc...@arpa.yale, sch...@arpa.mit-mc
A SHORT BALLAD DEDICATED TO THE GROWTH OF PROGRAMS
==================================================
by
Ashwin Ram
This is a tale of a sorry quest
To master pure code at the T guru's behest
I enrolled in a class that appealing did seem
For it promised to teach fine things like T3 and Scheme
The first day went fine; we learned of cells
And symbols and lists and functions as well
Lisp I had mastered and excited was I
For to master T3 my hackstincts did cry
I sailed through the first week with no problems at all
And I even said "closure" instead of "function call"
Then said the master that ready were we
To start real hacking instead of simple theory
Will you, said he, write me a function please
That in lists would associate values with keys
I went home and turned on my trusty Apollo
And wrote a function whose definition follows:
(cdr (assq key a-list))
A one-liner I thought, fool that I was
Just two simple calls without a COND clause
But when I tried this function to run
CDR didn't think that NIL was much fun
So I tried again like the good King of yore
And of code I easily generated some more:
(cond ((assq key a-list) => cdr))
It got longer but purer, and it wasn't too bad
But then COND ran out and that was quite sad
Well, that isn't hard to fix, I was told
Just write some more code, my son, be bold
Being young, not even a moment did I pause
I stifled my instincts and added a clause
(cond ((assq key a-list) => cdr)
(else nil))
Sometimes this worked and sometimes it broke
I debugged and prayed and even had a stroke
Many a guru tried valiantly to help
But undefined datums their efforts did squelch.
I returneth once more to the great sage of T
For no way out of the dilemma I could see
He said it was easy -- more lines must I fill
with code, for FALSE was no longer NIL.
(let ((val (assq key a-list)))
(cond (val (cdr val))
(else nil)))
You'd think by now I might be nearing the end
Of my ballad which seems bad things to portend
You'd think that we could all go home scot-free
But COND eschewed VAL; it wanted #T
So I went back to the master and appealed once again
I said, pardon me, but now I'm really insane
He said, no you're not really going out of your head
Instead of just VAL, you must use NOT NULL instead
(let ((val (assq key a-list)))
(cond ((not (null? val)) (cdr val))
(else nil)))
My song is over and I'm going home to bed
With this ineffable feeling that I've been misled
And just in case my point you have missed
Somehow I preferred (CDR (ASSQ KEY A-LIST))
:-)
==================================================
-------------------------------------------------------------------------------
>George Neuner <gneu...@comcast.net> wrote on Tue, 01 Mar 2011:
>> I really like the notion that boolean is a distinct type with distinct
>> true and false values
>
>OK, that sounds reasonable at first glance...
>
>> ... it occasionally forces an explicit test to the compiler
>
>Yeah, that. (See below.)
>
>> but it avoids a whole host of semantic problems in the most common
>> case of dealing with binary YES/NO logic.
>
>Can you provide some more details about what "semantic problems" you
>have in mind?
Hi Don.
Sorry for the delay - I've was traveling most of last week and haven't
been keeping up with the newsgroups.
I'm sure you've heard this before, so if you think I'm cracked, don't
worry ... you're not the only one 8-)
Understand that my feelings about "generalized booleans" are, shall we
say, "enhanced" by near daily exposure to the bad implementation in
C(++), but I have long past the point where even Lisp's (fairly well)
sanitized version irritates me. It's become one of my big peeves
regarding language design - largely because I see the crop of wannabe
languages (Ruby,Python,etc.) making the same mistakes all over again.
My opinions also are shaped by many years working on embedded and high
availability systems where software crashes simply are not tolerated.
Companies losing many (tens of) thousands of dollars per minute to
downtime are not shy about badmouthing and suing the equipment vendors
- if the mission critical system you provided isn't working, forget
software bugs ... the computer had better be on fire.
So I am all about robust, correct code and through those glasses I see
generalized booleans as 1% programmer convenience, 99% programmer
pitfall. As far as I'm concerned, treating arbitrary values as
boolean just provides opportunities for an unwary programmer to
introduce control logic errors by coding an incorrect test.
[And yes, the problem really is the making of logic errors rather than
semantic ones, but these particular logic errors are only possible
because of the semantics of the conditional form.]
Clearly it is shorter to type "(if obj ..." - or whatever conditional
form floats your boat - then the equivalent "(if (not (eq obj nil))
...". The shorthand is fine if that is exactly what you meant for the
test to be. Lisp - or at least CL - defines what will happen in this
circumstance. It's less clear what will happen when the test involves
a function call or macro expansion: things like the SETF macro can't
be relied on to return anything meaningful ... the result depends on
the update form. So coding something like (if (setf x (...)) ... )
might make demons fly out of your nose. Lisp doesn't really have
separately compilable modules, but that could be worse if, with latent
types, the compiler had no way of determining if a return value was
present [think returning (values)].
[I'm also firmly in the manifest typing camp - not for runtime
efficiency (though that's a perk) - but simply because I think the
compiler should help me as much as possible by catching obvious
mistakes and I am not yet convinced that type inferencing is fully
sound. I prefer the term "manifest" to "static" because I know some
typing has to done latently at runtime, but I prefer to see the
possibilities directly expressed in the source. I'm content that
others have different preferences so long as we're not going blind
looking for the reason "compatible" code won't integrate.]
Scheme took a step in the right direction by introducing a boolean
type distinct from null (nil), but then blew it by (sort of) copying
Lisp's generalized booleans, permitting conditional tests to evaluate
to #F/not-#F, rather than strictly to #F/#T.
[The poem's (CDR (ASSQ KEY A-LIST)) does't work because ASSQ returns
#F if the key is not found. null is not false. Also, in Scheme, null
and '() satisfy LIST?, but do not satisfy PAIR? and so CDR will not
accept them.]
Of course, the situation is much worse in C(++) which conflates
booleans with numbers and where mistyping a certain logical operator
turns the expression from a comparison into an assignment. Worse yet,
any built-in numeric type - as well as pointers and references - may
be used as zero/non-zero boolean. Python copied the zero/nonzero
nonsense and then further confused the issue by creating unique
"false" values for every other built-in type and even letting the
programmer override the handling of "true" values.
I've arrived at the point where I think the syntax of a conditional
form [in whatever language] should force an explicitly coded test that
evaluates to true/false. Let the compiler worry about optimization.
YMMV.
>Cause mostly, it just makes me think of this wonderful poem from a
>couple of decades ago (appended below).
Cute!
> -- Don
George
(defmacro bif ( condition then &optional else)
`(let ( (result ,condition ) )
(if (not (or (eq result t) (eq result nil)))
(error "error using bif: condition result is not boolean"))
(cond
(result ,then)
(t ,else))))
Your macro secretly binds variable RESULT which user certainly doesn't
expect.
(let ((result "my value"))
(bif t result "else"))
=> T ; But "my value" expected.
Create an uninterned symbol for your macro so it can't be seen
elsewhere. You can do that with GENSYM (or MAKE-SYMBOL). Here's a
version which fixes the binding problem and signals a correctable error
with ASSERT.
(defmacro bif (test then &optional else)
(let ((result (gensym)))
`(let ((,result ,test))
(assert (or (not ,result)
(eql ,result t))
(,result)
"Test didn't evaluate to T or NIL: ~S." ,result)
(if ,result ,then ,else))))
> If this a valid Common Lisp "boolean if"?
No, or at least it is not good style, because it binds RESULT.
Something like this avoids that and is also perhaps clearer:
(defmacro absurdly-fussy-if (c true &optional false)
(let ((cn (make-symbol "C")))
`(let ((,cn ,c))
(etypecase ,cn
(boolean
(if ,cn ,true ,false))))))
> George Neuner <gneu...@comcast.net> writes:
>
> > On Mon, 28 Feb 2011 20:00:03 -0800 (PST), TheFlyingDutchman
> > <zzbb...@aol.com> wrote:
> >
> >>> [CL] MEMBER is both a predicate and a searching function.
> > > >
> > > Am I wrong in saying that in Scheme documentation they would not refer
> > > to a function like "member" as a predicate?
> >
> > I think that's probably correct ... Scheme predicates return #T or #F,
> > but member returns a list if the object is found. It is potentially
> > confusing, though, because member returns #F if the object is not
> > found.
>
> Yes, at least, Common Lisp is consistent here, and returns () when the
> element is not found... But in scheme, () is true.
So? Scheme is consistent.
guile> (member 'd '(a b #f c))
#f
guile> (member #f '(a b #f c))
(#f c)
guile> (if (member #f '(a b #f c)) 'yes 'no)
yes
guile> (if (member 'd '(a b #f c)) 'yes 'no)
no
Not confusing. If member succeeds, the value returned is non-false.
If it fails, the returned value is false.
Anything other than #f can be used instead of #t by a predicate
to indicate success.
(defmacro absurdly-fussy-if-but-probably-more-efficient (c true &optional false)
(let ((cn (gensym)))
`(let ((,cn ,c))
(case ,cn
((t) ,true)
((nil) ,false)
(otherwise (error "~S expected a boolean, instead of the generalized boolean ~S"
'absurdly-fussy-if-but-probably-more-efficient ,cn))))))
It also issues a better error message.
CL-USER> (disassemble (compile nil (lambda () (ABSURDLY-FUSSY-IF (get-some-bool) (print 'true) (print 'false)))))
WARNING: Function GET-SOME-BOOL is not defined
Disassembly of function NIL
(CONST 0) = GET-SOME-BOOL
(CONST 1) = TRUE
(CONST 2) = FALSE
(CONST 3) = #:C
(CONST 4) = (BOOLEAN)
(CONST 5) = SYSTEM::TYPECASE-ERROR-STRING
(CONST 6) = (OR BOOLEAN)
(CONST 7) = SYSTEM::ETYPECASE-FAILED
0 required arguments
0 optional arguments
No rest parameter
No keyword parameters
25 byte-code instructions:
0 (CALL0 0) ; GET-SOME-BOOL
2 (PUSH)
3 (LOAD&JMPIFNOT 0 L10)
6 (LOAD&PUSH 0)
7 (T)
8 (JMPIFNOTEQ L24)
10 L10
10 (LOAD&JMPIF 0 L21)
13 (CONST 2) ; FALSE
14 L14
14 (PUSH)
15 (PUSH-UNBOUND 1)
17 (CALLS1 142) ; PRINT
19 (SKIP&RET 2)
21 L21
21 (CONST 1) ; TRUE
22 (JMP L14)
24 L24
24 (LOAD&PUSH 0)
25 (CONST&PUSH 3) ; #:C
26 (CONST&PUSH 4) ; (BOOLEAN)
27 (CALL2&PUSH 5) ; SYSTEM::TYPECASE-ERROR-STRING
29 (CONST&PUSH 6) ; (OR BOOLEAN)
30 (CALL 3 7) ; SYSTEM::ETYPECASE-FAILED
33 (SKIP&RET 2)
NIL
CL-USER> (disassemble (compile nil (lambda () (ABSURDLY-FUSSY-IF-BUT-PROBABLY-MORE-EFFICIENT (get-some-bool) (print 'true) (print 'false)))))
WARNING: Function GET-SOME-BOOL is not defined
Disassembly of function NIL
(CONST 0) = GET-SOME-BOOL
(CONST 1) = TRUE
(CONST 2) = FALSE
(CONST 3) = "~S expected a boolean, instead of the generalized boolean ~S"
(CONST 4) = ABSURDLY-FUSSY-IF-BUT-PROBABLY-MORE-EFFICIENT
0 required arguments
0 optional arguments
No rest parameter
No keyword parameters
20 byte-code instructions:
0 (CALL0 0) ; GET-SOME-BOOL
2 (PUSH)
3 (LOAD&PUSH 0)
4 (T)
5 (JMPIFEQ L18)
7 (LOAD&JMPIF 0 L21)
10 (CONST 2) ; FALSE
11 L11
11 (PUSH)
12 (PUSH-UNBOUND 1)
14 (CALLS1 142) ; PRINT
16 (SKIP&RET 2)
18 L18
18 (CONST 1) ; TRUE
19 (JMP L11)
21 L21
21 (CONST&PUSH 3) ; "~S expected a boolean, instead of the generalized boolean ~S"
22 (CONST&PUSH 4) ; ABSURDLY-FUSSY-IF-BUT-PROBABLY-MORE-EFFICIENT
23 (LOAD&PUSH 2)
24 (CALLSR 2 30) ; ERROR
NIL
"8 lines" of code? COBOL is insanely prolix. I guess that's why
the pompous and pretentious love it so.
Using Scheme:
guile> (define (hexc->num c) (string-index "0123456789abcdef" c))
guile> (hexc->num #\c)
12
guile> (hexc->num #\0)
0
guile> (hexc->num #\9)
9
guile> (hexc->num #\f)
15
Of course, you would actually use this:
guile> (string->number "f")
#f
guile> (string->number "f" 16)
15
> TheFlyingDutchman <zzbb...@aol.com> writes:
>
> > But as you point out, since every value returned falls into the set of
> > values of a "generalized boolean" (nil or not-nil) it could be argued
> > that every Common Lisp function is a predicate.
>
> This stems directly from CL treating NIL as false and any other value as
> true. Since a predicate is just a function that returns a truth value,
> every CL function can be seen as a predicate. But I don't see anything
> wrong with that. (C does the same, only there 0 is the false value.)
>
MatzLisp (Ruby) is similar. The only two things that are not true
are nil and false.
> (defmacro absurdly-fussy-if-but-probably-more-efficient (c true
> &optional false)
> (let ((cn (gensym)))
> `(let ((,cn ,c))
> (case ,cn
> ((t) ,true)
> ((nil) ,false)
> (otherwise (error "~S expected a boolean, instead of the
> generalized boolean ~S"
> 'absurdly-fussy-if-but-probably-more-efficient ,cn))))))
My theory was that my version would signal some kind of type-error
which is what this really is (obviously yours can be changed to do this
trivially), and also typecase might be something a type-inferencing
compiler can do useful things with, but then it can probably do things
with case as well. Yours is clearer, for sure.
> Also, in Scheme, null
> and '() satisfy LIST?, but do not satisfy PAIR? and so CDR will not
> accept them.]
null is unknown to Guile Scheme and Bigloo Scheme.
> Using Scheme:
>
> guile> (define (hexc->num c) (string-index "0123456789abcdef" c))
You probably actually mean this
(define (hexc->integer c)
(string-index "0123456789abcdef"
(lambda (cc)
(char-ci=? c cc))))
or in CL:
(defun hexc->integer (c)
(position c "0123456789abcdef"
:test #'char-equal))
Which is only a little clearer.
> George Neuner <gneu...@comcast.net> wrote on Tue, 01 Mar 2011:
> > I really like the notion that boolean is a distinct type with distinct
> > true and false values
>
> OK, that sounds reasonable at first glance...
>
> > ... it occasionally forces an explicit test to the compiler
>
> Yeah, that. (See below.)
>
> > but it avoids a whole host of semantic problems in the most common
> > case of dealing with binary YES/NO logic.
>
> Can you provide some more details about what "semantic problems" you
> have in mind?
>
> Cause mostly, it just makes me think of this wonderful poem from a
> couple of decades ago (appended below).
>
> -- Don
> ____________________________________________________________________________
> ___ Don Geddis http://don.geddis.org/
> d...@geddis.org
>
> ----------------------------------------------------------------------------
> --- A Short Ballad Dedicated to the Growth of Programs
Using Guile Scheme:
(define a-list '((foo . 22) (bar . 44) (baz . #f)))
(define (look key alist)
(cond ((assoc key alist) => cdr)
(else #f)))
guile> (look 'bar a-list)
44
guile> (look 'baz a-list)
#f
guile> (look 'bazzy a-list)
#f
If the value found is #f, you won't know whether it was found
or not.
For a one-liner, just make sure that cdr always has something
valid upon which to work:
guile> (cdr (or (assoc 'gloomy a-list) '(0 . #f)))
#f
guile> (cdr (or (assoc 'foo a-list) '(0 . #f)))
22
guile> (cdr (or (assoc 'baz a-list) '(0 . #f)))
#f
guile> (cdr (or (assoc 'bar a-list) '(0 . #f)))
44
>
> For a one-liner, just make sure that cdr always has something
> valid upon which to work:
>
> guile> (cdr (or (assoc 'gloomy a-list) '(0 . #f)))
> #f
> guile> (cdr (or (assoc 'foo a-list) '(0 . #f)))
> 22
> guile> (cdr (or (assoc 'baz a-list) '(0 . #f)))
> #f
> guile> (cdr (or (assoc 'bar a-list) '(0 . #f)))
> 44
guile> (cdr (or (assoc 'gloomy a-list) '(_ . #f)))
#f
ie.
(bif (= 2 a) (dostuff))
would not generate code that has a bare "nil" sitting as one branch of
an if/case/cond?
How about
(defmacro minimal-code-if (test-form
then-form
&optional
(else-form nil else-form-p))
(if else-form-p
`(if ,test-form ,then-form ,else-form)
`(if ,test-form ,then-form)))
or
(defmacro minimal-code-if (test-form
then-form
&optional
(else-form nil else-form-p))
`(if ,test-form ,then-form
,@(when else-form-p
(list else-form))))
CL-USER> (macroexpand '(minimal-code-if x a b))
(IF X A B)
T
CL-USER> (macroexpand '(minimal-code-if x a))
(IF X A)
T
?
That does the trick! Thanks.
I am thinking they mean the exact same thing.
What does the compiler do with the first that is different from what it
does with the second?
-Antony
Nothing.
CL-USER> (disassemble (compile nil (lambda (x y z) (if x y z))))
Disassembly of function NIL
3 required arguments
0 optional arguments
No rest parameter
No keyword parameters
6 byte-code instructions:
0 (LOAD&JMPIF 3 L6)
3 (LOAD 1)
4 (SKIP&RET 4)
6 L6
6 (LOAD 2)
7 (SKIP&RET 4)
NIL
CL-USER> (disassemble (compile nil (lambda (x y z) (if (not (null x)) y z))))
Disassembly of function NIL
3 required arguments
0 optional arguments
No rest parameter
No keyword parameters
6 byte-code instructions:
0 (LOAD&JMPIF 3 L6)
3 (LOAD 1)
4 (SKIP&RET 4)
6 L6
6 (LOAD 2)
7 (SKIP&RET 4)
NIL
CL-USER> (disassemble (compile nil (lambda (x y z) (if (not (eq x nil)) y z))))
Disassembly of function NIL
3 required arguments
0 optional arguments
No rest parameter
No keyword parameters
6 byte-code instructions:
0 (LOAD&JMPIF 3 L6)
3 (LOAD 1)
4 (SKIP&RET 4)
6 L6
6 (LOAD 2)
7 (SKIP&RET 4)
NIL
CL-USER>
Question: is this your CL compiler assembly output?
Cheers
--
MA
> On Mar 10, 4:56 pm, "Pascal J. Bourguignon" <p...@informatimago.com>
> wrote:
>> CL-USER> (disassemble (compile nil (lambda (x y z) (if (not (eq x nil)) y z))))
>>
>> Disassembly of function NIL
>> 3 required arguments
>> 0 optional arguments
>> No rest parameter
>> No keyword parameters
>> 6 byte-code instructions:
>> 0 (LOAD&JMPIF 3 L6)
>> 3 (LOAD 1)
>> 4 (SKIP&RET 4)
>> 6 L6
>> 6 (LOAD 2)
>> 7 (SKIP&RET 4)
>> NIL
>
> Question: is this your CL compiler assembly output?
Yes. One advantage of clisp is that it has a (virtual) lisp machine
with a nice assembler code.