From: Alan Malloy on
I'm trying to represent a hierarchical data structure, one with a lot of
sub-trees which are each identical but with slightly different
modifiers. This seems like a perfect example to design a domain-specific
language for concisely specifying data files (for now, the user can type
these by hand), which I'd like to expand (presumably with macros) into a
tree of fully-specified nodes so that it's easier to determine what
properties a given node has. My plan is to have the user define
"template" sub-trees (which may contain other templates) and then set
their modifiers. A simple example using less obscure object-types:

(template building
(...some specification for buildings))
(template suburb
(neighborhood uptown
(speed-limit 25)
(building house)
(building park))
(neighborhood downtown
(speed-limit 35)
(building strip-mall)))
(template urban-area
(...same kind of stuff as suburb))
(city
(name "New York")
(rent-per-month 10000)
(urban-area))


speed-limit, name, and rent-per-month are properties that should apply
to each sibling and all of their descendant nodes, so that if, after
expansion, I have a reference to a strip-mall building I don't have to
trace up the tree until I find a speed-limit definition. There are a
fixed number of such persistent properties, so they can be hard-coded,
but the definition of how to construct a city is up to the user, and
will involve deeply-nested templates. The final output is just a tree of
buildings (they nest within each other, which is where my "building"
example breaks down) with varying properties.

So I know what I want my data format to look like, but I don't really
know how to get started on defining the macros that will be needed to
transform this into a more-usable in-memory representation. Some sample
output might be a list like:
'(...
(:type park :name "New York Park" :speed-limit 35
:rent-per-month 10000 :neighborhood downtown)...)
#don't have to specify "building", because everything is a building

Can someone give me a push in the right direction?

--
Cheers,
Alan (San Jose, California, USA)
From: Tim X on
Alan Malloy <alan.NO.SPAM(a)malloys.org> writes:

> I'm trying to represent a hierarchical data structure, one with a lot of
> sub-trees which are each identical but with slightly different modifiers. This
> seems like a perfect example to design a domain-specific language for
> concisely specifying data files (for now, the user can type these by hand),
> which I'd like to expand (presumably with macros) into a tree of
> fully-specified nodes so that it's easier to determine what properties a given
> node has. My plan is to have the user define "template" sub-trees (which may
> contain other templates) and then set their modifiers. A simple example using
> less obscure object-types:
>
> (template building
> (...some specification for buildings))
> (template suburb
> (neighborhood uptown
> (speed-limit 25)
> (building house)
> (building park))
> (neighborhood downtown
> (speed-limit 35)
> (building strip-mall)))
> (template urban-area
> (...same kind of stuff as suburb))
> (city
> (name "New York")
> (rent-per-month 10000)
> (urban-area))
>
>
> speed-limit, name, and rent-per-month are properties that should apply to each
> sibling and all of their descendant nodes, so that if, after expansion, I have
> a reference to a strip-mall building I don't have to trace up the tree until I
> find a speed-limit definition. There are a fixed number of such persistent
> properties, so they can be hard-coded, but the definition of how to construct
> a city is up to the user, and will involve deeply-nested templates. The final
> output is just a tree of buildings (they nest within each other, which is
> where my "building" example breaks down) with varying properties.
>
> So I know what I want my data format to look like, but I don't really know how
> to get started on defining the macros that will be needed to transform this
> into a more-usable in-memory representation. Some sample output might be a
> list like:
> '(...
> (:type park :name "New York Park" :speed-limit 35
> :rent-per-month 10000 :neighborhood downtown)...)
> #don't have to specify "building", because everything is a building
>
> Can someone give me a push in the right direction?

My advice would be to forget about macros initially. I think trying to
code macros now will be counter productive because I'm not sure you
really have a clear idea or enough understanding of what is needed yet.

From your description, I expect CLOS might be closer to the type of
abstraction you are looking for, but lets leave that aside for now. YOu
can look at that later as, like macros, you will probably appreciate it
better once you have grasped the problem better and gained some
understanding of more basic abstractions. It is possible that later, a
different type of abstraction that is better suited to the problem you
are addressing will become evident and CLOS may not buy you much after all.

I would start by just defining some functions that abstract the
creation/update/printing of your basic data structures. Once you have
these functions defined, you will be in a better position to judge
whether your initial data bastraction is the right one and you will have
a better feel for it. (depending on the application, you may also want
to include a couple of the most common processing functions - its no
good having an abstraction you can create and modify very easily if at
the same time, you have to jump through a million hoops to perform the
basic actions of the application). Once you have done this, you will
have a better feel for things and udnerstand where/how macros could make
things better. I'm assuming your thinking of some kind of DSL to manage
these data elements. Depending on the number/size of the data elements
you plan to work with, you may find structure you have defined above is
inefficient or difficult to manage. For example, even though all nodes
in your structure don't need the same elements or they can have elements
that are easily derived from parent nodes, it may be better to repeat
data elements or have elements default to nil if that makes your code
simpler, clearer and easier to maintain. You may find that rather than
keywords, set positions in the list is more efficient or that a list of
structures is better or .....

