From: Bobby Toser on
hi, i'm learning lisp. :)

i have a lot of code in my game that looks like this:

(defstruct monster name health powers)

(defparameter monster-group
(list
(make-monster :name "greg" :health 100)
(make-monster :name "bobby" :health 200 :powers
(list :flying))))

i read in this book that you can type less (i want my friends to
help!) witha macro so i thought that i can do this because it is so
much easier :)

(defmonster-group monster-group
("greg" 100)
("bobby" 200 :flying))

but i cant get it to work!

i started with this, but i keep getting really confused at the end.

(defmacro defmonster-group (name &rest rest)
(let ((monsters (loop for monster in rest collecting monster)))
`(defparameter ,name
(list ,@(loop for monster in monsters ????

can you help me? can i find a good code that shows me how to learn
this too? im trying practical lisp on the internet but sometimes i
think i dont get it.

thanks!!

bobby
From: D Herring on
On 07/18/2010 11:30 AM, Bobby Toser wrote:
....
> (defstruct monster name health powers)
>
> (defparameter monster-group
> (list
> (make-monster :name "greg" :health 100)
> (make-monster :name "bobby" :health 200 :powers
> (list :flying))))
>
> i read in this book that you can type less (i want my friends to
> help!) witha macro so i thought that i can do this because it is so
> much easier :)
>
> (defmonster-group monster-group
> ("greg" 100)
> ("bobby" 200 :flying))
>
> but i cant get it to work!
....


A couple points:
* Use plain functions when possible. Macros are only needed for
processing arguments without evaluating them, introducing variables, etc.
* Decompose your problem into smaller parts.

Here, your defmonster-group does two or three separate things. It
creates a parameter, and it populates it with a list of monsters using
a custom syntax. In this case, a bottom-up construction seems natural.

Here's a solution for the last of those tasks.
(defun monster-builder (name health &rest powers)
(make-monster :name name
:health health
:powers powers))

Then we build on that
(defmacro monster-list (&rest monsters)
(cons 'list
(loop for monster in monsters
collecting (apply 'monster-builder monster))))

And finally get what you asked for
(defmacro defmonster-group (name &rest monsters)
`(defparameter ,name (monster-list ,@monsters)))


and a simple test example.
(defmonster-group *test* ("greg" 100) ("bobby" 200 :flying))

*test* ->
(#S(MONSTER :NAME "greg" :HEALTH 100 :POWERS NIL)
#S(MONSTER :NAME "bobby" :HEALTH 200 :POWERS (:FLYING)))


- Daniel
From: joswig on
On 18 Jul., 17:30, Bobby Toser <bobbyto...(a)hotmail.com> wrote:
> hi, i'm learning lisp. :)
>
> i have a lot of code in my game that looks like this:
>
> (defstruct monster name health powers)
>
> (defparameter monster-group
>   (list
>      (make-monster :name "greg" :health 100)
>       (make-monster :name "bobby" :health 200 :powers
> (list :flying))))
>
> i read in this book that you can type less (i want my friends to
> help!) witha macro so i thought that i can do this because it is so
> much easier :)
>
> (defmonster-group monster-group
>        ("greg" 100)
>        ("bobby" 200 :flying))
>
> but i cant get it to work!
>
> i started with this, but i keep getting really confused at the end.
>
> (defmacro defmonster-group (name &rest rest)
>   (let ((monsters (loop for monster in rest collecting monster)))
>     `(defparameter ,name
>        (list ,@(loop for monster in monsters ????
>
> can you help me? can i find a good code that shows me how to learn
> this too? im trying practical lisp on the internet but sometimes i
> think i dont get it.

If you want to create a list of monsters from some data, write a
function for that.
There is not much use of a macro for that.

>
> thanks!!
>
> bobby

From: Pascal J. Bourguignon on
Bobby Toser <bobbytoser(a)hotmail.com> writes:

> hi, i'm learning lisp. :)
>
> i have a lot of code in my game that looks like this:
>
> (defstruct monster name health powers)
>
> (defparameter monster-group

If you want to avoid a couple of days of debugging sometime in a not
too far away future, do name your special variables with stars!

(defparameter *monster-group*
...




> (list
> (make-monster :name "greg" :health 100)
> (make-monster :name "bobby" :health 200 :powers
> (list :flying))))
>
> i read in this book that you can type less (i want my friends to
> help!) witha macro so i thought that i can do this because it is so
> much easier :)
>
> (defmonster-group monster-group
> ("greg" 100)
> ("bobby" 200 :flying))
>
> but i cant get it to work!
>
> i started with this, but i keep getting really confused at the end.
>
> (defmacro defmonster-group (name &rest rest)
> (let ((monsters (loop for monster in rest collecting monster)))
> `(defparameter ,name
> (list ,@(loop for monster in monsters ????
>
> can you help me? can i find a good code that shows me how to learn
> this too? im trying practical lisp on the internet but sometimes i
> think i dont get it.

Macros are functions. So if you can write a function, you can write a
macro. And of course, if you cannot write a macro, it's because you
cannot write a function. So start by concentrating on writing
functions.


Namely, given a list such as:

(("greg" 100)
("bobby" 200 :flying))

there is nothing preventing you to write a function that would build a
list such as:

(#<monster :name "greg" :health 100 :power ()>
#<monster :name "bobby" :health 200 :power (:flying)>)


Hint: you could use MAPCAR


Therefore you could write:

(defparameter *monster-group*
(monsters '(("greg" 100)
("bobby" 200 :flying))))

without a need for any macro.


--
__Pascal Bourguignon__ http://www.informatimago.com/
From: Joshua Taylor on
On 2010.07.18 12:08 PM, D Herring wrote:
> Here's a solution for the last of those tasks.
> (defun monster-builder (name health &rest powers)
> (make-monster :name name
> :health health
> :powers powers))

This part can already be done with the defstruct.

(defstruct (monster
(:constructor monster-builder (name health &rest powers))
(:constructor make-monster)) ; for default constructor
name
health
powers)
=> MONSTER

(make-monster :name "name" :health 34 :powers (list 'fire 'water))
=> #S(MONSTER :NAME "name" :HEALTH 34 :POWERS (FIRE WATER))

(monster-builder "other-name" 38 (list 'water 'earth))
=> #S(MONSTER :NAME "other-name" :HEALTH 38 :POWERS ((WATER EARTH)))

//JT