From: Vladimir V. Zolotych
Subject: destructuring-bind
Date: 
Message-ID: <3A83C2AC.AA5ABFF@eurocom.od.ua>
  Hello

Is it possible make the following code shorter 
(e.g. avoid SETF) in some way ?

(defun parse-session (line)
  (declare (type string line))
  (let ((a (pregexp-match
            <skipped>
	    line)))
    (assert a (line) "'~A': Bad format." line)
    (let ((s (make-session)))
      (destructuring-bind (login tty connect date start end elapsed)
(cdr a)
	(setf (session-login s) login)
	(setf (session-tty s) tty)
	(setf (session-connect s) connect)
	(setf (session-date s) (parse-time date :error-on-mismatch t))
	(setf (session-start s) (parse-time3 start))
        (setf (session-end s) (parse-time3 end))
        (setf (session-elapsed s) (parse-time3 elapsed)))
      s)))

Where SESSION defined with DEFSTRUCT with appropriate fields.
PREGEXP-MATN returns list of strings, where each string corresponds
to matched part of the line.

  Thanks

-- 
Vladimir Zolotych                         ······@eurocom.od.ua

From: Janis Dzerins
Subject: Re: destructuring-bind
Date: 
Message-ID: <87u264194h.fsf@asaka.latnet.lv>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

>   Hello
> 
> Is it possible make the following code shorter 
> (e.g. avoid SETF) in some way ?
> ...

Try this (deduced from recent thread on apply usage :):

> (defun parse-session (line)
>   (declare (type string line))
>   (let ((a (pregexp-match
>             <skipped>
> 	    line)))
>     (assert a (line) "'~A': Bad format." line)

      (apply #'make-session
             (mapcan #'list
                     '(:login :tty :connect :date :start :end :elapsed)
                      (cdr a)))

>       ))

Janis Dzerins
-- 
  If million people say a stupid thing it's still a stupid thing.
From: Janis Dzerins
Subject: Re: destructuring-bind
Date: 
Message-ID: <87n1bv226a.fsf@asaka.latnet.lv>
Janis Dzerins <·····@latnet.lv> writes:

> "Vladimir V. Zolotych" <······@eurocom.od.ua> writes:
> 
> >   Hello
> > 
> > Is it possible make the following code shorter 
> > (e.g. avoid SETF) in some way ?
> > ...
> 
> Try this (deduced from recent thread on apply usage :):
> 
> > (defun parse-session (line)
> >   (declare (type string line))
> >   (let ((a (pregexp-match
> >             <skipped>
> > 	    line)))
> >     (assert a (line) "'~A': Bad format." line)
> 
>       (apply #'make-session
>              (mapcan #'list
>                      '(:login :tty :connect :date :start :end :elapsed)
>                       (cdr a)))
> 
> >       ))