The point is that if you define your functions well, it will hide the
underlying structure. You will then be able to change/modify that
structure without breaking your interface. This approach is IMO a more
lispy way to work. At least it is for me. I start with a bit of an idea,
fire up the repl and start coding/experimenting. I don't sit down and
define my data structures in deatil from the start. I tend to start
simple and become more complex as I find a need. I do tend to have a
general idea of what I think is a good starting abstraction and often,
my initial choice turns out to be correct or reasonably correct.
However, I'm always ready to rethink the problem and if necessary, try a
new approach. If I find the code appears to be getting overly complex
when doing what should be fairly simple and straight-forward things, it
generally indicates there is a problem with my abstraction and I need to
step back, think for a few minutes and start some new experiments.

HTH

Tim

--
tcross (at) rapttech dot com dot au
From: Paul Donnelly on
Alan Malloy <alan.NO.SPAM(a)malloys.org> writes:

> So I know what I want my data format to look like, but I don't really
> know how to get started on defining the macros that will be needed to
> transform this into a more-usable in-memory representation. Some
> sample output might be a list like:
> '(...
> (:type park :name "New York Park" :speed-limit 35
> :rent-per-month 10000 :neighborhood downtown)...)
> #don't have to specify "building", because everything is a building
>
> Can someone give me a push in the right direction?

If it's a data file you're working with, you don't need macros. Just
read the data then construct appropriate structures... or perhaps use
structures and read them directly.

I'm not really sure what you're trying to do, but could you just keep a
list of templates defined, then substitute them into your data
structures as you read them? Something like this no doubt buggy code.

(defun process (data)
(let (templates)
(reverse (let (o)
(dolist (d data o)
(case (car d)
(template (push (cdr d) templates))
(t (push (expand d) o))))))))

(defun expand (data)
(loop for d in data
collect (if (atom d)
d
(or (cdr (assoc (car d) *templates*))
d))))

(process '((template foo c) (hi) (city (foo))))
=> ((HI) (CITY (C)))
From: Pascal J. Bourguignon on
Tim X <timx(a)nospam.dev.null> writes:

> Alan Malloy <alan.NO.SPAM(a)malloys.org> writes:
>
>> I'm trying to represent a hierarchical data structure, one with a lot of
>> sub-trees which are each identical but with slightly different modifiers. This
>> seems like a perfect example to design a domain-specific language for
>> concisely specifying data files (for now, the user can type these by hand),
>> which I'd like to expand (presumably with macros) into a tree of
>> fully-specified nodes so that it's easier to determine what properties a given
>> node has. My plan is to have the user define "template" sub-trees (which may
>> contain other templates) and then set their modifiers. A simple example using
>> less obscure object-types:
>>
>> (template building
>> (...some specification for buildings))
>> (template suburb
>> (neighborhood uptown
>> (speed-limit 25)
>> (building house)
>> (building park))
>> (neighborhood downtown
>> (speed-limit 35)
>> (building strip-mall)))
>> (template urban-area
>> (...same kind of stuff as suburb))
>> (city
>> (name "New York")
>> (rent-per-month 10000)
>> (urban-area))
>>
>>
>> speed-limit, name, and rent-per-month are properties that should apply to each
>> sibling and all of their descendant nodes, so that if, after expansion, I have
>> a reference to a strip-mall building I don't have to trace up the tree until I
>> find a speed-limit definition. There are a fixed number of such persistent
>> properties, so they can be hard-coded, but the definition of how to construct
>> a city is up to the user, and will involve deeply-nested templates. The final
>> output is just a tree of buildings (they nest within each other, which is
>> where my "building" example breaks down) with varying properties.
>>
>> So I know what I want my data format to look like, but I don't really know how
>> to get started on defining the macros that will be needed to transform this
>> into a more-usable in-memory representation. Some sample output might be a
>> list like:
>> '(...
>> (:type park :name "New York Park" :speed-limit 35
>> :rent-per-month 10000 :neighborhood downtown)...)
>> #don't have to specify "building", because everything is a building
>>
>> Can someone give me a push in the right direction?
>
> I would start by just defining some functions that abstract the
> creation/update/printing of your basic data structures. Once you have
> these functions defined, you will be in a better position to judge
> whether your initial data bastraction is the right one and you will have
> a better feel for it.

Indeed. Macros would be useful only if you wanted to integrate these
data definition (the templates) and data manipulation (the "insert" data
declarations) languages into normal lisp code.

If you keep these data in separate files, or separate input streams
(ie. user input), then you can merely define functions to read and
process them:

(defun load-area-data (file &key verbose print
(if-does-not-exist :error)
(external-format :default))
...
(loop
...
collect (read-area-data stream)
...))


