From: Luke J Crook
Subject: Getting rid of nil's in a macro ?
Date: 
Message-ID: <2L9Lb.43318$C87.2804@twister.socal.rr.com>
I am attempting to write a macro that generates the clauses in a COND

I do this using a mapcar..

`(cond
   ,@(mapcar #'(lambda (event)
             (cond
                ((eql mouseup t)
                   `((eql...
                ((eql mousedown t)
                   `((eql...
                ...
              ))
             list-of-events))

..passing it a list-of-events and having it generate the corresponding
clause. My problem is that the lambda will return NIL
when no clause is generated, obviously. mapcar then cons this result
onto the result list. This tends to mess up my COND, interspersing the
clauses with NIL.

Is there a way I can have mapcar not add NIL to the list of
results ? Or have the lambda not return a nil ? Or am I approaching
this the wrong way ?

To overcome this I am 'pre-processing' whereby I build the clauses using:

(setf event-forms (remove nil
   (mapcar #'(lambda (event)
             (cond
                ((eql mouseup t)
                   `((eql...
                ((eql mousedown t)
                   `((eql...
                ...
              ))
             list-of-events))))

and then splicing event-forms into the macro:

`(cond
	,@event-forms)

Is there an easier way ?

From: Kaz Kylheku
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <cf333042.0401081131.65fda21c@posting.google.com>
Luke J Crook <······@NO-SPAM.hd-plus.com> wrote in message news:<····················@twister.socal.rr.com>...
> I am attempting to write a macro that generates the clauses in a COND
> 
> I do this using a mapcar..
> 
> `(cond
>    ,@(mapcar #'(lambda (event)
>              (cond
>                 ((eql mouseup t)
>                    `((eql...
>                 ((eql mousedown t)
>                    `((eql...
>                 ...
>               ))
>              list-of-events))

One way to do this while remaining in the current paradigm, is to use
MAPCAN instead of MAPCAR, and modify your lambda so it places its
intended result value in a one-element list:

   (mapcan #'(lambda (event)
               (cond
                 ((eql mouseup t)
                  (list `((eql ...)))
                  ...)))

MAPCAN catenates the outputs of the function (which it does
destructively, as if by NCONC!) Any NIL results are then empty lists
which disappear in the splicing.

> To overcome this I am 'pre-processing' whereby I build the clauses using:
> 
> (setf event-forms (remove nil
>    (mapcar #'(lambda (event)
>              (cond
>                 ((eql mouseup t)
>                    `((eql...
>                 ((eql mousedown t)
>                    `((eql...
>                 ...
>               ))
>              list-of-events))))

Of course you could do this without the variable

  `(cond ,@(remove nil (mapcar ...))))

I like best the LOOP based solutions elsewhere in the thread.
From: Alexander Schmolck
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <yfsd69uwj21.fsf@black132.ex.ac.uk>
Luke J Crook <······@NO-SPAM.hd-plus.com> writes:

> Is there a way I can have mapcar not add NIL to the list of
> results 

Switch to maplist / mapcon?

'as
From: Frode Vatvedt Fjeld
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <2hekuah3ls.fsf@vserver.cs.uit.no>
Luke J Crook <······@NO-SPAM.hd-plus.com> writes:

> Is there a way I can have mapcar not add NIL to the list of results
> ? Or have the lambda not return a nil ?

No there is no way to do this. What you do is use mapcan instead, and
have the lambda return (list foo) if it is to add foo to the result,
or nil if it is to add nothing. Or (list foo bar) to add both foo and
bar, and so on. I.e. the results are concatenated. Just make sure
you're returning fresh lists from the lambda.

> Or am I approaching this the wrong way ?

An alternative idiom is something like this

  (loop for ...
     when (this-iteration-needs-to-add-something)
     collect (generate-something))

Or, if you know that the result should never contain nil:

  (loop for ...
     when (generate-something)
     collect it)

-- 
Frode Vatvedt Fjeld
From: Luke J Crook
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <vWtLb.52325$nG3.20025@twister.socal.rr.com>
Frode Vatvedt Fjeld wrote:

  >
> An alternative idiom is something like this
> 
>   (loop for ...
>      when (this-iteration-needs-to-add-something)
>      collect (generate-something))
> 
> Or, if you know that the result should never contain nil:
> 
>   (loop for ...
>      when (generate-something)
>      collect it)
> 

I had actually held off using loop (for better or worse) until I had 
more of a feel for Lisp. To me, the loop seems more of an embedded 
language within Lisp.. a language for performing loops.

Your description is more readable than mapcar. I suppose it's time I 
took the plunge.

Thanks.
-Luke
From: Ivan Toshkov
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <btjsbj$7up0s$1@ID-207269.news.uni-berlin.de>
Luke J Crook wrote:
> I am attempting to write a macro that generates the clauses in a COND
> 
> I do this using a mapcar..
> 
> `(cond
>   ,@(mapcar #'(lambda (event)
>             (cond
>                ((eql mouseup t)
>                   `((eql...
>                ((eql mousedown t)
>                   `((eql...
>                ...
>              ))
>             list-of-events))
> 
> ..passing it a list-of-events and having it generate the corresponding
> clause. My problem is that the lambda will return NIL
> when no clause is generated, obviously. mapcar then cons this result
> onto the result list. This tends to mess up my COND, interspersing the
> clauses with NIL.
> 
> Is there a way I can have mapcar not add NIL to the list of
> results ? Or have the lambda not return a nil ? Or am I approaching
> this the wrong way ?
> 
> To overcome this I am 'pre-processing' whereby I build the clauses using:
> 
> (setf event-forms (remove nil
>   (mapcar #'(lambda (event)
>             (cond
>                ((eql mouseup t)
>                   `((eql...
>                ((eql mousedown t)
>                   `((eql...
>                ...
>              ))
>             list-of-events))))
> 
> and then splicing event-forms into the macro:
> 
> `(cond
>     ,@event-forms)
> 
> Is there an easier way ?
> 
> 

Why not getting rid of the event-forms, like this:
`(cond
    ,@(remove nil (mapcar ....)))

You can create a special purpose mapcar (perhaps using reduce), which 
does not include NILs, but in macros this frequently is not needed, 
because they run in compilation (macroexpansion) time.

HTH,
Ivan
-- 
All we are saying 		| Ivan Toshkov
Is give Lisp a chance 		| email: ··········@last-name.org
From: Luke J Crook
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <sHtLb.52320$nG3.45164@twister.socal.rr.com>
Ivan Toshkov wrote:
> Luke J Crook wrote:
> 
>> (setf event-forms (remove nil
>>   (mapcar #'(lambda (event)
>>             (cond
>>                ((eql mouseup t)
>>                   `((eql...
>>                ((eql mousedown t)
>>                   `((eql...
>>                ...
>>              ))
>>             list-of-events))))
>>
>> and then splicing event-forms into the macro:
>>
>> `(cond
>>     ,@event-forms)
>>
>> Is there an easier way ?
>>
>>
> 
> Why not getting rid of the event-forms, like this:
> `(cond
>    ,@(remove nil (mapcar ....)))
> 

For some reason I completely missed this.
From: Gareth McCaughan
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <87wu828gtc.fsf@g.mccaughan.ntlworld.com>
Luke J Crook <······@NO-SPAM.hd-plus.com> writes:

> Is there a way I can have mapcar not add NIL to the list of
> results ? Or have the lambda not return a nil ? Or am I approaching
> this the wrong way ?

As others have suggested, you should be using MAPCAN
or LOOP-with-WHEN or something of the sort. But I have
an incidental comment:

>              (cond
>                 ((eql mouseup t)
>                    `((eql...

Can MOUSEUP here have any value other than T and NIL?
If not, it would be more idiomatic to replace
(EQL MOUSEUP T) with just MOUSEUP, etc.

-- 
Gareth McCaughan
.sig under construc
From: Frode Vatvedt Fjeld
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <2h65fmgvrb.fsf@vserver.cs.uit.no>
Gareth McCaughan <················@pobox.com> writes:

> Can MOUSEUP here have any value other than T and NIL?

Of course. In Common Lisp, "false" is NIL, and "true" is any other
value than NIL.

-- 
Frode Vatvedt Fjeld
From: Gareth McCaughan
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <873caq82ww.fsf@g.mccaughan.ntlworld.com>
Frode Vatvedt Fjeld wrote:

> Gareth McCaughan <················@pobox.com> writes:
> 
>> Can MOUSEUP here have any value other than T and NIL?
> 
> Of course. In Common Lisp, "false" is NIL, and "true" is any other
> value than NIL.

I think you misunderstood the point of my question. In case
the original poster did too, I'll clarify.

The original poster has some code in which some variables
with names like MOUSEUP and MOUSEDOWN (apparently derived
from fields in some sort of event object) are compared
explicitly against T. Precisely *because* plenty of values
other than T are considered true in Common Lisp, explicit
comparisons against T are a (weak) danger sign, because ...

  1 If the intention is to test whether the value
    is "true", and if there is any possibility that
    whatever-it-is that is generating the values
    (in this case, presumably a library that does
    something with events) might ever produce a
    true value other than T, then explicit comparison
    against T can give the wrong answer.

    For instance, maybe some (present or future)
    version of the library might say that MOUSEUP
    is NIL if the event wasn't a mouse-up event,
    but if it *was* then it contains a value that
    identifies which mouse button was un-clicked.

  2 If there is no possibility that any value other
    than T or NIL will ever be produced, then it will
    do no positive harm to compare against T, but it
    will do no good either. By writing (EQL MOUSEUP T)
    instead of just MOUSEUP, you require a bunch of
    extra keystrokes, you potentially take up extra
    space on the screen, and you make your readers
    work harder.

The only case where explicit comparison against T
is sensible is where whatever produces the values
*can* sometimes produce something that's neither
T nor NIL, *and* you want to treat T one way and
(NIL and all the non-T true values) the other way.
That's a pretty weird sort of situation, and should
probably be made clearer in the code, either with
a comment or by defining a function with an enlightening
name that checks (EQL MOUSEUP T) or whatever.

The same thing happens in other languages; experienced
C programmers wince when they see things like

    if (can_access(name) == TRUE) { ... }

for exactly the same reasons as experienced CL programmers
wince when they see

    (when (eql (can-access name) t) ...)

-- 
Gareth McCaughan
.sig under construc
From: Luke J Crook
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <XOtLb.52323$nG3.16594@twister.socal.rr.com>
Gareth McCaughan wrote:

> Luke J Crook <······@NO-SPAM.hd-plus.com> writes:
> 
> 
> But I have
> an incidental comment:
> 
> 
>>             (cond
>>                ((eql mouseup t)
>>                   `((eql...
> 
> 
> Can MOUSEUP here have any value other than T and NIL?
> If not, it would be more idiomatic to replace
> (EQL MOUSEUP T) with just MOUSEUP, etc.
> 

Actually, the macro looks something like this:

(cond
   ((eql (first event)
        :quit)
     `((eql...
   ((eql (first event)
        :keypress)
     `((eql...
   ...)

Where (first event) is the event keyword identifier, i.e. :quit, 
:mousebutton-down, :mouse-motion etc.

I simplified my first post bit too much, I think. I didn't want to come 
across as 'hey, write this macro for me'.

-Luke
From: Ivan Toshkov
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <btlt5l$8m64e$1@ID-207269.news.uni-berlin.de>
Luke J Crook wrote:
> Actually, the macro looks something like this:
> 
> (cond
>   ((eql (first event)
>        :quit)
>     `((eql...
>   ((eql (first event)
>        :keypress)
>     `((eql...
>   ...)
> 
> Where (first event) is the event keyword identifier, i.e. :quit, 
> :mousebutton-down, :mouse-motion etc.
> 
> I simplified my first post bit too much, I think. I didn't want to come 
> across as 'hey, write this macro for me'.
> 
> -Luke

Maybe 'case' would be more readable than 'cond' in this case.

-- 
Ivan Toshkov

email: ··········@last-name.org
From: Kenny Tilton
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <qxiLb.178319$0P1.2280@twister.nyc.rr.com>
Luke J Crook wrote:
> I am attempting to write a macro that generates the clauses in a COND
> 
> I do this using a mapcar..
> 
> `(cond
>   ,@(mapcar #'(lambda (event)
>             (cond
>                ((eql mouseup t)
>                   `((eql...
>                ((eql mousedown t)
>                   `((eql...
>                ...
>              ))
>             list-of-events))
> 
> ..passing it a list-of-events and having it generate the corresponding
> clause. My problem is that the lambda will return NIL
> when no clause is generated, obviously.

Why? Does list-of-events contain nils? Some events get no handling? You 
can still generate empty handlers for those. But I have other Qs:

    (eql mouseup t)?

To what is mouseup bound? And where is the event parameter used? At 
run-time, how will a mouseup event be represented? As a symbol? A 
structure or CLOS instance of type 'mouseup?

How would this macro be used? Something like:

    (events-worry-about event (mouseup mousedown diskInsert))?

Why is this a macro, btw? Are you also tailoring the handling:

    (events-handle event
       (mouseup (do-this))
       (mousedown (do-that))?

But that could be a case or typecase. Well, I'm guessing too much.

Others explained how to lose nils -- (delete nil ...) is not too shabby 
-- but I see more issues, including probably no reason for nils even to 
appear in the expansion (if you need a macro!)>

kt

-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film

Your Project Here! http://alu.cliki.net/Industry%20Application
From: Luke J Crook
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <6YpLb.51585$nG3.1140@twister.socal.rr.com>
Kenny Tilton wrote:
> 
> 
> Why? Does list-of-events contain nils? Some events get no handling? You 
> can still generate empty handlers for those. But I have other Qs:

I seemed to have erred on the side brevity.

> 
> How would this macro be used? Something like:
> 
>    (events-worry-about event (mouseup mousedown diskInsert))?
> 
> Why is this a macro, btw? Are you also tailoring the handling:
> 
>    (events-handle event
>       (mouseup (do-this))
>       (mousedown (do-that))?
> 
> But that could be a case or typecase. Well, I'm guessing too much.

You are pretty much spot on. I am trying to move some very messy event 
handling code into something that looks like the code below, using macros.

(with-sdl-events
   (:quit (q)
       (setf q t))
   (:mousebuttonup (state x y xrel yrel)
       (look-mom-the-mousebutton-is-up))
   (:idle
       (and-here-are)
       (forms-that-are-executed)
       (when-there-are-no-events)
       (in-the-event-queue)))

Here, :idle is treated like an event, but is not an event as these forms 
are placed after the processing of the event loop. So the #'(lambda that 
tests for events retuns nil for :idle.

The original code is below (Corman Lisp).

(do ()
     ((eql quit t))

     ;Check for SDL Events. Exit on quit.
     (do ((poll-event 1 (sdl:SDL_PollEvent sdl-event)))
         ((eql poll-event 0) 'done)
         (cond
             ((eql sdl:SDL_QUIT
                  (ct:cref sdl:SDL_Event sdl-event sdl::type))
                 (setf quit t))
             ((eql sdl:SDL_KEYDOWN (ct:cref sdl:SDL_Event
                                            sdl-event sdl::type))
                 (handle-key-down (ct:cref sdl:SDL_KeyboardEvent
                                            sdl-event sdl::keysym)))))
     ;; Do stuff here
      (and-here-are)
      (forms-that-are-executed)
      (when-there-are-no-events)
     (in-the-event-queue))

I seem to have the macro working now, thanks to the feedback on removing 
the nil.

-Luke
From: Luke J Crook
Subject: Re: Getting rid of nil's in a macro ?
Date: 
Message-ID: <p7uLb.52329$nG3.17742@twister.socal.rr.com>
Kenny Tilton wrote:

 >
 >
 > Why? Does list-of-events contain nils? Some events get no handling?
 > You can still generate empty handlers for those. But I have other Qs:


I seemed to have erred on the side brevity.

 >
 > How would this macro be used? Something like:
 >
 >    (events-worry-about event (mouseup mousedown diskInsert))?
 >
 > Why is this a macro, btw? Are you also tailoring the handling:
 >
 >    (events-handle event
 >       (mouseup (do-this))
 >       (mousedown (do-that))?
 >
 > But that could be a case or typecase. Well, I'm guessing too much.


You are pretty much spot on. I am trying to move some very messy event 
handling code into something that looks like the code below, using macros.

(with-sdl-events
   (:quit (q)
       (setf q t))
   (:mousebuttonup (state x y xrel yrel)
       (look-mom-the-mousebutton-is-up))
   (:idle
       (and-here-are)
       (forms-that-are-executed)
       (when-there-are-no-events)
       (in-the-event-queue)))

Here, :idle is treated like an event, but is not an event as these forms 
are placed after the processing of the event loop. So the #'(lambda that 
tests for events retuns nil for :idle.

The original code is below (Corman Lisp).

(do ()
     ((eql quit t))

     ;Check for SDL Events. Exit on quit.
     (do ((poll-event 1 (sdl:SDL_PollEvent sdl-event)))
         ((eql poll-event 0) 'done)
         (cond
             ((eql sdl:SDL_QUIT
                  (ct:cref sdl:SDL_Event sdl-event sdl::type))
                 (setf quit t))
             ((eql sdl:SDL_KEYDOWN (ct:cref sdl:SDL_Event
                                            sdl-event sdl::type))
                 (handle-key-down (ct:cref sdl:SDL_KeyboardEvent
                                            sdl-event sdl::keysym)))))
     ;; Do stuff here
      (and-here-are)
      (forms-that-are-executed)
      (when-there-are-no-events)
     (in-the-event-queue))

I seem to have the macro working now, thanks to the feedback on removing 
the nil.

-Luke