Bad habit to post in haste. And to followup my own post. But I only
now realized that I did not read all the body of parse-session (just
first 3 setf's) and that my version applies only if data in (cdr a)
does not need any processing before storing into the session
structure. And this is was not such a case.

Janis Dzerins
-- 
  If million people say a stupid thing it's still a stupid thing.
From: Marco Antoniotti
Subject: Re: destructuring-bind
Date: 
Message-ID: <y6citmjbxdt.fsf@octagon.mrl.nyu.edu>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

>   Hello
> 
> Is it possible make the following code shorter 
> (e.g. avoid SETF) in some way ?
> 
> (defun parse-session (line)
>   (declare (type string line))
>   (let ((a (pregexp-match
>             <skipped>
> 	    line)))
>     (assert a (line) "'~A': Bad format." line)
>     (let ((s (make-session)))
>       (destructuring-bind (login tty connect date start end elapsed)
> (cdr a)
> 	(setf (session-login s) login)
> 	(setf (session-tty s) tty)
> 	(setf (session-connect s) connect)
> 	(setf (session-date s) (parse-time date :error-on-mismatch t))
> 	(setf (session-start s) (parse-time3 start))
>         (setf (session-end s) (parse-time3 end))
>         (setf (session-elapsed s) (parse-time3 elapsed)))
>       s)))
> 
> Where SESSION defined with DEFSTRUCT with appropriate fields.
> PREGEXP-MATN returns list of strings, where each string corresponds
> to matched part of the line.
> 

Then why not do

(defun parse-session (line)
  (declare (type string line))
  (let ((a (pregexp-match
            <skipped>
	    line)))
    (assert a (line) "'~A': Bad format." line)
    (destructuring-bind (login tty connect date start end elapsed)
	(rest a)
      (make-session :login   login
		    :tty     tty
		    :connect connect
		    :date    (parse-time date :error-on-mismatch t)
		    :start   (parse-time3 start)
		    :end     (parse-time3 end)
		    :elapsed (parse-time3 elapsed)))))

?

Cheers


-- 
Marco Antoniotti =============================================================
NYU Courant Bioinformatics Group		 tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                          fax  +1 - 212 - 995 4122
New York, NY 10003, USA				 http://galt.mrl.nyu.edu/valis
             Like DNA, such a language [Lisp] does not go out of style.
			      Paul Graham, ANSI Common Lisp
From: Tim Bradshaw
Subject: Re: destructuring-bind
Date: 
Message-ID: <nkjn1bwdocl.fsf@tfeb.org>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> (defun parse-session (line)
>   (declare (type string line))
>   (let ((a (pregexp-match
>             <skipped>
> 	    line)))
>     (assert a (line) "'~A': Bad format." line)
>     (let ((s (make-session)))
>       (destructuring-bind (login tty connect date start end elapsed)
> (cdr a)
> 	(setf (session-login s) login)
> 	(setf (session-tty s) tty)
> 	(setf (session-connect s) connect)
> 	(setf (session-date s) (parse-time date :error-on-mismatch t))
> 	(setf (session-start s) (parse-time3 start))
>         (setf (session-end s) (parse-time3 end))
>         (setf (session-elapsed s) (parse-time3 elapsed)))
>       s)))
> 

I think this is really fine -- it's kind of tedious, but sometimes
things just are.  I'd personally use the multiple-argument SETF
thing, so you say

	(setf (session-login s) login
              ... ...)

Five years ago I would have stressed about how ugly this was and tried
to invent some clever cleaner version of it, but I don't think I would
any more.  What I would do, if I did the make-object, destructure,
set-slots bit a lot would be to write a function to do just that, but
myt guess is that you only call it from one place, so there's no real
virtue in it.

--tim
From: Frode Vatvedt Fjeld
Subject: Re: destructuring-bind
Date: 
Message-ID: <2hk870f263.fsf@dslab7.cs.uit.no>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> Is it possible make the following code shorter (e.g. avoid SETF) in
> some way ?

>     (let ((s (make-session)))
>       (destructuring-bind (login tty connect date start end elapsed)
>           (cdr a)
> 	  (setf (session-login s) login)
>         ....

I may be missing some point here, but can't you do

  (destructuring-bind (login tty connect date start end elapsed)
      (cdr a)
    (make-session :login login :tty tty ...))

-- 
Frode Vatvedt Fjeld
From: Vladimir V. Zolotych
Subject: Re: destructuring-bind
Date: 
Message-ID: <3A83FF53.1DDBEA8D@eurocom.od.ua>
Frode Vatvedt Fjeld wrote:
> 
>     (make-session :login login :tty tty ...))

Yes, this or multiple-argument SETF (as Tim suggested)
simplifies the code. 

Thanks.

-- 
Vladimir Zolotych                         ······@eurocom.od.ua
From: Barry Margolin
Subject: Re: destructuring-bind
Date: 
Message-ID: <qiVg6.16$4w6.4931@burlma1-snr2>
In article <················@naggum.net>, Erik Naggum  <····@naggum.net> wrote:
>  Frankly, I don't see the point in stuffing this in a structure, but
>  that's probably immaterial.

A solution that makes creating the structure from that list simple, but
still provides the nice accessors, would be to define the structure with
the :TYPE LIST option.  So the list would already be in the format that the
accessors expect -- it wouldn't be necessary to call a constructor at all.

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Vladimir V. Zolotych
Subject: Re: destructuring-bind
Date: 
Message-ID: <3A842261.EF851811@eurocom.od.ua>
Erik Naggum wrote:
> 
>   ......How big is the final regexp that is _correct_?

"^>\\s+([-_\\w]+)\\s+(\\S+)\\s+(.*?)\\s+(\\w+\\s+\\w+\\s+\\d+\\s+\\d+)\\s+(\\S+)[-\\s]+(\\S+)\\s+\\((\\S+)\\)$"

>   It would probably be much faster for both you and the machine to write up
>   a real parser, 

Unfortunately I know almost nothing about writing such things.

* (time (alt-x "alt.orig" "alt.09"))
........
Evaluation took:
  9.02 seconds of real time
  7.54 seconds of user run time
  0.85 seconds of system run time
  [Run times include 2.38 seconds GC run time]
  46 page faults and
  60237320 bytes consed.

$ wc -l alt.orig
  1749 alt.orig

alt-x calls PARSE-SESSION, do some things wiht SESSION
object, then prints the resulted object. Each line in a file
represents an SESSION object.

-- 
Vladimir Zolotych                         ······@eurocom.od.ua
From: Joe Marshall
Subject: Re: destructuring-bind
Date: 
Message-ID: <wvazza2o.fsf@content-integrity.com>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> Erik Naggum wrote:
> > 
> >   ......How big is the final regexp that is _correct_?
> 
> "^>\\s+([-_\\w]+)\\s+(\\S+)\\s+(.*?)\\s+(\\w+\\s+\\w+\\s+\\d+\\s+\\d+)\\s+(\\S+)[-\\s]+(\\S+)\\s+\\((\\S+)\\)$"
> 
> >   It would probably be much faster for both you and the machine to write up
> >   a real parser, 
> 
> Unfortunately I know almost nothing about writing such things.

Check out Henry Baker's paper ``Pragmatic Parsing in Common Lisp''

His web site was down for a while, but there seems to be a mirror at

  ftp://samaris.tunes.org/pub/food/papers/people/Henry.Baker/hbaker/



-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----==  Over 80,000 Newsgroups - 16 Different Servers! =-----
From: Rob Warnock
Subject: Re: destructuring-bind
Date: 
Message-ID: <962asd$32t6o$1@fido.engr.sgi.com>
Joe Marshall  <···@content-integrity.com> wrote:
+---------------
| Check out Henry Baker's paper ``Pragmatic Parsing in Common Lisp''
| His web site was down for a while, but there seems to be a mirror at
|   ftp://samaris.tunes.org/pub/food/papers/people/Henry.Baker/hbaker/
+---------------

There's also a mirror at <URL:http://linux.rice.edu/~rahul/hbaker/home.html>


-Rob

-----
Rob Warnock, 31-2-510		····@sgi.com
SGI Network Engineering		<URL:http://reality.sgi.com/rpw3/>
1600 Amphitheatre Pkwy.		Phone: 650-933-1673
Mountain View, CA  94043	PP-ASEL-IA
From: Vladimir V. Zolotych
Subject: Re: destructuring-bind
Date: 
Message-ID: <3A8556B1.42FD0BCB@eurocom.od.ua>
Erik Naggum wrote:
> 
>   ....you should just try to do this with real code
>   instead of regexp components.  .....

I'll try to write parser.

-- 
Vladimir Zolotych                         ······@eurocom.od.ua
From: Janis Dzerins
Subject: Re: destructuring-bind
Date: 
Message-ID: <87elx418fp.fsf@asaka.latnet.lv>
"Vladimir V. Zolotych" <······@eurocom.od.ua> writes:

> Erik Naggum wrote:
> > 
> >   ....you should just try to do this with real code
> >   instead of regexp components.  .....
> 
> I'll try to write parser.

I first saw how simple that is while reading html parser code from
Franz. All you need is a Finite State Automaton, which is really easy
to make. You can find link to it here: http://opensource.franz.com/

Janis Dzerins
-- 
  If million people say a stupid thing it's still a stupid thing.
From: Vladimir V. Zolotych
Subject: Re: destructuring-bind
Date: 
Message-ID: <3A8AD899.9D2BCFDF@eurocom.od.ua>
"Vladimir V. Zolotych" wrote:
> 
> Erik Naggum wrote:
> >
> >   ....you should just try to do this with real code
> >   instead of regexp components.  .....

I've learn the things more closely.

1) Regexps isn't necessary for this particular case.
   (The input data are machine generated and have strict
   format except few fields.)
2) I've rewrite code without regexps.