(defun read-area-data (&optional (input-stream *standard-input*)
(eof-error-p t) eof-value)
(let* ((my-eof-value (load-time-value (gensym)))
(form (read stream eof-error-p my-eof-value)))
(if (eq form my-eof-value)
eof-value
(eval-area-data form))))

(defvar *templates* '() "The collection of templates defined so far.")

(defun eval-area-data (form)
(if (atom form)
(error "~S cannot be an Area data expression.~%" form)
(case (first form)
((template) (destructuring-bind (op ...) form
...
(register-template ...)))
(otherwise
;; parse the form to find called up templates
;; and build the data objects.
...))))




--
__Pascal Bourguignon__
From: Alan Malloy on
Pascal J. Bourguignon wrote:
> Tim X <timx(a)nospam.dev.null> writes:
>
>> Alan Malloy <alan.NO.SPAM(a)malloys.org> writes:
>>
>>> I'm trying to represent a hierarchical data structure, one with a lot of
>>> sub-trees which are each identical but with slightly different modifiers. This
>>> seems like a perfect example to design a domain-specific language for
>>> concisely specifying data files (for now, the user can type these by hand),
>>> which I'd like to expand (presumably with macros) into a tree of
>>> fully-specified nodes so that it's easier to determine what properties a given
>>> node has. My plan is to have the user define "template" sub-trees (which may
>>> contain other templates) and then set their modifiers. A simple example using
>>> less obscure object-types:
>>>
>>> (template building
>>> (...some specification for buildings))
>>> (template suburb
>>> (neighborhood uptown
>>> (speed-limit 25)
>>> (building house)
>>> (building park))
>>> (neighborhood downtown
>>> (speed-limit 35)
>>> (building strip-mall)))
>>> (template urban-area
>>> (...same kind of stuff as suburb))
>>> (city
>>> (name "New York")
>>> (rent-per-month 10000)
>>> (urban-area))
>>>
>>>
>>> speed-limit, name, and rent-per-month are properties that should apply to each
>>> sibling and all of their descendant nodes, so that if, after expansion, I have
>>> a reference to a strip-mall building I don't have to trace up the tree until I
>>> find a speed-limit definition. There are a fixed number of such persistent
>>> properties, so they can be hard-coded, but the definition of how to construct
>>> a city is up to the user, and will involve deeply-nested templates. The final
>>> output is just a tree of buildings (they nest within each other, which is
>>> where my "building" example breaks down) with varying properties.
>>>
>>> So I know what I want my data format to look like, but I don't really know how
>>> to get started on defining the macros that will be needed to transform this
>>> into a more-usable in-memory representation. Some sample output might be a
>>> list like:
>>> '(...
>>> (:type park :name "New York Park" :speed-limit 35
>>> :rent-per-month 10000 :neighborhood downtown)...)
>>> #don't have to specify "building", because everything is a building
>>>
>>> Can someone give me a push in the right direction?
>> I would start by just defining some functions that abstract the
>> creation/update/printing of your basic data structures. Once you have
>> these functions defined, you will be in a better position to judge
>> whether your initial data bastraction is the right one and you will have
>> a better feel for it.
>
> Indeed. Macros would be useful only if you wanted to integrate these
> data definition (the templates) and data manipulation (the "insert" data
> declarations) languages into normal lisp code.
>
> If you keep these data in separate files, or separate input streams
> (ie. user input), then you can merely define functions to read and
> process them:
>
> (defun load-area-data (file &key verbose print
> (if-does-not-exist :error)
> (external-format :default))
> ...
> (loop
> ...
> collect (read-area-data stream)
> ...))
>
>
> (defun read-area-data (&optional (input-stream *standard-input*)
> (eof-error-p t) eof-value)
> (let* ((my-eof-value (load-time-value (gensym)))
> (form (read stream eof-error-p my-eof-value)))
> (if (eq form my-eof-value)
> eof-value
> (eval-area-data form))))
>
> (defvar *templates* '() "The collection of templates defined so far.")
>
> (defun eval-area-data (form)
> (if (atom form)
> (error "~S cannot be an Area data expression.~%" form)
> (case (first form)
> ((template) (destructuring-bind (op ...) form
> ...
> (register-template ...)))
> (otherwise
> ;; parse the form to find called up templates
> ;; and build the data objects.
> ...))))
>
>
>
>

Hmmm, thanks. I had somehow gotten the idea that the idiomatic way to
use sexps to store data in lisp is to have appropriate macros defined so
that when you read/eval the "data", it is transformed into code that
creates the in-memory data structure you want. I've written a few simple
I/O functions for reading basic text data, and if the "right" way to do
this is to read my tree (or other abstraction, as Paul points out)
through a set of actual functions it should be a fair bit easier for me
to grasp anyway.

--
Cheers,
Alan (San Jose, California, USA)
 |  Next  |  Last
Pages: 1 2 3
Prev: hunchentoot start
Next: (expt 2 #c(2d0 0))?