Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Martin Fowler talks about Lisp...

534 views
Skip to first unread message

Pascal Costanza

unread,
Jul 1, 2005, 4:34:07 PM7/1/05
to
...and favorably so. See
http://martinfowler.com/articles/languageWorkbench.html


Pascal

--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/

Joe Marshall

unread,
Jul 1, 2005, 5:10:57 PM7/1/05
to
Pascal Costanza <p...@p-cos.net> writes:

I noticed that Tiobe ( http://www.tiobe.com/ )
now rates Lisp as a `Mainstream Language' with an `A' rating.

What is the world coming to?


Rainer Joswig

unread,
Jul 1, 2005, 6:43:07 PM7/1/05
to
Am 01.07.2005 22:34 Uhr schrieb "Pascal Costanza" unter <p...@p-cos.net> in
3ilnm1F...@individual.net:

> ...and favorably so. See
>
> http://martinfowler.com/articles/languageWorkbench.html
>
>
> Pascal


His example in some primitive way:


The macro does most of the work. It generates a class for
the data and two methods for parsing the lines.


(defmacro defmapping (name mapping &body fields)
`(progn
(defclass ,name ()
,(loop for (nil nil slot) in fields
collect slot))
(defmethod find-mapping-class-name ((mapping (eql ',(intern mapping))))
',name)
(defmethod parse-line-for-class (line (class-name (eql ',(intern
name))))
(let ((object (make-instance class-name)))
(loop for (start end slot) in ',fields
do (setf (slot-value object slot) (subseq line start (1+
end))))
object))))

Now we use the macro to define the mappings:


(defmapping service-call "SVCL"
(04 18 customer-name)
(19 23 customer-id)
(24 27 call-type-code)
(28 35 date-of-call-string)))

(defmapping usage "USGE"
(04 08 customer-id)
(09 22 customer-name)
(30 30 cycle)
(31 36 read-date))


The example lines:

(defparameter *test-lines*
"SVCLFOWLER 10101MS0120050313.........................
SVCLHOHPE 10201DX0320050315........................
SVCLTWO x10301MRP220050329..............................
USGE10301TWO x50214..7050329...............................")


Let's try it out:


CL-USER 21 > (map nil 'describe
(with-input-from-string (stream *test-lines*)
(loop for line = (read-line stream nil nil)
while line
collect (parse-line-for-class line (find-mapping-class-name
(intern (subseq line 0 4)))))))

#<SERVICE-CALL 10082C7F> is a SERVICE-CALL
CUSTOMER-NAME "FOWLER "
CUSTOMER-ID "10101"
CALL-TYPE-CODE "MS01"
DATE-OF-CALL-STRING "20050313"
#<SERVICE-CALL 100828A3> is a SERVICE-CALL
CUSTOMER-NAME "HOHPE "
CUSTOMER-ID "10201"
CALL-TYPE-CODE "DX03"
DATE-OF-CALL-STRING "20050315"
#<SERVICE-CALL 100824BB> is a SERVICE-CALL
CUSTOMER-NAME "TWO x"
CUSTOMER-ID "10301"
CALL-TYPE-CODE "MRP2"
DATE-OF-CALL-STRING "20050329"
#<USAGE 100820CF> is an USAGE
CUSTOMER-ID "10301"
CUSTOMER-NAME "TWO x"
CYCLE "7"
READ-DATE "050329"

Andras Simon

unread,
Jul 2, 2005, 7:08:54 AM7/2/05
to
Joe Marshall <j...@ccs.neu.edu> writes:

Its senses.

Andras

thal...@gmail.com

unread,
Jul 6, 2005, 4:41:44 PM7/6/05
to
Rainer Joswig wrote:
> (defmacro defmapping (name mapping &body fields)
> `(progn
> (defclass ,name ()
> ,(loop for (nil nil slot) in fields
> collect slot))
> (defmethod find-mapping-class-name ((mapping (eql ',(intern mapping))))
> ',name)
> (defmethod parse-line-for-class (line (class-name (eql ',(intern
> name))))
> (let ((object (make-instance class-name)))
> (loop for (start end slot) in ',fields
> do (setf (slot-value object slot) (subseq line start (1+
> end))))
> object))))

Hi Rainer!

This was very interesting. How short and simple you made it look,
especially compared to that clumsy C# code Martin posted. However, I
tried your code on both clisp and sbcl and ran into a problem. (intern
'something) doesn't work in them so I had to change your code a tiny
bit.

Here's a version that works for me. Please let me know if the fix is
insufficient in some way,

(defmacro defmapping (name mapping &body fields)
`(progn
(defclass ,name ()
,(loop for (nil nil slot) in fields
collect slot))
(defmethod find-mapping-class-name ((mapping (eql ',(intern
mapping))))
',name)
(defmethod parse-line-for-class (line (class-name (eql ',(intern

(symbol-name name)))))


(let ((object (make-instance class-name)))
(loop for (start end slot) in ',fields
do (setf (slot-value object slot) (subseq line start (1+
end))))
object))))

Regards, Tommy

Rainer Joswig

unread,
Jul 7, 2005, 10:20:06 AM7/7/05
to
Am 06.07.2005 22:41 Uhr schrieb "thal...@gmail.com" unter
<thal...@gmail.com> in
1120682504....@g47g2000cwa.googlegroups.com:

Try this one:

(defmacro defmapping (name mapping &body fields)
`(progn
(defclass ,name ()
,(loop for (nil nil slot) in fields
collect slot))
(defmethod find-mapping-class-name ((mapping (eql ',(intern mapping))))
',name)

(defmethod parse-line-for-class (line (class-name (eql ',name)))

Rainer Joswig

unread,
Jul 7, 2005, 7:29:33 PM7/7/05
to
Am 07.07.2005 16:20 Uhr schrieb "Rainer Joswig" unter <jos...@lisp.de> in
BEF306B6.FE68%jos...@lisp.de:

> Am 06.07.2005 22:41 Uhr schrieb "thal...@gmail.com" unter
> <thal...@gmail.com> in
> 1120682504....@g47g2000cwa.googlegroups.com:
>
>> Rainer Joswig wrote:
>>> (defmacro defmapping (name mapping &body fields)
>>> `(progn
>>> (defclass ,name ()
>>> ,(loop for (nil nil slot) in fields
>>> collect slot))
>>> (defmethod find-mapping-class-name ((mapping (eql ',(intern mapping))))
>>> ',name)
>>> (defmethod parse-line-for-class (line (class-name (eql ',(intern
>>> name))))
>>> (let ((object (make-instance class-name)))
>>> (loop for (start end slot) in ',fields
>>> do (setf (slot-value object slot) (subseq line start (1+
>>> end))))
>>> object))))
>>
>> Hi Rainer!
>>
>> This was very interesting. How short and simple you made it look,
>> especially compared to that clumsy C# code Martin posted.

I've written a short article about some DSL style programming technique:

http://lispm.dyndns.org/news?ID=NEWS-2005-07-08-1

GP lisper

unread,
Jul 8, 2005, 6:59:56 PM7/8/05
to
On Fri, 08 Jul 2005 01:29:33 +0200, <jos...@lisp.de> wrote:
>
> I've written a short article about some DSL style programming technique:
>
> http://lispm.dyndns.org/news?ID=NEWS-2005-07-08-1

I enjoyed the article, but the part that I really need to grok is
looking at:

SVCLHOHPE 10201DX0320050315........................

and seeing a mapping macro as the way to solve this problem. Clearly
I need to slough thru these problems a few times more.

Rainer Joswig

unread,
Jul 9, 2005, 2:55:19 AM7/9/05
to
Am 09.07.2005 0:59 Uhr schrieb "GP lisper" unter <spam...@CloudDancer.com>
in 1120863635.4cb311645ca9886eb8604a246f0fd4eb@teranews:

What you can know from looking at the data is:

- it is some text based format with one record per line
- there is a tag in front of each line, which gives you the record type
- the record will have several fields
- different records will have different sets of fields
- records are best represented by Common Lisp classes
- fields are best represented by Common Lisp object's slots
- then you need a simple way to describe the layout the data and compute the
class from this description
- plus you need some mechanism to get from the record type the class
- ...

Parts of the development process are demonstrated in the video referenced
in the article. You might need some time to download it...


GP lisper

unread,
Jul 9, 2005, 3:14:47 AM7/9/05
to
On Sat, 09 Jul 2005 08:55:19 +0200, <jos...@lisp.de> wrote:
>
> Parts of the development process are demonstrated in the video referenced
> in the article. You might need some time to download it...

If I get it downloaded (second attempt now), I'll rehost it (if you
don't mind).

--
LOOP :: a Domain Specific Language.

GP lisper

unread,
Jul 9, 2005, 3:49:25 AM7/9/05
to
On Sat, 09 Jul 2005 08:55:19 +0200, <jos...@lisp.de> wrote:
>
> Am 09.07.2005 0:59 Uhr schrieb "GP lisper" unter <spam...@CloudDancer.com>
> in 1120863635.4cb311645ca9886eb8604a246f0fd4eb@teranews:
>>
>> SVCLHOHPE 10201DX0320050315........................
>>
>> and seeing a mapping macro as the way to solve this problem. Clearly
>> I need to slough thru these problems a few times more.
>
> What you can know from looking at the data is:
>
> - it is some text based format with one record per line
> - there is a tag in front of each line, which gives you the record type
> - the record will have several fields
> - different records will have different sets of fields
> - records are best represented by Common Lisp classes

Agreed (but that last one moved from below to above during the
rewriting of this post).

> - fields are best represented by Common Lisp object's slots
> - then you need a simple way to describe the layout the data and compute the
> class from this description
> - plus you need some mechanism to get from the record type the class

I have Keenes book and several examples, including nifty cells code
from Kenny which follows the above list nearly verbatim. In writing
this post and rethinking the problem, I get a glimmer of this CLOS
stuff, just as I did when I read Keene the first time. As an old
assembly hacker, I think I'm so used to writing all the boilerplate
that it is hard to step back from it to see the 'simpler'
approach...but I think I can learn to like CLOS.

Thanks!

GP lisper

unread,
Jul 9, 2005, 1:14:20 PM7/9/05
to
On Sat, 9 Jul 2005 00:14:47 -0700, <spam...@CloudDancer.com> wrote:
>
>
> On Sat, 09 Jul 2005 08:55:19 +0200, <jos...@lisp.de> wrote:
>>
>> Parts of the development process are demonstrated in the video referenced
>> in the article. You might need some time to download it...
>
> If I get it downloaded (second attempt now), I'll rehost it (if you
> don't mind).

I think that the resource and data forks (if Macs still do such) are a
problem. I keep ending up with 125M transferred, but only a 7M file.

Rainer Joswig

unread,
Jul 9, 2005, 2:56:33 PM7/9/05
to
In article <1120929324.dea8124342cbd9fba7336ad2d1092175@teranews>,
GP lisper <spam...@CloudDancer.com> wrote:

The file has a size of 131323719 bytes. It transfers fine for me.

GP lisper

unread,
Jul 10, 2005, 3:20:49 AM7/10/05
to

From mac to mac? Mac to PC linux? mac to win32? Remote or local?

Joerg Hoehle

unread,
Jul 18, 2005, 11:05:14 AM7/18/05
to
Rainer Joswig <jos...@lisp.de> writes:
> > SVCLHOHPE 10201DX0320050315........................

> What you can know from looking at the data is:
> - it is some text based format with one record per line
> - there is a tag in front of each line, which gives you the record type
> - the record will have several fields
> - different records will have different sets of fields
Agree with all the above

> - records are best represented by Common Lisp classes
> - fields are best represented by Common Lisp object's slots

This is a bogus conclusion. It doesn't logically follow from anything,
except maybe personal preference.

In one of several such applications, it would have been much to costly
to instanciate a new object for every line (hundreds of thousands, if
not millions of lines in plenty of files).

Instead, I had people write code like when using WITH SLOTS.
They wrote the (vitual) slot names they needed, and that got
transformed (via the DSL) into something like
(parse-integer huge-array :start start-of-that-column :end end-of-that-column)
or even
(let (slotx (parse-integer ...))
&body)

All the users need to know is the name SLOTX, which they declared
themselves via the DSL that describes each line. The rest was MACRO
and LAMBDA.

In the most recent such application, I made use of CLOS because it has
a nice declarative touch) for configuration only. At the time each
line is processed, nothing was using CLOS anymore. FUNCALL was it.

Regards,
Jorg Hohle
Telekom/T-Systems Technology Center

Rainer Joswig

unread,
Jul 18, 2005, 3:05:07 PM7/18/05
to
In article <uvf38i...@users.sourceforge.net>,
Joerg Hoehle <hoe...@users.sourceforge.net> wrote:

> Rainer Joswig <jos...@lisp.de> writes:
> > > SVCLHOHPE 10201DX0320050315........................
> > What you can know from looking at the data is:
> > - it is some text based format with one record per line
> > - there is a tag in front of each line, which gives you the record type
> > - the record will have several fields
> > - different records will have different sets of fields
> Agree with all the above
>
> > - records are best represented by Common Lisp classes
> > - fields are best represented by Common Lisp object's slots
> This is a bogus conclusion. It doesn't logically follow from anything,
> except maybe personal preference.

No, if you really want to represent fields and records
(as opposed to use the line and just compute stuff) for
further processing, the usual other options would have
been lists, vectors and structures.

> In one of several such applications, it would have been much to costly
> to instanciate a new object for every line (hundreds of thousands, if
> not millions of lines in plenty of files).

Could be. If you still want to work (temporarily) with objects, there are
a few optimizations. CL-HTTP for example uses pools
(resources) of objects and lazy parsing for the slots.
My applications mostly have been just using pools.

facethe...@hotmail.com

unread,
Jul 19, 2005, 8:28:29 AM7/19/05
to
Joe Marshall wrote:
> Pascal Costanza <p...@p-cos.net> writes:
>
> > ...and favorably so. See
> > http://martinfowler.com/articles/languageWorkbench.html
>
> I noticed that Tiobe ( http://www.tiobe.com/ )
> now rates Lisp as a `Mainstream Language' with an `A' rating.
>
It brings you just below ECMAScript :)
http://www.itjobswatch.co.uk/default.aspx?page=2&sortby=0&orderby=0&jt=0&q=&id=900

The mainstream languages are on the other page :
1 SQL
2 Java
3 C++
4 VB
5 Perl
........
http://www.itjobswatch.co.uk/default.aspx?page=1&sortby=0&orderby=0&jt=0&q=&id=900

Jon Atack

unread,
Oct 20, 2015, 5:55:19 PM10/20/15
to
One of the things I appreciate about Common Lisp: Ten years after this was written, I run across Rainer's code above, drop it into SBCL 1.2.16 and it works perfectly. Very nice.
0 new messages