With regexp

Evaluation took:
  9.27 seconds of real time
  7.43 seconds of user run time
  1.04 seconds of system run time
  [Run times include 2.39 seconds GC run time]
  71 page faults and
  60230568 bytes consed.

W/o regexp (real code)

Evaluation took:
  5.31 seconds of real time
  4.34 seconds of user run time
  0.42 seconds of system run time
  [Run times include 1.04 seconds GC run time]
  26 page faults and
  29273560 bytes consed.

My code is rather crude. The results would differ
more when my knowledge of the Lisp improved.


-- 
Vladimir Zolotych                         ······@eurocom.od.ua
From: ········@hex.net
Subject: Re: destructuring-bind
Date: 
Message-ID: <sTfh6.14094$gb1.604321@news4.aus1.giganews.com>
Erik Naggum <····@naggum.net> writes:
> * "Vladimir V. Zolotych" <······@eurocom.od.ua>
> > "^>\\s+([-_\\w]+)\\s+(\\S+)\\s+(.*?)\\s+(\\w+\\s+\\w+\\s+\\d+\\s+\\d+)\\s+(\\S+)[-\\s]+(\\S+)\\s+\\((\\S+)\\)$"

>If this is a/the _correct_ regexp, your date and time parsing
>functions must make good use of conditions and your code good use of
>handlers for exceptional conditions...  I think you dramatically
>underestimate what a correct regexp needs to match and fail to match.
>Most regexp users do.

