From: TomSW
Subject: Matching and unpacking arbitrary data structures
Date: 
Message-ID: <019523aa-150e-4739-9edd-2d0e3482d0dd@21g2000hsj.googlegroups.com>
I've recently started programming Lisp at work, and often find myself
having to unpack a data structure (eg, a plist containing plists
containing lists) and then filter and process it as a list.

It strikes me this is a kind of data query, and I was wondering if
there was a neat way to do it, a kind of SQL for objects. This would
avoid what seems always to happen - the query code gets entangled in
the code that processes the data, making it harder to read what the
function is "really" doing.

For example, I might have to do this:

;; Yuk!
(do.plist (date priority.and.equipment
(fn.that.returns.nested.data :today)
 (declare (ignore date))
 (do.plist (priority equipment priority.and.equipment)
   (declare (ignore priority))
   (destructuring-bind (item.id item.name item.stock.id) equipment
     (when (member item.id my.list.of.relevant.ids)
       (finally.do.something.with item.id item.stock.id))))))

Whereas I'd like to do something a bit more like this:

;; nicer?
(do.unpack (item.id item.stock.id)
	   (fn.that.returns.nested.data :today)
	   (:plist date
	    (:plist prio
	     (:list
	      (:list item.id item.name item.stock.id))))
  (when (member item.id my.list.of.relevant.ids)
    (finally.do.something.with item.id item.stock.id)))

... although ideally, the filtering would also be done by the
do.unpack macro.

Is there an established way to do this?
Thanks
Tom SW

ps: yes, I could try and persuade my colleagues not to use plists, or
provide functions that give me exactly the data I want when I want it,
but I don't think that'll work :)

From: Zach Beane
Subject: Re: Matching and unpacking arbitrary data structures
Date: 
Message-ID: <m38x3gcd13.fsf@unnamed.xach.com>
TomSW <·············@gmail.com> writes:

> It strikes me this is a kind of data query, and I was wondering if
> there was a neat way to do it, a kind of SQL for objects. This would
> avoid what seems always to happen - the query code gets entangled in
> the code that processes the data, making it harder to read what the
> function is "really" doing.

You could separate the concerns by having a selection function take a
function is called on a record and returns true if a record is
applicable. Many built-in functions work this way.

I wrote a little bit about generating functions to query records here:

  http://xach.livejournal.com/131456.html

It's more about string matching than structure matching, but I hope
you can see how the functional approach would be applicable in your
situation.

Also, I find your use of dots in symbols really hard to read. Dashes,
man, dashes! :)

Zach
From: TomSW
Subject: Re: Matching and unpacking arbitrary data structures
Date: 
Message-ID: <83793e4c-65a2-4b33-9eb4-3ecdeb8b2ab8@d4g2000prg.googlegroups.com>
On 27 Dez, 16:34, Zach Beane <····@xach.com> wrote:

> You could separate the concerns by having a selection function take a
> function is called on a record and returns true if a record is
> applicable. Many built-in functions work this way.

When "querying" a nested data structure to extract flat records, it
would be more efficient to apply tests as early as possible, which is
why separating the querying and filtering concerns isn't necessarily a
good idea. I was really thinking of something closer to SQL or regexps
for arbitrary objects.

> I wrote a little bit about generating functions to query records here:
>
>  http://xach.livejournal.com/131456.html
>
> It's more about string matching than structure matching, but I hope
> you can see how the functional approach would be applicable in your
> situation.

Thanks, it's interesting.

> Also, I find your use of dots in symbols really hard to read. Dashes,
> man, dashes! :)

Sorry, it's a work convention I forgot to turn off. It's to
distinguish our functions from CL ones...

Apropos, we have another convention, which is documenting complex
return values using BNF. Surely that BNF could be used to create
destructuring macros / parsers?
From: Rob Warnock
Subject: Re: Matching and unpacking arbitrary data structures
Date: 
Message-ID: <QeWdnWlFZvDcSOnanZ2dnUVZ_ramnZ2d@speakeasy.net>
TomSW  <·············@gmail.com> wrote:
+---------------
| I've recently started programming Lisp at work, and often find myself
| having to unpack a data structure (eg, a plist containing plists
| containing lists) and then filter and process it as a list.
| 
| It strikes me this is a kind of data query, and I was wondering if
| there was a neat way to do it, a kind of SQL for objects. ...
+---------------

Have you bought/read Peter Seibel's "Practical Common Lisp" yet?
It sounds like the simple in-memory database shown in Chapter 3
might be just what you're looking for. It starts from scratch and
works up to being able to write SQL-ish queries such as this one:

    CL-USER> (select (where :title "Give Us a Break" :ripped t))
    ((:TITLE "Give Us a Break" :ARTIST "Limpopo" :RATING 10 :RIPPED T))

Chapter 27 takes this further, introducing multiple tables, schema
definitions, and a richer SELECT operator [that also returns tables
as its results, which can be fed to other SELECTs, etc.], e.g.:

    ;; Select a sorted list of artists with songs in the genre "Rock"
    (select
      :columns :artist
      :from *mp3s*
      :where (matching *mp3s* :genre "Rock")
      :distinct t
      :order-by :artist)


-Rob

p.s. Oh, o.k., you can also read Chapters 3 & 27 here:

    http://gigamonkeys.com/book/practical-a-simple-database.html
    http://gigamonkeys.com/book/practical-an-mp3-database.html

But buy the hardcopy book anyway. It's worth it.

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: TomSW
Subject: Re: Matching and unpacking arbitrary data structures
Date: 
Message-ID: <54bf9b3f-1db3-43e2-a64c-4b42e75a682a@21g2000hsj.googlegroups.com>
On Dec 28, 10:51 am, ····@rpw3.org (Rob Warnock) wrote:

> Have you bought/read Peter Seibel's "Practical Common Lisp" yet?
> It sounds like the simple in-memory database shown in Chapter 3
> might be just what you're looking for. It starts from scratch and
> works up to being able to write SQL-ish queries such as this one:

The unpacking part is more important than the querying part - the data
is a given, it's its structure I have the problem with. A regular
expression lets you iterate all the matches on a given pattern in a
string: I want to be able to do that with other things (like nested
plists), not just strings.