Coming from a C/C++ background I like structures. A lot. The thing is,
I find DEFSTRUCT's default accessors to be horribly horribly verbose. I
am looking for a way to reduce the amount of text on screen so but still
use structures.
For example, for a simple structure of structures, like the following
require a huge, verbose line for every member access!
(defstruct joystick-axis
"A joystick axis and its limits"
index
min
max)
(defstruct joystick-input-map
"A map of joystick axes and buttons to our format"
(left-stick-axis-x :type joystick-axis)
(left-stick-axis-y :type joystick-axis)
(right-stick-axis-x :type joystick-axis)
(right-stick-axis-y :type joystick-axis))
;; This is way too long and verbose!!!
(joystick-axis-index (joystick-input-map-left-stick-axis-x joystick))
This is just way too verbose for my tastes! I need a shorter way to
express what I want to do so I don't get bogged down by details like this.
I've noticed that CLOS has a function SLOT-VALUE that adds uniformity to
the code as well as shortening it. This seems good because I could
define a macro for member access. Currently I see creating a read macro
to for a CLOS class to be the best option. That way I could write
something like the following expression, which I feel is much closer to
what I want to express.
@(joystick :left-stick-axis :index)
This seems like something that people must have solved previously (or
perhaps there is a solution in the standard). That is why I would like
your input. I need feedback from people who have written big projects
and therefore must have run into this problem before.
-- MJF
M Jared Finder wrote:
> Coming from a C/C++ background I like structures. A lot. The thing
> is, I find DEFSTRUCT's default accessors to be horribly horribly
> verbose. I am looking for a way to reduce the amount of text on
> screen so but still use structures.
>
> For example, for a simple structure of structures, like the following
> require a huge, verbose line for every member access!
>
> (defstruct joystick-axis
> "A joystick axis and its limits"
> index
> min
> max)
>
>
> (defstruct joystick-input-map
> "A map of joystick axes and buttons to our format"
> (left-stick-axis-x :type joystick-axis)
> (left-stick-axis-y :type joystick-axis)
> (right-stick-axis-x :type joystick-axis)
> (right-stick-axis-y :type joystick-axis))
>
> ;; This is way too long and verbose!!!
> (joystick-axis-index (joystick-input-map-left-stick-axis-x joystick))
>
> This is just way too verbose for my tastes! I need a shorter way to
> express what I want to do so I don't get bogged down by details like
> this.
>
> I've noticed that CLOS has a function SLOT-VALUE that adds uniformity
> to the code as well as shortening it. This seems good because I
> could define a macro for member access. Currently I see creating a
> read macro to for a CLOS class to be the best option. That way I
> could write something like the following expression, which I feel is
> much closer to what I want to express.
>
> @(joystick :left-stick-axis :index)
>
> This seems like something that people must have solved previously (or
> perhaps there is a solution in the standard). That is why I would
> like your input. I need feedback from people who have written big
> projects and therefore must have run into this problem before.
>
> -- MJF
If you want to make a class, you could use the WITH-SLOTS macro:
(defclass joystick ()
((left-stick-axis-x :accessor axis-x)))
Now you could do:
(setq j (make-instance 'joystick))
(setf (axis-x j) 10)
or
(with-slots (left-stick-axis-x j)
(print left-stick-axis-x))
Jeff
"Jeff" <···@nospam.insightbb.com> wrote in message
····························@attbi_s51...
> If you want to make a class, you could use the WITH-SLOTS macro:
>
> (defclass joystick ()
> ((left-stick-axis-x :accessor axis-x)))
>
> Now you could do:
>
> (setq j (make-instance 'joystick))
>
> (setf (axis-x j) 10)
>
> or
>
> (with-slots (left-stick-axis-x j)
> (print left-stick-axis-x))
syntax correction: j needs to be after the list of slot-names. This allows
specifying local alias' too, which will be more helpful for the OP's
original problem of verbosity:
(with-slots ((left-x left-stick-axis-x) ...<more-slots>... ) j
(print left-x))
--
Coby Beck
(remove #\Space "coby 101 @ big pond . com")
M Jared Finder <·······@hpalace.com> wrote in message news:<··············@uni-berlin.de>...
> Coming from a C/C++ background I like structures. A lot. The thing is,
> I find DEFSTRUCT's default accessors to be horribly horribly verbose. I
> am looking for a way to reduce the amount of text on screen so but still
> use structures.
[snip]
> ;; This is way too long and verbose!!!
> (joystick-axis-index (joystick-input-map-left-stick-axis-x joystick))
defstruct has a lot of options for handling such problems. They're in
the HyperSpec at
http://www.lisp.org/HyperSpec/Body/mac_defstruct.html
I think :conc-name is what you want.
M Jared Finder <·······@hpalace.com> wrote in message news:<··············@uni-berlin.de>...
> This is just way too verbose for my tastes!
Hmm - typing time has never been an issue for me. (A shorter struct
name is often better than using conc-name.)
> I need a shorter way to
> express what I want to do so I don't get bogged down by details like this.
Huh? Long names aren't a detail problem. They're just long names.
Your reading time isn't proportional to the number of characters, it's
proportional to the amount of processing. Appropriate names reduce
that, even when they're longer.
> Currently I see creating a read macro
> to for a CLOS class to be the best option. That way I could write
> something like the following expression, which I feel is much closer to
> what I want to express.
>
> @(joystick :left-stick-axis :index)
Oh joy - yet another ideosyncratic syntax.
With very few exceptions, and this isn't one of them, read macros are
a mistake.
Common Lisp gives you far more rope than most languages, yet you
typically should use less.
If you're just learning the language, stay out of the nooks and
crannies.
Andy Freeman wrote:
> M Jared Finder <·······@hpalace.com> wrote in message news:<··············@uni-berlin.de>...
>
>>This is just way too verbose for my tastes!
>
>
> Hmm - typing time has never been an issue for me. (A shorter struct
> name is often better than using conc-name.)
>
>
>>I need a shorter way to
>>express what I want to do so I don't get bogged down by details like this.
>
>
> Huh? Long names aren't a detail problem. They're just long names.
> Your reading time isn't proportional to the number of characters, it's
> proportional to the amount of processing. Appropriate names reduce
> that, even when they're longer.
>
>
>> Currently I see creating a read macro
>>to for a CLOS class to be the best option. That way I could write
>>something like the following expression, which I feel is much closer to
>>what I want to express.
>>
>>@(joystick :left-stick-axis :index)
>
>
> Oh joy - yet another ideosyncratic syntax.
>
> With very few exceptions, and this isn't one of them, read macros are
> a mistake.
>
> Common Lisp gives you far more rope than most languages, yet you
> typically should use less.
>
> If you're just learning the language, stay out of the nooks and
> crannies.
If you're dead set on creating a macro to reduce the amount of typing,
it should be easy enough to make a wrapper for defstruct (or defclass,
or make-instance...) that makes you code look reasonable without
rendering it completely opaque to someone who actually knows Lisp.
This is yet another example of how people coming from other languages
tend to be drawn to premature optimizatons.
paul
Andy Freeman wrote:
> M Jared Finder <·······@hpalace.com> wrote in message news:<··············@uni-berlin.de>...
>
> If you're just learning the language, stay out of the nooks and
> crannies.
I have to reply to this, because it really irks me. I have found the
best way to fully learn anything is to investigate all those obscure
nooks and crannies, of course making horrible mistakes along the way.
After you've horribly screwed yourself in ways you couldn't even
comprehend at the beginning, you know much better what has worked and
what hasn't
If I limited myself to just the well known path, I wouldn't even be
here, I'd be on comp.lang.java. :P
-- MJF
M Jared Finder <·······@hpalace.com> wrote in message news:<··············@uni-berlin.de>...
> Andy Freeman wrote:
> > M Jared Finder <·······@hpalace.com> wrote in message news:<··············@uni-berlin.de>...
> >
> > If you're just learning the language, stay out of the nooks and
> > crannies.
>
> I have to reply to this, because it really irks me. I have found the
> best way to fully learn anything is to investigate all those obscure
> nooks and crannies, of course making horrible mistakes along the way.
My bad - I thought that your message was written by someone who wanted
to get something done with the least amount of pain.
If you want to learn from your own mistakes, spend all your time in
the nooks and crannies.
It's generally a bad idea to use the same code to chase both goals.
YMMV but I learn more from successful projects than from "learning"
projects.
> After you've horribly screwed yourself in ways you couldn't even
> comprehend at the beginning, you know much better what has worked and
> what hasn't
My point is that the nooks and crannies are good places to screw
yourself; if that's not your goal, stay out of them.
Note that in every non-trivial project, the code will be worked on by
someone less competent than you. (Yup, even single-person projects -
the mechanism is left as an excercise to the reader.) To succeed, you
need to keep that person from screwing up.
FWIW, You don't have to know why something is "good practice" to get
the benefits from following said "good practice".
"M Jared Finder" <·······@hpalace.com> wrote in message
···················@uni-berlin.de...
> Andy Freeman wrote:
> > M Jared Finder <·······@hpalace.com> wrote in message
news:<··············@uni-berlin.de>...
> >
> > If you're just learning the language, stay out of the nooks and
> > crannies.
>
> I have to reply to this, because it really irks me. I have found the
> best way to fully learn anything is to investigate all those obscure
> nooks and crannies, of course making horrible mistakes along the way.
> After you've horribly screwed yourself in ways you couldn't even
> comprehend at the beginning, you know much better what has worked and
> what hasn't
>
> If I limited myself to just the well known path, I wouldn't even be
> here, I'd be on comp.lang.java. :P
Indeed! Lisp is Robert Frost path "less traveled by" and you won't regret
taking it!
Now that I've buttered you up, I will second an earlier post and recommend
defclass over defstruct for many easily googled reasons, among them
solutions for your accessor naming problem.
--
Coby Beck
(remove #\Space "coby 101 @ big pond . com")
M Jared Finder <·······@hpalace.com> writes:
> Coming from a C/C++ background I like structures. A lot. The thing
> is, I find DEFSTRUCT's default accessors to be horribly horribly
> verbose. I am looking for a way to reduce the amount of text on
> screen so but still use structures.
>
> For example, for a simple structure of structures, like the following
> require a huge, verbose line for every member access!
>
> (defstruct joystick-axis
> "A joystick axis and its limits"
> index
> min
> max)
>
>
> (defstruct joystick-input-map
> "A map of joystick axes and buttons to our format"
> (left-stick-axis-x :type joystick-axis)
> (left-stick-axis-y :type joystick-axis)
> (right-stick-axis-x :type joystick-axis)
> (right-stick-axis-y :type joystick-axis))
>
> ;; This is way too long and verbose!!!
> (joystick-axis-index (joystick-input-map-left-stick-axis-x joystick))
>
> This is just way too verbose for my tastes! I need a shorter way to
> express what I want to do so I don't get bogged down by details like
> this.
From the Emacs documentation:
M-/ runs `dabbrev-expand'
Expands to the most recent, preceding word for which this is a prefix.
If no suitable preceding word is found, words following point are
considered. If still no suitable word is found, then look in the
buffers accepted by the function pointed out by variable
`dabbrev-friend-buffer-function'.
So now you don't have to type as much.
(defmacro left-joystick-index (joystick)
`(joystick-axis-index (joystick-input-map-left-stick-axis-x ,joystick)))
Now you can use the short form.
> I've noticed that CLOS has a function SLOT-VALUE that adds uniformity
> to the code as well as shortening it.
It also removes a level of abstraction. I don't recommend doing this.
> This seems like something that people must have solved previously (or
> perhaps there is a solution in the standard). That is why I would
> like your input. I need feedback from people who have written big
> projects and therefore must have run into this problem before.
Verbosity is not necessarily evil. It really helps when you are
looking at old dusty code. You can trim your names a bit, though.
> (defstruct joystick-input-map
> "A map of joystick axes and buttons to our format"
> (left-stick-axis-x :type joystick-axis)
> (left-stick-axis-y :type joystick-axis)
> (right-stick-axis-x :type joystick-axis)
> (right-stick-axis-y :type joystick-axis))
Is there an output map? If not, then the word `input' is unnecessary.
I assume your joysticks have sticks, so the work `stick' is a bit
redundant. I don't see that the work `axis' is doing much either.
(defstruct joystick-map
"A map of joystick axes and buttons to our format"
(left-x :type joystick-axis)
(left-y :type joystick-axis)
(right-x :type joystick-axis)
(right-y :type joystick-axis))
> (joystick-axis-index (joystick-map-left-x joystick))
From: Marco Baringer
Subject: Re: Making structures useable
Date:
Message-ID: <m2fz6bpry5.fsf@convey.it>
you could use the :conc-name struct option, to eliminate the prefix in
the accessor names:
(defstruct (joystick-axis (:conc-name))
"A joystick axis and its limits"
index
min
max)
(defstruct (joystick-input-map (:conc-name))
"A map of joystick axes and buttons to our format"
(left-stick-axis-x :type joystick-axis)
(left-stick-axis-y :type joystick-axis)
(right-stick-axis-x :type joystick-axis)
(right-stick-axis-y :type joystick-axis))
now this:
> (joystick-axis-index (joystick-input-map-left-stick-axis-x joystick))
is just:
(index (left-stick-axis-x joystick))
or you could use defclass which allows you to specify any accessor
name you want (or none at all).
> This seems like something that people must have solved previously (or
> perhaps there is a solution in the standard). That is why I would like
> your input. I need feedback from people who have written big projects
> and therefore must have run into this problem before.
are you sure you just don't want shorter names?
--
-Marco
Ring the bells that still can ring.
Forget your perfect offering.
There is a crack in everything.
That's how the light gets in.
-Leonard Cohen
M Jared Finder <·······@hpalace.com> writes:
> Coming from a C/C++ background I like structures. A lot. The thing
> is, I find DEFSTRUCT's default accessors to be horribly horribly
> verbose. I am looking for a way to reduce the amount of text on
> screen so but still use structures.
>
> For example, for a simple structure of structures, like the following
> require a huge, verbose line for every member access!
>
> (defstruct joystick-axis
> "A joystick axis and its limits"
> index
> min
> max)
>
>
> (defstruct joystick-input-map
> "A map of joystick axes and buttons to our format"
> (left-stick-axis-x :type joystick-axis)
> (left-stick-axis-y :type joystick-axis)
> (right-stick-axis-x :type joystick-axis)
> (right-stick-axis-y :type joystick-axis))
>
> ;; This is way too long and verbose!!!
> (joystick-axis-index (joystick-input-map-left-stick-axis-x joystick))
>
> This is just way too verbose for my tastes! I need a shorter way to
> express what I want to do so I don't get bogged down by details like
> this.
>
> I've noticed that CLOS has a function SLOT-VALUE that adds uniformity
> to the code as well as shortening it. This seems good because I could
> define a macro for member access. Currently I see creating a read
> macro to for a CLOS class to be the best option. That way I could
> write something like the following expression, which I feel is much
> closer to what I want to express.
>
> @(joystick :left-stick-axis :index)
>
> This seems like something that people must have solved previously (or
> perhaps there is a solution in the standard). That is why I would
> like your input. I need feedback from people who have written big
> projects and therefore must have run into this problem before.
>
> -- MJF
it's not hard to write a simple wrapper macro to save typing, for
example-
(defmacro defclassifier (class &rest slotnames)
(let (classname concname super)
(etypecase class
(cons (setq classname (car class)
concname (string-upcase (cadr class)))
(if (> (length class) 2)
(setq super (cddr class))))
(atom (setq classname class
concname (symbol-name classname))))
`(defclass ,classname ,super
,(do* ((slotcdr slotnames (cdr slotcdr))
(slotname (car slotcdr) (car slotcdr))
slottext
(slotform nil nil)
result)
((null slotcdr) (nreverse result))
(etypecase slotname
(cons (setq slottext (symbol-name (car slotname))
slotform (cadr slotname)
slotname (car slotname)))
(atom (setq slottext (symbol-name slotname))))
(push `(,slotname :initarg ,(intern slottext "KEYWORD")
:initform ,slotform
:accessor ,(intern (if (zerop (length concname))
slottext
(concatenate 'string concname "-" slottext)))) result)))))
(the formatting was changed for <79 cols)
This will allow you to say things like:
(defclassifier (seq-mixin "")
(sequence-no 0))
(defclassifier (author "auth" seq-mixin)
id (name "default value") affils)
So you can use a more defstruct-like way of doing your CLOS
classes. The macro can include options that mine doesn't to
allow you to specify other CLOS things. Of course if the
class def gets more complicated you can enhance the macro
or just code it explicitly with DEFCLASS.
--
Jock Cooper
http://www.fractal-recursions.com
I would rearrange your structs a bit and use :cons-name
to shorten up the names. Seems an axis always has a left and right,
so:
(defstruct (joystick-axis (:conc-name))
"A joystick axis and its limits"
xindex
xmin
xmax
yindex
ymin
ymax)
(defstruct (joystick-input-map (:conc-name))
"A map of joystick axes and buttons to our format"
(left-axis :type joystick-axis)
(right-axis :type joystick-axis))
Then access becomes:
(xindex (left-axis joystick))
Wade
Wade Humeniuk wrote:
> I would rearrange your structs a bit and use :cons-name
> to shorten up the names. Seems an axis always has a left and right,
That should be "always has an x and y".
Wade
M Jared Finder <·······@hpalace.com> writes:
> Coming from a C/C++ background I like structures. A lot. The thing
Can you elaborate on why you prefer them over CLOS classes?
Paolo
--
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Recommended Common Lisp libraries/tools (Google for info on each):
- ASDF/ASDF-INSTALL: system building/installation
- CL-PPCRE: regular expressions
- UFFI: Foreign Function Interface
M Jared Finder <·······@hpalace.com> writes:
> @(joystick :left-stick-axis :index)
>
> This seems like something that people must have solved previously
> (or perhaps there is a solution in the standard). That is why I
> would like your input. I need feedback from people who have written
> big projects and therefore must have run into this problem before.
My feedback would be that one should consider defstruct to be
deprecated, and use defclass instead.
--
Frode Vatvedt Fjeld
I'm replying to myself because I wish to reply to everyone, and this
will seem the least favoring of everyone.
M Jared Finder wrote:
[snip]
> ;; This is way too long and verbose!!!
> (joystick-axis-index (joystick-input-map-left-stick-axis-x joystick))
>
> This is just way too verbose for my tastes! I need a shorter way to
> express what I want to do so I don't get bogged down by details like this.
>
> I've noticed that CLOS has a function SLOT-VALUE that adds uniformity to
> the code as well as shortening it. This seems good because I could
> define a macro for member access. Currently I see creating a read macro
> to for a CLOS class to be the best option. That way I could write
> something like the following expression, which I feel is much closer to
> what I want to express.
>
> @(joystick :left-stick-axis :index)
>
> This seems like something that people must have solved previously (or
> perhaps there is a solution in the standard). That is why I would like
> your input. I need feedback from people who have written big projects
> and therefore must have run into this problem before.
Thanks for all of your feedback. I'm not quite satisfied with the
responses as I describe below. I seem to have gotten three types of
responses.
Response 1:
"Your structures/variables are badly named. Use :conc-name to shorten
the accessors if you really need to."
I'll admit that my structures aren't named or structured ideally. In
particular, the STICK-AXIS part of the members of JOYSTICK-INPUT-MAP are
completely redundant, as each x/y coordinate must belong to an axis, and
each axis must be on a stick. That reduces the names to a manageable
level for me. However, I do not see this as a good long term solution,
since I have had structures containing structures containing structures
(for example, a monster holding a target holding a destination vector)
often enough that I see this having the potential to be a problem in the
future.
Response 2:
"Use a good editor that allows you to autocomplete the function names."
My problem isn't with the typing of such long names, it's with the
verbosity of the names. My pet example for this is the built in
mathematical functions. Imagine if + and / were actually written out as
PLUS and DIVIDE, and also were not polymorphic with respect to their
inputs. You would end up having to write functions like
AVERAGE-INTEGERS instead of like AVERAGE:
(defun average-integers (&rest values)
(divide-integer-integer-allowing-ratio
(reduce #'plus-integer-integer values)
(length values)))
(defun average (&rest values)
(/ (reduce #'+ values)
(length values)))
I think it is quite clear that AVERAGE is much easier to understand than
AVERAGE-INTEGERS *because* of its brevity. Having those long names in
the source code is the problem, not having to type them.
Response 3:
"Use these macros instead."
Some of these look quite good, and I am looking into them. I
particularly like WITH-ACCESSORS, though for another problem I was
considering I might have.
While following responses 1 and 3 seems to reduce the problem somewhat,
I do not see it completely removing the verbosity that would occur
sometimes. Has this really not ever been a problem for any of you?
-- MJF
M Jared Finder <·······@hpalace.com> wrote in message news:<··············@uni-berlin.de>...
> My problem isn't with the typing of such long names, it's with the
> verbosity of the names. My pet example for this is the built in
> mathematical functions. Imagine if + and / were actually written out as
> PLUS and DIVIDE, and also were not polymorphic with respect to their
> inputs. You would end up having to write functions like
> AVERAGE-INTEGERS instead of like AVERAGE:
>
> (defun average-integers (&rest values)
> (divide-integer-integer-allowing-ratio
> (reduce #'plus-integer-integer values)
> (length values)))
>
> (defun average (&rest values)
> (/ (reduce #'+ values)
> (length values)))
>
> I think it is quite clear that AVERAGE is much easier to understand than
> AVERAGE-INTEGERS *because* of its brevity. Having those long names in
> the source code is the problem, not having to type them.
If that was true, the following would be better than the first,
despite having the same limitations.
(def ai (&rest v)
(dii (pii @. v) (length v))
As it's pretty clear that it isn't, that it's arguably less clear
what's going on despite being shorter, brevity isn't the relevant
difference. (I could have helped by using /ii and +ii, but if we're
just counting characters, dii and pii is just as good.)
The relevant difference is polymorphism; the polymorphic version would
be better even if it was longer, even if polymorphic division and
addition was poly/ and poly+ and the integer only versions were / and
+.
BTW - addition is conceptually nary. Thus, the (reduce #'+ values)
should be (apply #'+ values).
> While following responses 1 and 3 seems to reduce the problem somewhat,
> I do not see it completely removing the verbosity that would occur
> sometimes. Has this really not ever been a problem for any of you?
Verbosity due to name length hasn't been an issue since I stopped
using punch cards. With auto-complete IDEs, it's even less of an
issue.
Andy Freeman wrote:
> M Jared Finder <·······@hpalace.com> wrote in message news:<··············@uni-berlin.de>...
>
>>My problem isn't with the typing of such long names, it's with the
>>verbosity of the names. My pet example for this is the built in
>>mathematical functions. Imagine if + and / were actually written out as
>>PLUS and DIVIDE, and also were not polymorphic with respect to their
>>inputs. You would end up having to write functions like
>>AVERAGE-INTEGERS instead of like AVERAGE:
>>
>>(defun average-integers (&rest values)
>> (divide-integer-integer-allowing-ratio
>> (reduce #'plus-integer-integer values)
>> (length values)))
>>
>>(defun average (&rest values)
>> (/ (reduce #'+ values)
>> (length values)))
>>
>>I think it is quite clear that AVERAGE is much easier to understand than
>>AVERAGE-INTEGERS *because* of its brevity. Having those long names in
>>the source code is the problem, not having to type them.
>
>
> If that was true, the following would be better than the first,
> despite having the same limitations.
>
> (def ai (&rest v)
> (dii (pii @. v) (length v))
>
> As it's pretty clear that it isn't, that it's arguably less clear
> what's going on despite being shorter, brevity isn't the relevant
> difference. (I could have helped by using /ii and +ii, but if we're
> just counting characters, dii and pii is just as good.)
>
> The relevant difference is polymorphism; the polymorphic version would
> be better even if it was longer, even if polymorphic division and
> addition was poly/ and poly+ and the integer only versions were / and
> +.
Thanks for continuing to reply even though I disagree with you. Not
many people I know are willing to help someone of a differing opinion
understand their point of view.
I agree, to a point. I have found in my experience that once you start
to surpass the 15 character limit for *commonly used idioms*, you slow
down comprehension because of the time taken to read the name.
You stated that +ii and /ii would help be more clear than pii and dii,
which I agree with, because the glyphs + and / have well understood
meanings taught since grade-school. The glyphs ' and #' have a similar
status in Lisp, because they are commonly used throughout code.
My original idea was to use a read macro for a concept that I have found
I have used pervasively in other programming language projects in C,
C++, and assembly. I viewed this as serving the same purpose as ' and
#' in Lisp -- shorten a pervasive concept to a graphically unique and
easily identifiable symbol.
You stated that read macros are, in general, a bad idea. I agree if
there are more than five to ten such macros being used commonly, there
is a problem (keeping all the symbols in one's head will be difficult),
but I would think that if only used for different ideas, they would
greatly help readability. Are there other problems with read-macros
that you see me encountering?
> BTW - addition is conceptually nary. Thus, the (reduce #'+ values)
> should be (apply #'+ values).
That's my C background combining with my inexperience of functional
programming showing itself again. I actually thought of divide as
"accumulate a sum of reals *in a loop* and divide that by the number of
numbers you summed", instead of the much simpler "sum the numbers and
divide by the number of numbers given". I really like how mapcar,
reduce, apply, and such abstract different looping styles being used,
encouraging the code to work at a higher level of abstraction.
-- MJF
M Jared Finder <·······@hpalace.com> wrote in message news:<··············@uni-berlin.de>...
> My original idea was to use a read macro for a concept that I have found
> I have used pervasively in other programming language projects in C,
> C++, and assembly.
Yes, one can write Fortran in Lisp, but when in Rome.... (You'd
introduce a C/C++ macro for something like that? Yech.)
> You stated that read macros are, in general, a bad idea. I agree if
> there are more than five to ten such macros being used commonly,
It's not so much the number as the fact that these read macros appear
in your code and no where else.
I wrote:
> > BTW - addition is conceptually nary. Thus, the (reduce #'+ values)
> > should be (apply #'+ values).
>
> That's my C background combining with my inexperience of functional
> programming showing itself again.
Note that I'm referring to "conceptually nary".
-andy
······@earthlink.net (Andy Freeman) writes:
> BTW - addition is conceptually nary. Thus, the (reduce #'+ values)
> should be (apply #'+ values).
Actually, these two mean very different things. One means "I know
what I'm doing", and the other means "I want my code to break
tomorrow".
Christophe
--
http://www-jcsu.jesus.cam.ac.uk/~csr21/ +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%") (pprint #36rJesusCollegeCambridge)
Andy Freeman <······@earthlink.net> wrote:
+---------------
| BTW - addition is conceptually nary. Thus, the (reduce #'+ values)
| should be (apply #'+ values).
+---------------
Even if (> (LENGTH VALUES) CALL-ARGUMENTS-LIMIT)???
No, I thought not. ;-}
Rather, what we really need is for implementors to add the :MAX-ARGS
keyword as an extension to REDUCE so that it can act like the Unix
shell command "xargs", that is, allow things like this:
(REDUCE #'+ VALUES :MAX-ARGS 35)
which would internally APPLY the function argument successively
to length 34 (to account for the accumulated intermediate result)
subsequences of the sequence arg.
[Note: ":MAX-ARGS T" should probably mean "MAX-ARGS CALL-ARGUMENTS-LIMIT".]
[Note#2: I say "implementors", since while one could write a MY-REDUCE
that took such a :MAX-ARGS keyword and "did the right thing", it would
probably be much more efficient if were implemented in the base system.]
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
····@rpw3.org (Rob Warnock) writes:
> Rather, what we really need is for implementors to add the :MAX-ARGS
> keyword as an extension to REDUCE so that it can act like the Unix
> shell command "xargs", that is, allow things like this:
>
> (REDUCE #'+ VALUES :MAX-ARGS 35)
>
> which would internally APPLY the function argument successively
> to length 34 (to account for the accumulated intermediate result)
> subsequences of the sequence arg.
Why would you want this? I mean, internally I believe e.g. + is likely
to be implemented thusly:
(defun + (&rest numbers)
(reduce #'lowlevel-two-arg-plus numbers :initial-value 0))
So if you think that it would somehow be more efficient to add many
numbers 'at a time' I think that's misguided.
--
Frode Vatvedt Fjeld
Frode Vatvedt Fjeld <······@cs.uit.no> writes:
> ····@rpw3.org (Rob Warnock) writes:
>
> > Rather, what we really need is for implementors to add the :MAX-ARGS
> > keyword as an extension to REDUCE so that it can act like the Unix
> > shell command "xargs", that is, allow things like this:
> >
> > (REDUCE #'+ VALUES :MAX-ARGS 35)
> >
> > which would internally APPLY the function argument successively
> > to length 34 (to account for the accumulated intermediate result)
> > subsequences of the sequence arg.
>
> Why would you want this? I mean, internally I believe e.g. + is likely
> to be implemented thusly:
>
> (defun + (&rest numbers)
> (reduce #'lowlevel-two-arg-plus numbers :initial-value 0))
Actually, it could probably be more complicated, something like:
sort the arguments by types,
sum each kind of numbers separately,
sum the totals.
(with any step being optional depending on the present arguments).
> So if you think that it would somehow be more efficient to add many
> numbers 'at a time' I think that's misguided.
So, indeed, it should be more efficient (and more precise) to add many
numbers "at once".
--
__Pascal Bourguignon__ http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we.
Frode Vatvedt Fjeld <······@cs.uit.no> writes:
>> Why would you want this? I mean, internally I believe e.g. + is likely
>> to be implemented thusly:
>>
>> (defun + (&rest numbers)
>> (reduce #'lowlevel-two-arg-plus numbers :initial-value 0))
Pascal Bourguignon <····@mouse-potato.com> writes:
> Actually, it could probably be more complicated, something like:
> sort the arguments by types,
> sum each kind of numbers separately,
> sum the totals.
> (with any step being optional depending on the present arguments).
It could, but I think an implementation would have to be extremely
careful doing such things if it wanted to achieve an overall
performance gain. I.e I'd believe it if I saw it, but not much sooner ;)
> So, indeed, it should be more efficient (and more precise) to add
> many numbers "at once".
And, if one also takes into account the overhead of managing the
process of applying a function to sublists of tens of elements, and
processing of ditto rest-arguments, etc.. My initial guess would be
you'd lose many times over with this strategy.
I'd be interested to hear evidence to the contrary, though.
--
Frode Vatvedt Fjeld
Frode Vatvedt Fjeld wrote:
> Why would you want this? I mean, internally I believe e.g. + is likely
> to be implemented thusly:
>
> (defun + (&rest numbers)
> (reduce #'lowlevel-two-arg-plus numbers :initial-value 0))
Actually, no... I think in almost every implementation + is a
multimethod, specialized for different argument type combinations
and usually with forms up to some smallish number of arguments
that avoid consing a rest list.
> So if you think that it would somehow be more efficient to add many
> numbers 'at a time' I think that's misguided.
On the contrary, it's pretty likely.
Bear
Ray Dillinger <····@sonic.net> writes:
> Frode Vatvedt Fjeld wrote:
>
>> Why would you want this? I mean, internally I believe e.g. + is likely
>> to be implemented thusly:
>> (defun + (&rest numbers)
>> (reduce #'lowlevel-two-arg-plus numbers :initial-value 0))
>
> Actually, no... I think in almost every implementation + is a
> multimethod, specialized for different argument type combinations
> and usually with forms up to some smallish number of arguments
> that avoid consing a rest list.
I doubt it. There may be compiler transforms, for cases where type
information is known to the compiler, but in the case under discussion
(apply vs. reduce) I think Frode is exactly right. Just to do a quick
roll-call: I have certain knowledge that CMUCL, SBCL and OpenMCL are
implemented as frodef says; examining disassembly in Allegro CL leads
me to suspect a similar implementation strategy[*]; and while I
wouldn't like to claim certain knowledge, reading CLISP source does
not make me think of a multimethod. How would a multimethod help in
(apply #'+ foo), anyway? The &REST list would have to be consed up to
perform the dispatch -- though of course it can be stack allocated, as
can the &rest list in Frode's implementation.
[*] 212: 8b 5f 93 movl ebx,[edi-109] ; EXCL::+_2OP
>> So if you think that it would somehow be more efficient to add many
>> numbers 'at a time' I think that's misguided.
>
> On the contrary, it's pretty likely.
OK, let's see some numbers.
Christophe
····@rpw3.org (Rob Warnock) writes:
> Rather, what we really need is for implementors to add the :MAX-ARGS
> keyword as an extension to REDUCE so that it can act like the Unix
> shell command "xargs", that is, allow things like this:
>
> (REDUCE #'+ VALUES :MAX-ARGS 35)
>
> which would internally APPLY the function argument successively
> to length 34 (to account for the accumulated intermediate result)
> subsequences of the sequence arg.
I don't see how you can make something like this work. The value of
(REDUCE FUNCTION ARGLIST) is in general not equal to the value of
(APPLY FUNCTION ARGLIST). As a trivial example, consider the
following:
CL-USER> (defun average (&rest numbers)
(/ (reduce #'+ numbers)
(length numbers)))
AVERAGE
CL-USER> (apply #'average '(1.0 2.0 3.0))
2.0
CL-USER> (reduce #'average '(1.0 2.0 3.0))
2.25
As far as I can see, your idea would only work if the implementation
had some way of determining whether an n-ary function is
left-associative. This seems very hard to do.
--
Tord Romstad
Tord Kallqvist Romstad <·······@math.uio.no> wrote:
+---------------
| ····@rpw3.org (Rob Warnock) writes:
| > Rather, what we really need is for implementors to add the :MAX-ARGS
| > keyword as an extension to REDUCE so that it can act like the Unix
| > shell command "xargs", that is, allow things like this:
| >
| > (REDUCE #'+ VALUES :MAX-ARGS 35)
| >
| > which would internally APPLY the function argument successively
| > to length 34 (to account for the accumulated intermediate result)
| > subsequences of the sequence arg.
|
| I don't see how you can make something like this work. The value of
| (REDUCE FUNCTION ARGLIST) is in general not equal to the value of
| (APPLY FUNCTION ARGLIST). As a trivial example, consider the
| following:
|
| CL-USER> (defun average (&rest numbers)
| (/ (reduce #'+ numbers)
| (length numbers)))
| AVERAGE
| CL-USER> (apply #'average '(1.0 2.0 3.0))
| 2.0
| CL-USER> (reduce #'average '(1.0 2.0 3.0))
| 2.25
|
| As far as I can see, your idea would only work if the implementation
| had some way of determining whether an n-ary function is
| left-associative. This seems very hard to do.
+---------------
You took the idea out of context. The idea was to use it in the
*definition* of AVERAGE, where you *do* know that #'+ is associative:
(defun average (&rest numbers)
(/ (reduce #'+ numbers :max-args 50)
(length numbers)))
But there's no point in that, since with a &REST arg you're already
limited by CALL-ARGUMENTS-LIMIT, so you might as well just define
AVERAGE as:
(defun average (&rest numbers)
(/ (apply #'+ numbers)
(length numbers)))
Instead, where it really shines is in a LIST-AVERAGE, with a
calling sequence allowing more elements than CALL-ARGUMENTS-LIMIT:
(defun list-average (list-of-numbers)
(/ (reduce #'+ list-of-numbers :max-args call-arguments-limit)
(length list-of-numbers)))
You'd get to pass in more than CALL-ARGUMENTS-LIMIT args, but you
wouldn't have to pay the overhead of calling #'+ once for every arg.
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
M Jared Finder <·······@hpalace.com> wrote:
> While following responses 1 and 3 seems to reduce the problem somewhat,
> I do not see it completely removing the verbosity that would occur
> sometimes. Has this really not ever been a problem for any of you?
Sometimes, to a degree. Solutions that have been particularly
helpfull: :conc-name, using standard-instances instead, and ugly hacks
like this:
(defstruct box
foo
bar)
(defstruct ball
foo
bar)
(declaim (inline foo))
(defun foo (x)
(etypecase x
(box (box-foo x))
(ball (ball-foo x))))
...
Which is quite horrible like this, but can approach cute if you automate
it with macros (eg. define-dispatch-class, finalize-dispatch). As long as
you declare the types (or have enough information handy that the
compiler is able to infer the rest) you'll get static dispatch.
Cheers,
-- Nikodemus "Not as clumsy or random as a C++ or Java.
An elegant weapon for a more civilized time."
M Jared Finder <·······@hpalace.com> writes:
> Response 1:
> "Your structures/variables are badly named. Use :conc-name to shorten
> the accessors if you really need to."
>
> [...] I have had structures containing structures
> containing structures (for example, a monster holding a target holding
> a destination vector) often enough that I see this having the
> potential to be a problem in the future.
If you're not happy with you're giving long names, then give short names!
And with structures containing structures, I don't see where's the problem:
(defstruct (node-of-a-binary-tree
(:conc-name nil) (:constructor nn))
(left :type node-of-a-binary-tree)
(right :type node-of-a-binary-tree))
(let ((node (nn :right (nn :left (nn :right (nn :right))))))
(right (left (right (right node)))))
> While following responses 1 and 3 seems to reduce the problem
> somewhat, I do not see it completely removing the verbosity that would
> occur sometimes. Has this really not ever been a problem for any of
> you?
No, not really not. I've programmed in Objective-C which favors long
names too (but method names can be splitted like in Smalltalk). My
maximum method name was about 86 characters.
--
__Pascal Bourguignon__ http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we.
M Jared Finder <·······@hpalace.com> writes:
> Has this really not ever been a problem for any of you?
Not for me, no. Due to Response 4: Don't use defstruct. It's very
easy, works every time, and the problem simply goes away, along with a
number of other nuisances related to defstruct.
--
Frode Vatvedt Fjeld
Frode Vatvedt Fjeld wrote:
> M Jared Finder <·······@hpalace.com> writes:
>
>>Has this really not ever been a problem for any of you?
>
> Not for me, no. Due to Response 4: Don't use defstruct. It's very
> easy, works every time, and the problem simply goes away, along with a
> number of other nuisances related to defstruct.
What should I use instead of defstruct? Should I use defclass and
define slot accessors for each member? Or use slot-value and directly
access the data?
-- MJF
M Jared Finder <·······@hpalace.com> writes:
> Frode Vatvedt Fjeld wrote:
>> M Jared Finder <·······@hpalace.com> writes:
>>
>>>Has this really not ever been a problem for any of you?
>> Not for me, no. Due to Response 4: Don't use defstruct. It's very
>> easy, works every time, and the problem simply goes away, along with a
>> number of other nuisances related to defstruct.
>
> What should I use instead of defstruct? Should I use defclass and
> define slot accessors for each member? Or use slot-value and directly
> access the data?
Use DEFCLASS and define accessors for each member (using the :accessor
slot option.)
-Peter
--
Peter Seibel ·····@javamonkey.com
Lisp is the red pill. -- John Fraser, comp.lang.lisp
Peter Seibel wrote:
> M Jared Finder <·······@hpalace.com> writes:
>>
>>What should I use instead of defstruct? Should I use defclass and
>>define slot accessors for each member? Or use slot-value and directly
>>access the data?
>
>
> Use DEFCLASS and define accessors for each member (using the :accessor
> slot option.)
And according to my tests, that's polymorphic as well! Thanks, I was
not aware that DEFCLASS's accessor functions were polymorphic.
-- MJF
M Jared Finder <·······@hpalace.com> writes:
> What should I use instead of defstruct? Should I use defclass and
> define slot accessors for each member? Or use slot-value and
> directly access the data?
Yes, use defclass and the :reader, :writer, and :accessor slot-options
(class elements are usually referred to as "slots").
Whether to use slot-value and/or accessor methods is a design issue,
but I think in general it makes sense to use accessor methods by
default because these are the most flexible and easily changed and
specialized. Then sometimes slot-value comes in handy for some special
situations. Think of the accessor methods as defining the class's
protocol (API), and slot-value as an under-the-hood primitive for
implementing such protocols.
Also, fyi, most (if not all) CLOS implementations support
specialization of the slot access protocol via the
mop:slot-value-using-class accessor method. But this fits in I suppose
at the under-the-under-the-hood level wrt. what I described above.
--
Frode Vatvedt Fjeld
M Jared Finder wrote:
> I'm replying to myself because I wish to reply to everyone, and this
> will seem the least favoring of everyone.
>
> M Jared Finder wrote:
> [snip]
>
> Response 1:
> "Your structures/variables are badly named. Use :conc-name to shorten
> the accessors if you really need to."
>
> I'll admit that my structures aren't named or structured ideally. In
> particular, the STICK-AXIS part of the members of JOYSTICK-INPUT-MAP are
> completely redundant, as each x/y coordinate must belong to an axis, and
> each axis must be on a stick. That reduces the names to a manageable
> level for me. However, I do not see this as a good long term solution,
> since I have had structures containing structures containing structures
> (for example, a monster holding a target holding a destination vector)
> often enough that I see this having the potential to be a problem in the
> future.
>
Here is a real life example of me handling this depth of access issue.
In this example I use with-slots and with-badge (which uses symbol-macrolet)
to handle the depth (and shorten the access names). A caveat, LW allows use
of slot-value with structures, other CLs might not.
(defclass badge (capi:output-pane)
((entries :initform nil :initarg :entries :accessor entries :type list)
(date :initform (calendar:current-date) :initarg :date :type list :accessor badge-date)
(entry-position :initform 0 :accessor entry-position :allocation :class :type fixnum)
(milestone :initform nil :initarg :milestone :accessor milestone))
(:default-initargs
:input-model '(((:button-1 :press) simple-badge-select)
(:post-menu popup-badge-menu))
:visible-border nil
:background 'win32:color_3dface
:foreground :black
:min-width 80 :max-width 80
:min-height 92 :max-height 92
:display-callback #'draw-badge))
(defmacro with-badge (badge &rest body)
`(symbol-macrolet ((%entries (slot-value ,badge 'entries))
(%date (slot-value ,badge 'date))
(%milestone (slot-value ,badge 'milestone))
(%entry-position (slot-value ,badge 'entry-position))
(%current-entry (nth %entry-position %entries)))
,@body))
(defun draw-badge (badge &optional x y width height)
(declare (ignore x y width height) (type badge badge))
(with-slots (selected-date selected-dates) (capi:element-interface badge)
(with-badge badge
(if (null (run-distance %current-entry))
(progn
(pixblt-image badge *empty-badge*)
(draw-badge-date badge %date)
(when %milestone (pixblt-image badge *milestone*))
(draw-distance-summary badge nil
(run-scheduled-distance %current-entry)))
(progn
(draw-badge-subimage badge
(run-colour %current-entry) *badge-images*)
(draw-badge-subimage badge (run-type %current-entry)
*runner-images*)
(draw-badge-subimage badge (run-weather %current-entry)
*weather-images*)
(draw-badge-subimage badge (run-how-felt %current-entry)
*felt-images*)
(when %milestone (pixblt-image badge *milestone*))
(draw-badge-date badge %date :white)
(draw-distance-summary badge
(run-distance %current-entry)
(run-scheduled-distance %current-entry)
:white)))
(when (calendar:date= %date selected-date)
(draw-highlight badge)))))
Wade
M Jared Finder wrote:
> While following responses 1 and 3 seems to reduce the problem somewhat,
> I do not see it completely removing the verbosity that would occur
> sometimes. Has this really not ever been a problem for any of you?
I think it's a cultural difference. In C'ish languages you have a
lot of clues as to what's going on - much of it because special
semantics attach to punctuation characters. This is absent in
LISP: everything has the same surface syntax with open-paren,
function or macro being called, arguments if any, close paren.
So in Lisp, names are carrying more information because you rely on
the names of things to tell you what's going on rather than on the
surface syntax. C programmers often respond to the paren based
syntax with fear and confusion; I think it's partly because they
rely on a highly punctuated syntax to tell them what's going on,
and when the surface syntax is all uniform as in lisps, it looks
"opaque" to them. But then if they stick with it they start
actually reading the names, and the problem goes away.
Bear