> > Unfortunately I know almost nothing about writing such things.

>I actually doubt that.  You know enough about regexps to use
>character classes, there is no backtracking and no _searching_ in
>your regexp that I can see, and you end up only selecting a few
>fields separated by simple delimiters.

Ah, but how to do this sort of thing in a reasonably "idiomatic"
Lisp-based way is the rub.

There's a reasonably rich literature out there for the YACC/LALR/
"generate parser and connect to C" approach.  There's starting to be a
fair bit of stuff on parsing XML and attaching code to parse trees
using DOM.

It seems harder to find the equivalent sort of literature for Lisp.
Henry Baker's paper seems pretty good; what is missing is the "general
literature" side of it.

PAIP codes up a full-scale Othello playing program; what would be nice
to see would be:

-> An implementation of an "opening book" scheme for chess (or
   Othello) where the point of the exercise is to generate possible
   responses, and then serialize them and write them out for future
   reference.  

   This would _probably_ be best done by writing the data structures
   out as Lispy s-expressions, perhaps resulting in using a custom
   reader, but compactness might dictate a denser representation,
   mandating a "real parser."  

   Or, [and I certainly stand to be corrected on this,] it might be
   more efficient to read in strings and transform them into symbols
   only as needed, rather than having CL generate interned symbols
   with all the attendant data and work attached to that...

-> Tools for parsing mail and/or news postings, perhaps transforming
   them into an associative list.

   I recently had call for this for doing some statistical analysis on
   mail messages.

