From: Bob Felts
Subject: Is there a better way?
Date: 
Message-ID: <1i4nj72.va9wjk15wk1z8N%wrf3@stablecross.com>
I'm writing some code that uses Zach Bean's wonderful SKIPPY library to
create gif files to graph some secret data.  I need to map genus and
species to colors and put together the following table.  The names have
been changed to protect the guilty.  And it really isn't a biology
project, but species/genus works as an equivalent abstraction.

(defparameter *color-table*
  '(("Species1"  . ((nil             . (nil . (  0   0   0)))))
    ("Species2"  . (("Genus1" . (nil . (255 255 255)))
                     ("Genus2" . (nil . (255 255   0)))
                     ("Genus3" . (nil . ( 67 167 241)))
                     ("Genus4" . (nil . (255   0 255)))
                     ("Genus5" . (nil . (  0 255 255)))
                     (nil             . (nil . (255 100 100)))))
    ("Species3"  . (("Genus1" . (nil . (255 230 108)))
                     ("Genus2" . (nil . (128   0 128)))
                     ("Genus3" . (nil . (  0 128 128)))
                     (nil             . (nil . (  0 255   0)))))
    (nil               . ((nil              . (nil . (255 128 0))))))) 

I picked this form since is makes finding Species/Genus easy with
assoc().  nil matches anything, which is handled by #'assoc-string (not
shown here).