CLTL2 alludes to the notion that one might customize the reader into a
customized parser; seeing some interesting examples worked out would
be _really useful_.
-- 
(reverse (concatenate 'string ····················@" "454aa"))
http://vip.hyperusa.com/~cbbrowne/lisp.html
The hypochondriac's epitaph: "NOW will you believe me?" 
From: Marco Antoniotti
Subject: Re: destructuring-bind
Date: 
Message-ID: <y6cwvav293b.fsf@octagon.mrl.nyu.edu>
Erik Naggum <····@naggum.net> writes:

> * ········@hex.net
> > -> Tools for parsing mail and/or news postings, perhaps transforming
> >    them into an associative list.
> > 
> >    I recently had call for this for doing some statistical analysis on
> >    mail messages.
> 
>   GNU Emacs users may find a shot at this in lisp/mail/mailheader.el.
> 
> > CLTL2 alludes to the notion that one might customize the reader into a
> > customized parser; seeing some interesting examples worked out would
> > be _really useful_.

Since I "grew up" at NYU I had my share of Ada and of the more
obscure, yet very interesting language SETL.  SETL is a very high
level language that uses "sets" and "tuples" as its primary "objects
of discourse".  The development of SETL spearheaded the concurrent
development of many interesting algorithms for set manipulation.

Let me show an example of what SETL can do.  Then I will go on and
talk about the reason I still use Common Lisp instead. :)

A SETL program to compute the primes up to 

==============================================================================
-- primes.setl -- Prints the primes from 3 to 100.

program primes;
  print([n in [3, 5 .. 100] | not (exists m in [3, 5 .. (floor(sqrt(float(n))) + 2) min (n - 1)] | n mod m = 0)]);
end test;

-- end of file -- primes.setl --
==============================================================================

This is a one-liner where most of the features of SETL are shown.
Essentially the "tuple-constructor"

	[ <expression> | <iterator and filtering condition> ]

Regular sets are built using '{' '}' instead.

Apart from some of the underlying machinery to efficiently manipulate
sets (essentially hash tables), what is most useful in SETL is that
its "notation" is very mathematically oreinted (R. Gabriel would say
"too much") and that many useful algorithms are more easily expressed
using this set notation.

Now, sitting where I sit, I get in regular "poors' wars" with the SETL
people here. :)  So I finally decided to rewrite the previous program
in Common Lisp.  Here it is

==============================================================================
;;; primes.lisp -- A function that prints the primes from 3 to MAX.

(in-package "SETL-USER")

(defun primes (max)
  [n in (range 3 max 2) / (not (exist m in (range 3 (min (1- n) (+ 2 (sqrt n))) 2) / (= (mod n m) 0)))])

;;; end of file -- primes.lisp --
==============================================================================

Aparto from the change in notation for "ranges", the program looks
pretty much the same as the original.  The function produces a list by
expanding the form in a series of nested loops. The whole of SETL
notation is captured in the 300 lines of CL macrology and macro character
manipulations which make up the SETL and SETL-USER packages.

I rest my case :)

Cheers

-- 
Marco Antoniotti =============================================================
NYU Courant Bioinformatics Group		 tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                          fax  +1 - 212 - 995 4122
New York, NY 10003, USA				 http://galt.mrl.nyu.edu/valis
             Like DNA, such a language [Lisp] does not go out of style.
			      Paul Graham, ANSI Common Lisp
From: Lieven Marchand
Subject: Re: destructuring-bind
Date: 
Message-ID: <m3elx3ol8s.fsf@localhost.localdomain>
Marco Antoniotti <·······@cs.nyu.edu> writes:

> 
> Now, sitting where I sit, I get in regular "poors' wars" with the SETL
> people here. :)  So I finally decided to rewrite the previous program
> in Common Lisp.  Here it is
> 
> ==============================================================================
> ;;; primes.lisp -- A function that prints the primes from 3 to MAX.
> 
> (in-package "SETL-USER")
> 
> (defun primes (max)
>   [n in (range 3 max 2) / (not (exist m in (range 3 (min (1- n) (+ 2 (sqrt n))) 2) / (= (mod n m) 0)))])
> 
> ;;; end of file -- primes.lisp --
> ==============================================================================
> 
> Aparto from the change in notation for "ranges", the program looks
> pretty much the same as the original.  The function produces a list by
> expanding the form in a series of nested loops. The whole of SETL
> notation is captured in the 300 lines of CL macrology and macro character
> manipulations which make up the SETL and SETL-USER packages.
> 
> I rest my case :)
> 

You could show them the CL way with SERIES.

(defun primes (max)
  (choose-if #'(lambda (n) 
                 (collect-and (mapping ((x (scan-range :from 3 
                                                       :by 2 
                                                       :upto (+ 1 (isqrt n)))))
                                        (not (zerop (mod n x)))))) 
             (scan-range :from 3 :by 2 :upto max))

-- 
Lieven Marchand <···@wyrd.be>
Gla�r ok reifr skyli gumna hverr, unz sinn b��r bana.
From: Marco Antoniotti
Subject: Re: destructuring-bind
Date: 
Message-ID: <y6c4rxy1uho.fsf@octagon.mrl.nyu.edu>
Lieven Marchand <···@wyrd.be> writes:

> Marco Antoniotti <·······@cs.nyu.edu> writes:
> 
> > 
> > Now, sitting where I sit, I get in regular "poors' wars" with the SETL
> > people here. :)  So I finally decided to rewrite the previous program
> > in Common Lisp.  Here it is
> > 
> > ==============================================================================
> > ;;; primes.lisp -- A function that prints the primes from 3 to MAX.
> > 
> > (in-package "SETL-USER")
> > 
> > (defun primes (max)
> >   [n in (range 3 max 2) / (not (exist m in (range 3 (min (1- n) (+ 2 (sqrt n))) 2) / (= (mod n m) 0)))])
> > 
> > ;;; end of file -- primes.lisp --
> > ==============================================================================
> > 
> > Aparto from the change in notation for "ranges", the program looks
> > pretty much the same as the original.  The function produces a list by
> > expanding the form in a series of nested loops. The whole of SETL
> > notation is captured in the 300 lines of CL macrology and macro character
> > manipulations which make up the SETL and SETL-USER packages.
> > 
> > I rest my case :)
> > 
> 
> You could show them the CL way with SERIES.
> 
> (defun primes (max)
>   (choose-if #'(lambda (n) 
>                  (collect-and (mapping ((x (scan-range :from 3 
>                                                        :by 2 
>                                                        :upto (+ 1 (isqrt n)))))
>                                         (not (zerop (mod n x)))))) 
>              (scan-range :from 3 :by 2 :upto max))

Yes.  However that was not my intent :) SERIES do not use the sets and
tuple notation. E.g. in the SETL-USER package.

SETL-USER[1]> (== {1 2 {3 4}} {1 {4 3} 2})
T

SERIES may be a good implementation tool for
the guts of a real CL SETL extension, but time is a killer :)

Cheers

-- 
Marco Antoniotti =============================================================
NYU Courant Bioinformatics Group		 tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                          fax  +1 - 212 - 995 4122
New York, NY 10003, USA				 http://galt.mrl.nyu.edu/valis
             Like DNA, such a language [Lisp] does not go out of style.
			      Paul Graham, ANSI Common Lisp
From: Christopher J. Vogt
Subject: Re: destructuring-bind
Date: 
Message-ID: <3A844BBF.C3FFE857@computer.org>
"Vladimir V. Zolotych" wrote:
> 
> Is it possible make the following code shorter
> (e.g. avoid SETF) in some way ?
> 
> (defun parse-session (line)
>   (declare (type string line))
>   (let ((a (pregexp-match
>             <skipped>
>             line)))
>     (assert a (line) "'~A': Bad format." line)
>     (let ((s (make-session)))
>       (destructuring-bind (login tty connect date start end elapsed)
> (cdr a)
>         (setf (session-login s) login)
>         (setf (session-tty s) tty)
>         (setf (session-connect s) connect)
>         (setf (session-date s) (parse-time date :error-on-mismatch t))
>         (setf (session-start s) (parse-time3 start))
>         (setf (session-end s) (parse-time3 end))
>         (setf (session-elapsed s) (parse-time3 elapsed)))
>       s)))

Use keyword args to make-session, and a little reordering:

(defun parse-session (line)
  (declare (type string line))
  (let ((a (pregexp-match <skipped> line)))
    (assert a (line) "'~A': Bad format." line)
    (destructuring-bind (login tty connect date start end elapsed) (cdr a)
      (make-session :login login
		    :tty tty
		    :connect connect
		    :date (parse-time date :error-on-mismatch t)
		    :start (parse-time3 start)
		    :end (parse-time3 end)
		    :elapsed (parse-time3 elapsed)))))