(defun map-color (species genus)
  (car (cdr (assoc genus (cdr (assoc species *color-table* :test
#'assoc-string)) :test #'assoc-string))))

The inner assoc finds the species and the outer assoc finds the genus.
The outer cdr returns the (nil . (R G B)) pair, and the car returns the
nil.  The nil was earlier initialized to be the index of the color in
the color table:

(defun init-clut (clut)
  (loop for species in *color-table*
       do
       (loop for genus in (rest species)
       do
       (let ((color-info (rest genus)))
         (setf (car color-info)
         (ensure-color (apply #'rgb-color (cdr color-info)) clut))))))

ensure-color is the SKIPPY function to make an RGB triplet into a color
table and return the index.

My guestion is:  is there a better way to do this?  I'm not quite happy
with using the (nil . (R G B)) constuct to handle associating a color
index with an RGB triplet, but I'm not sure why I don't like it.  I
should be happy that everything is data driven and that the code to
handle colors is quite short, but something is making me restless.

Any comments?

From: Rainer Joswig
Subject: Re: Is there a better way?
Date: 
Message-ID: <joswig-8BF834.09442819092007@news-europe.giganews.com>
In article <···························@stablecross.com>,
 ····@stablecross.com (Bob Felts) wrote:

> I'm writing some code that uses Zach Bean's wonderful SKIPPY library to
> create gif files to graph some secret data.  I need to map genus and
> species to colors and put together the following table.  The names have
> been changed to protect the guilty.  And it really isn't a biology
> project, but species/genus works as an equivalent abstraction.
> 
> (defparameter *color-table*
>   '(("Species1"  . ((nil             . (nil . (  0   0   0)))))
>     ("Species2"  . (("Genus1" . (nil . (255 255 255)))
>                      ("Genus2" . (nil . (255 255   0)))
>                      ("Genus3" . (nil . ( 67 167 241)))
>                      ("Genus4" . (nil . (255   0 255)))
>                      ("Genus5" . (nil . (  0 255 255)))
>                      (nil             . (nil . (255 100 100)))))
>     ("Species3"  . (("Genus1" . (nil . (255 230 108)))
>                      ("Genus2" . (nil . (128   0 128)))
>                      ("Genus3" . (nil . (  0 128 128)))
>                      (nil             . (nil . (  0 255   0)))))
>     (nil               . ((nil              . (nil . (255 128 0))))))) 

Make sure that you understand that above is a literal constant
and should NOT (!!!) be modified. It is not allowed in ANSI CL
to modify literal constants. If you want kind of
a list that you can modify, you need to create one
(using LIST, COPY-LIST, COPY-TREE, ...).

> 
> I picked this form since is makes finding Species/Genus easy with
> assoc().  nil matches anything, which is handled by #'assoc-string (not
> shown here).

It might be a bit more idiomatic to use symbols instead of strings.

Instead of data with list accessors (CAR, CDR) use
a data type described with DEFSTRUCT or DEFCLASS.
If you want to use lists, then use DEFSTRUCT with the list
option. Like here:

? (defstruct (foo (:type list)) a b)
FOO
? (make-foo :a 'bar :b "baz")
(BAR "baz")
? (foo-a *)
BAR
? 


> 
> (defun map-color (species genus)
>   (car (cdr (assoc genus (cdr (assoc species *color-table* :test
> #'assoc-string)) :test #'assoc-string))))
> 
> The inner assoc finds the species and the outer assoc finds the genus.
> The outer cdr returns the (nil . (R G B)) pair, and the car returns the
> nil.  The nil was earlier initialized to be the index of the color in

CAR and CDR are bad data accessors. See above.

> the color table:
> 
> (defun init-clut (clut)
>   (loop for species in *color-table*
>        do
>        (loop for genus in (rest species)
>        do
>        (let ((color-info (rest genus)))
>          (setf (car color-info)
>          (ensure-color (apply #'rgb-color (cdr color-info)) clut))))))

IF you use a primitive LOOP, DOLIST is as good.

Otherwise you can use LOOP like this:

(defun init-clut (clut)
  (loop for (name . genus) in *color-table*
        do (loop for (name . color-info) in genus
                 do (setf (car color-info)
                          (ensure-color (apply #'rgb-color (cdr color-info))
                                        clut)))))

But then you have the implementation of your color table
in your other code.

I would write a function that maps a function over the
color-table. Similar to this usage:

(defun init-clut (clut)
  (map-color-table-entries
   (lambda (r g b)
     (ensure-color (rgb-color r g b) clut))))



> 
> ensure-color is the SKIPPY function to make an RGB triplet into a color
> table and return the index.
> 
> My guestion is:  is there a better way to do this?  I'm not quite happy
> with using the (nil . (R G B)) constuct to handle associating a color
> index with an RGB triplet, but I'm not sure why I don't like it.  I
> should be happy that everything is data driven and that the code to
> handle colors is quite short, but something is making me restless.
> 
> Any comments?

See also

See the article "DEFTABLE: A Macro for Implementing Tables"
by Peter Norvig, in  Lisp Pointers.
http://www-cgi.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/ext/tables/0.html
http://portal.acm.org/citation.cfm?id=382665

-- 
http://lispm.dyndns.org
From: Bob Felts
Subject: Re: Is there a better way?
Date: 
Message-ID: <1i4rcgi.156rmgo1b11fboN%wrf3@stablecross.com>
Rainer Joswig <······@lisp.de> wrote:

First, let me say thanks.  Sorry I haven't  responded sooner; other
events were taking my time.

I'm going to learn this language if it kills me.  To that end, I still
have a few questions.

> In article <···························@stablecross.com>,
>  ····@stablecross.com (Bob Felts) wrote:
> 
> > I'm writing some code that uses Zach Bean's wonderful SKIPPY library to
> > create gif files to graph some secret data.  I need to map genus and
> > species to colors and put together the following table.  The names have
> > been changed to protect the guilty.  And it really isn't a biology
> > project, but species/genus works as an equivalent abstraction.
> > 
> > (defparameter *color-table*
> >   '(("Species1"  . ((nil             . (nil . (  0   0   0)))))
> >     ("Species2"  . (("Genus1" . (nil . (255 255 255)))
> >                      ("Genus2" . (nil . (255 255   0)))
> >                      ("Genus3" . (nil . ( 67 167 241)))
> >                      ("Genus4" . (nil . (255   0 255)))
> >                      ("Genus5" . (nil . (  0 255 255)))
> >                      (nil             . (nil . (255 100 100)))))
> >     ("Species3"  . (("Genus1" . (nil . (255 230 108)))
> >                      ("Genus2" . (nil . (128   0 128)))
> >                      ("Genus3" . (nil . (  0 128 128)))
> >                      (nil             . (nil . (  0 255   0)))))
> >     (nil               . ((nil              . (nil . (255 128 0)))))))
> 
> Make sure that you understand that above is a literal constant
> and should NOT (!!!) be modified. It is not allowed in ANSI CL
> to modify literal constants. If you want kind of
> a list that you can modify, you need to create one
> (using LIST, COPY-LIST, COPY-TREE, ...).
> 

From a purist perspective, I agree with you.  But I'm not sure I have
the right mental model of what's happening here.  If I may descend to a
"vulgar" langauge, in C I can write:

  SomeStructureType foo =
   { { ...}, {...}, {...} ...}

I can freely modify the contents of foo, unless I preface the
declaration with 'const'.

Is this equivalent to the defparameter?  Or is there an implicit 'const'
in the Lisp expression?  It seems seems strange to me that I can't
declare something like this and use it, without first copying it
somewhere else.

> > 
> > I picked this form since is makes finding Species/Genus easy with
> > assoc().  nil matches anything, which is handled by #'assoc-string (not
> > shown here).
> 
> It might be a bit more idiomatic to use symbols instead of strings.
> 

There's madness to my method; the strings are what is found in a text
file and I want to be able to look at the things in the text file and
map them to the table without having to need an intermediate conversion.
This makes it simple to add another entry to the table - just add what
is seen in the text file.

> Instead of data with list accessors (CAR, CDR) use a data type described
> with DEFSTRUCT or DEFCLASS. If you want to use lists, then use DEFSTRUCT
> with the list option. Like here:
> 
> ? (defstruct (foo (:type list)) a b)
> FOO
> ? (make-foo :a 'bar :b "baz")
> (BAR "baz")
> ? (foo-a *)
> BAR
> ? 
> 

I'm having trouble making the connection between what I think this does
and what I think I need.  I spent some time yesterday googling for
defstruct; didn't help me much.  However, I'll play with this when I get
some time to see what I can figure out.

[...]

> > the color table:
> > 
> > (defun init-clut (clut)
> >   (loop for species in *color-table*
> >        do
> >        (loop for genus in (rest species)
> >        do
> >        (let ((color-info (rest genus)))
> >          (setf (car color-info)
> >          (ensure-color (apply #'rgb-color (cdr color-info)) clut))))))
> 
> IF you use a primitive LOOP, DOLIST is as good.
> 

Since I'm still learning Lisp, I'm stressing LOOP at the moment just to
build muscle memory.

> Otherwise you can use LOOP like this:
> 
> (defun init-clut (clut)
>   (loop for (name . genus) in *color-table*
>         do (loop for (name . color-info) in genus
>                  do (setf (car color-info)
>                           (ensure-color (apply #'rgb-color (cdr color-info))
>                                         clut)))))
> 

Oh, my!  Something else to learn.

> But then you have the implementation of your color table
> in your other code.
> 
> I would write a function that maps a function over the
> color-table. Similar to this usage:
> 
> (defun init-clut (clut)
>   (map-color-table-entries
>    (lambda (r g b)
>      (ensure-color (rgb-color r g b) clut))))
> 
> 
> 
> > 
> > ensure-color is the SKIPPY function to make an RGB triplet into a color
> > table and return the index.
> > 
> > My guestion is:  is there a better way to do this?  I'm not quite happy
> > with using the (nil . (R G B)) constuct to handle associating a color
> > index with an RGB triplet, but I'm not sure why I don't like it.  I
> > should be happy that everything is data driven and that the code to
> > handle colors is quite short, but something is making me restless.
> > 
> > Any comments?
> 
> See also
> 
> See the article "DEFTABLE: A Macro for Implementing Tables"
> by Peter Norvig, in  Lisp Pointers.
>
http://www-cgi.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code
/ext/tables/0.html
> http://portal.acm.org/citation.cfm?id=382665

I wish I could.  I'm going on vacation next week and need to watch the
budget. :-o
From: D Herring
Subject: Re: Is there a better way?
Date: 
Message-ID: <kvGdnZ7QMqt8sm7bnZ2dnUVZ_uevnZ2d@comcast.com>
Bob Felts wrote:
> Rainer Joswig <······@lisp.de> wrote:
> 
> First, let me say thanks.  Sorry I haven't  responded sooner; other
> events were taking my time.
> 
> I'm going to learn this language if it kills me.  To that end, I still
> have a few questions.
> 
>> In article <···························@stablecross.com>,
>>  ····@stablecross.com (Bob Felts) wrote:
>>
>>> I'm writing some code that uses Zach Bean's wonderful SKIPPY library to
>>> create gif files to graph some secret data.  I need to map genus and
>>> species to colors and put together the following table.  The names have
>>> been changed to protect the guilty.  And it really isn't a biology
>>> project, but species/genus works as an equivalent abstraction.
>>>
>>> (defparameter *color-table*
>>>   '(("Species1"  . ((nil             . (nil . (  0   0   0)))))
>>>     ("Species2"  . (("Genus1" . (nil . (255 255 255)))
>>>                      ("Genus2" . (nil . (255 255   0)))
>>>                      ("Genus3" . (nil . ( 67 167 241)))
>>>                      ("Genus4" . (nil . (255   0 255)))
>>>                      ("Genus5" . (nil . (  0 255 255)))
>>>                      (nil             . (nil . (255 100 100)))))
>>>     ("Species3"  . (("Genus1" . (nil . (255 230 108)))
>>>                      ("Genus2" . (nil . (128   0 128)))
>>>                      ("Genus3" . (nil . (  0 128 128)))
>>>                      (nil             . (nil . (  0 255   0)))))
>>>     (nil               . ((nil              . (nil . (255 128 0)))))))
>> Make sure that you understand that above is a literal constant
>> and should NOT (!!!) be modified. It is not allowed in ANSI CL
>> to modify literal constants. If you want kind of
>> a list that you can modify, you need to create one
>> (using LIST, COPY-LIST, COPY-TREE, ...).
>>
> 
> From a purist perspective, I agree with you.  But I'm not sure I have
> the right mental model of what's happening here.  If I may descend to a
> "vulgar" langauge, in C I can write:
> 
>   SomeStructureType foo =
>    { { ...}, {...}, {...} ...}
> 
> I can freely modify the contents of foo, unless I preface the
> declaration with 'const'.
> 
> Is this equivalent to the defparameter?  Or is there an implicit 'const'
> in the Lisp expression?  It seems seems strange to me that I can't
> declare something like this and use it, without first copying it
> somewhere else.

Lisp has a separate command for constants:
defvar and defparameter -
   http://www.lisp.org/HyperSpec/Body/mac_defparametercm_defvar.html
defconstant - http://www.lisp.org/HyperSpec/Body/mac_defconstant.html

You can ask the system whether something is constant
constantp - http://www.lisp.org/HyperSpec/Body/fun_constantp.html

>>> I picked this form since is makes finding Species/Genus easy with
>>> assoc().  nil matches anything, which is handled by #'assoc-string (not
>>> shown here).
>> It might be a bit more idiomatic to use symbols instead of strings.
> 
> There's madness to my method; the strings are what is found in a text
> file and I want to be able to look at the things in the text file and
> map them to the table without having to need an intermediate conversion.
> This makes it simple to add another entry to the table - just add what
> is seen in the text file.

Symbols are nice since Lisp provides a symbol<->string mapping:
(symbol-name 'hi) => "HI"
(symbol-name '|hello world|) => "hello world"
(intern "hello world") => '|hello world|

Additionally, its generally faster to check (eql 'hi 'there) than 
(string= "hi" "there").

Systems which do a lot of text-input manipulation may take this a step 
further.  For example, here's a snippet from MockMMA[1] that converts 
variable names into integers to speed up symbolic manipulation.

[1] http://www.cs.berkeley.edu/~fateman/mma.mailer

simp1.lisp:
-----
(defvar varcount 0)
(defvar vartab (make-hash-table :test #'equal)) ;; map from kernels to 
integers
(defvar revtab (make-hash-table :test #'eql)) ;; map from integers to 
kernels

;; look-up-var: look up a variable in the hash-table; if exists,
;;    	        return the value of it; otherwise, increment varcount
;;              and add variable to hash-table

(defun look-up-var (x)
   (cond ((gethash x vartab))
	(t (setf (gethash (setq varcount (1+ varcount)) revtab) x)
	   (setf (gethash x vartab) varcount))))
-----

> 
>> Instead of data with list accessors (CAR, CDR) use a data type described
>> with DEFSTRUCT or DEFCLASS. If you want to use lists, then use DEFSTRUCT
>> with the list option. Like here:
>>
>> ? (defstruct (foo (:type list)) a b)
>> FOO
>> ? (make-foo :a 'bar :b "baz")
>> (BAR "baz")
>> ? (foo-a *)
>> BAR
>> ? 
>>
> 
> I'm having trouble making the connection between what I think this does
> and what I think I need.  I spent some time yesterday googling for
> defstruct; didn't help me much.  However, I'll play with this when I get
> some time to see what I can figure out.

You'll have better luck reading a book (several are freely available 
online) or searching at
http://lispdoc.com/

Later,
Daniel
From: Raffael Cavallaro
Subject: Re: Is there a better way?
Date: 
Message-ID: <2007092112415275249-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2007-09-21 08:38:51 -0400, Kent M Pitman <······@nhplace.com> said:

> Does this help?

Maybe I'm confused as well, but for me the issue arises because I
would expect that (constantp x) would tell me if x is a constant
*object*, which is to say, I would expect that constantp would tell
me if an object is immutable. Instead, constantp tells me if a
*form* is a constant form, which is not always helpful. These
examples are taken more or less straight from the hyperspec -
I've just interspersed some constantp forms:

? (setq alpha (make-array 4))
#(0 0 0 0)
? (constantp alpha)
T
? (setf (aref alpha 3) 'sirens)
SIRENS
? alpha
#(0 0 0 SIRENS)
? (constantp alpha)
T
?
From: Rob Warnock
Subject: Re: Is there a better way?
Date: 
Message-ID: <nqednViuEqeimmjbnZ2dnUVZ_s-pnZ2d@speakeasy.net>
Raffael Cavallaro  <················@pas-d'espam-s'il-vous-plait-mac.com> wrote:
+---------------
| Kent M Pitman <······@nhplace.com> said:
| > Does this help?
| 
| Maybe I'm confused as well, but for me the issue arises because I
| would expect that (constantp x) would tell me if x is a constant
| *object*, which is to say, I would expect that constantp would tell
| me if an object is immutable. Instead, constantp tells me if a
| *form* is a constant form, which is not always helpful.
+---------------

That's correct [in both senses]. E.g., in an implementation like CMUCL
which chooses[1] to evaluate the value of a (DEFCONSTANT <var> <form>)
at LOAD time, a (CONSTANTP <var>) can return T at compile time and yet
the *value* of <var> is *NOT* available at compile time!!

To say that at times this can be frustrating is an understatement...  ;-}


-Rob

[1] Legally, according to CLHS "Macro DEFCONSTANT":

        If a defconstant form appears as a top level form, the
        compiler must recognize that name names a constant variable.

    That implies that a (CONSTANTP <var>) later in the code *must*
    return T, but:

	An implementation may choose to evaluate the value-form
	at compile time, load time, or both.

    So attempting to *reference* the value of <var> at compile time
    is allowed to fail... even if <form> is a simple literal!

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Bob Felts
Subject: Re: Is there a better way?
Date: 
Message-ID: <1i4suwo.8lr7mm1rue7awN%wrf3@stablecross.com>
Kent M Pitman <······@nhplace.com> wrote:

[...]

> 
> (In writing the glossary, I tried to codify the current usage of
> language as spoken rather than to force the creation of new language
> with some specialized spec-only purpose, which is why the terms are
> overloaded as they are; that's the way the people who made the
> language really talked, and I wanted people to understand how the
> community really spoke about things, especially since the variety of
> language is reflective of the variety of implementational theories.)
> 
> Does this help?

Wow.  Yes.  If you're ever in Atlanta, I'll buy you a beverage (or
three) of your choice.

Between what you, "D Herring" and Ranier wrote, I know what I need to do
to make my code much more elegant .  Thanks, everyone.
From: Rob St. Amant
Subject: Re: Is there a better way?
Date: 
Message-ID: <fd3h4j$rn$1@blackhelicopter.databasix.com>
····@stablecross.com (Bob Felts) writes:

> Rainer Joswig <······@lisp.de> wrote:
>
>> Instead of data with list accessors (CAR, CDR) use a data type described
>> with DEFSTRUCT or DEFCLASS. If you want to use lists, then use DEFSTRUCT
>> with the list option. Like here:
>> 
>> ? (defstruct (foo (:type list)) a b)
>> FOO
>> ? (make-foo :a 'bar :b "baz")
>> (BAR "baz")
>> ? (foo-a *)
>> BAR
>> ? 
>> 
>
> I'm having trouble making the connection between what I think this does
> and what I think I need.  I spent some time yesterday googling for
> defstruct; didn't help me much.  However, I'll play with this when I get
> some time to see what I can figure out.

I imagine part of what Rainer is suggesting is that it would be easier
to understand the entries in the color table (both building them and
accessing them) if they're associated with named functions.

(defparameter *color-table*
  (list (make-species-entry "Species1"
                            (make-genus-entry nil ; or :default
                                              (make-color-entry 0 0 0)))
        (make-species-entry "Species2"
                            (make-genus-entry "Genus1"
                                              (make-color-entry 255 255 255))
                            . . .)
        . . .))

These make-*-entry functions would be defined on top of (or as
overrides for) automatically generated defstruct functions.  Depending
on the real domain, abstracting away colors from RGB values might be
useful, too.
From: Felipe Micaroni Lalli
Subject: Re: Is there a better way?
Date: 
Message-ID: <1190473030.727634.28490@w3g2000hsg.googlegroups.com>
On 18 set, 21:15, ····@stablecross.com (Bob Felts) wrote:
> I'm writing some code that uses Zach Bean's wonderful SKIPPY library to
> create gif files to graph some secret data.  I need to map genus and
> species to colors and put together the following table.  The names have
> been changed to protect the guilty.  And it really isn't a biology
> project, but species/genus works as an equivalent abstraction.
>
> (defparameter *color-table*
>   '(("Species1"  . ((nil             . (nil . (  0   0   0)))))
>     ("Species2"  . (("Genus1" . (nil . (255 255 255)))
>                      ("Genus2" . (nil . (255 255   0)))
>                      ("Genus3" . (nil . ( 67 167 241)))
>                      ("Genus4" . (nil . (255   0 255)))
>                      ("Genus5" . (nil . (  0 255 255)))
>                      (nil             . (nil . (255 100 100)))))
>     ("Species3"  . (("Genus1" . (nil . (255 230 108)))
>                      ("Genus2" . (nil . (128   0 128)))
>                      ("Genus3" . (nil . (  0 128 128)))
>                      (nil             . (nil . (  0 255   0)))))
>     (nil               . ((nil              . (nil . (255 128 0)))))))
>
> I picked this form since is makes finding Species/Genus easy with
> assoc().  nil matches anything, which is handled by #'assoc-string (not
> shown here).
>
> (defun map-color (species genus)
>   (car (cdr (assoc genus (cdr (assoc species *color-table* :test
> #'assoc-string)) :test #'assoc-string))))
>
> The inner assoc finds the species and the outer assoc finds the genus.
> The outer cdr returns the (nil . (R G B)) pair, and the car returns the
> nil.  The nil was earlier initialized to be the index of the color in
> the color table:
>
> (defun init-clut (clut)
>   (loop for species in *color-table*
>        do
>        (loop for genus in (rest species)
>        do
>        (let ((color-info (rest genus)))
>          (setf (car color-info)
>          (ensure-color (apply #'rgb-color (cdr color-info)) clut))))))
>
> ensure-color is the SKIPPY function to make an RGB triplet into a color
> table and return the index.
>
> My guestion is:  is there a better way to do this?  I'm not quite happy
> with using the (nil . (R G B)) constuct to handle associating a color
> index with an RGB triplet, but I'm not sure why I don't like it.  I
> should be happy that everything is data driven and that the code to
> handle colors is quite short, but something is making me restless.
>
> Any comments?

Why this code is so ugly?
From: Bob Felts
Subject: Re: Is there a better way?
Date: 
Message-ID: <1i57o3o.6j29klfgx4qoN%wrf3@stablecross.com>
Felipe Micaroni Lalli <·········@gmail.com> wrote:

> On 18 set, 21:15, ····@stablecross.com (Bob Felts) wrote:
> > I'm writing some code ...
> >
> > Any comments?
> 
> Why this code is so ugly?

If you're referring to the formatting, it was input using a
proportionally spaced font, so things didn't line up properly.

If you're referring to the code itself, you'll have to tell me.