From: Alexander Schreiber
Subject: Wanted: Magic Lisp snippets
Date: 
Message-ID: <slrnd2asfh.s7d.als@mordor.angband.thangorodrim.de>
Hi!

I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
event in Germany.

To show off the elegance and power of Lisp I'm looking for very short
"magic" snippets of Lisp code: 
 - does something tricky/complex/interesting in a (for Lisp)
   simple and elegant way,
 - possible showing of some very useful Lisp features (like bignums,
   crypto in < 1 K of Lisp code anyone?),
 - should fit in 15 lines by 50 characters (presentation foils),
 - should _not_ be obfuscated - I'm trying to get people interested
   in Lisp, not scare them away,
 - credit will of course be given (or withheld, honouring the wishes
   of the author of the Lisp snippet)

Since there are many very experienced Lispers here, I'm confident
something interesting will show up.

Thanks in advance,
                 Alex.
-- 
"Opportunity is missed by most people because it is dressed in overalls and
 looks like work."                                      -- Thomas A. Edison

From: Alexander Repenning
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <1109779712.293929.216200@z14g2000cwz.googlegroups.com>
This "magic" shows that Lisp can be easily extended as language to
include and be mixed with other languages. XMLisp integrated Lisp/CLOS
with XML through the Meta Object Protocol. Mix and match Lisp and XML
expressions. Read, print, eval, inspect, compile... XML +Lisp
expression.

A nice example is the RSS one but that's a bit more than 18 lines. A
shorter one, but perhaps to abstract is a simple HTML link example:

define CLOS class for HTML elements, e.g., "A" the link

(defclass A (xml-serializer)
   ((href :accessor href :initform "" :initarg :href))
   (:documentation "HTML link"))

;; -> done: create an instance

? (make-instance 'a :href "http://www.apple.com")
<a href="http://www.apple.com"/>

;; Note that the instance manifests itself in the listenere as XML
expression.
;; XML is not just output, try:

? (href <a href="http://agentsheets.com/lisp/XMLisp/">XMLisp
examples</a>)
"http://agentsheets.com/lisp/XMLisp/"

if Lisp reads an XML expression (which could be nested of course) it
will create a CLOS instance.

crazy bonus idea: if you use an XML-based slide presentation tool
(e.g., Apple's Keynote, not sure about PowerPoint) you could create a
slide show that IS Lisp code. Think about this one for a second...

Alex
From: Geoffrey Summerhayes
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <CqyVd.35523$kz6.685598@news20.bellglobal.com>
"Alexander Repenning" <·····@cs.colorado.edu> wrote in message ·····························@z14g2000cwz.googlegroups.com...
>
> crazy bonus idea: if you use an XML-based slide presentation tool
> (e.g., Apple's Keynote, not sure about PowerPoint) you could create a
> slide show that IS Lisp code. Think about this one for a second...
>

A while back I just used the listener for a presentation:

  (defmethod present ((item list))
    (let ((*print-right-margin* 60))
      (pprint item))
    (read-char *standard-input*)
    (format *standard-output* "~&~{~A~%~}" (multiple-value-list (eval item))))

  (defmethod present ((item symbol))
    (format *standard-output* "~&~A contains: ~A~%" item (eval item)))

  (defmethod present ((item string))
    (format *standard-output* "~&~A~%" item))

  (defun run()
    (let ((*read-eval* nil))
      (with-open-file (stream "presentation.txt" :direction :input)
        (do ((form (read stream nil :eof) (read stream nil :eof)))
            ((eql form :eof))
          (present form)
          (read-char *standard-input*))))
    "Thank you!!")

where the text file had things like:

  "  - lexical and dynamic scope"

  (defun make-counter (x)
    (lambda () (prog1 x (incf x))))

  (defparameter bar (make-counter 0))

  bar

But for short snippets, my favorites are

  (apply #'mapcar #'list '((1 2 3)(4 5 6)))

and the rule-based GENERATE from chapter 2 of PAIP.

--
Geoff
From: Frank Buss
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <d041pt$ao2$1@newsreader2.netcologne.de>
Alexander Schreiber <···@usenet.thangorodrim.de> wrote:

> To show off the elegance and power of Lisp I'm looking for very short
> "magic" snippets of Lisp code: 

the original Java code ( http://tinyurl.com/57smz ) is not by me, but
the Lisp translation:

(loop for y from -1 to 1.1 by 0.1 do
      (loop for x from -2 to 1 by 0.04 do
            (let* ((c 126)
                   (z (complex x y))
                   (a z))
              (loop while (< (abs
                              (setq z (+ (* z z) a)))
                             2)
                    while (> (decf c) 32)) 
              (princ (code-char c))))
      (format t "~%"))

The output (use a fixed font to view it)

~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}||||||||{{{zyvrwuW{|||||}}}}}}~~~~~~~~~~~~
~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}|||||||||{{{zyxwoaqwxz{{{|||||}}}}}}~~~~~~~~~
~~~~~~~~}}}}}}}}}}}}}}}}}}}|||||||||{{zzzyxvn    Knwyz{{{{||||}}}}}}~~~~~~~
~~~~~~}}}}}}}}}}}}}}}}}}||||||||{{zyxuxxxwvuq     svwwyzzzyr{||}}}}}}}~~~~~
~~~~}}}}}}}}}}}}}}}}}|||||{{{{{zzzxt>  qf             pttfqeqz{|}}}}}}}}~~~
~~~}}}}}}}}}}}}}}|||{{{{{{{{{zzzywotn                     atyz{||}}}}}}}}~~
~~}}}}}}}}}||||{{zwvyyyyyyyyyyyxvsP                        swvz{||}}}}}}}}~
~}}}}|||||||{{{{zyxvpN[ur]spvwwvi                           qxz{|||}}}}}}}}
~}||||||||{{{{{zyytun         qq                            avz{|||}}}}}}}}
~||||||{zzzzyyxtroqb           a                            xz{{|||}}}}}}}}
·@G::# 6# (                                              pvxyz{{||||}}}}}}}
~||||||{zzzzyyxtroqb           a                            xz{{|||}}}}}}}}
~}||||||||{{{{{zyytun         qq                            avz{|||}}}}}}}}
~}}}}|||||||{{{{zyxvpN[ur]spvwwvi                           qxz{|||}}}}}}}}
~~}}}}}}}}}||||{{zwvyyyyyyyyyyyxvsP                        swvz{||}}}}}}}}~
~~~}}}}}}}}}}}}}}|||{{{{{{{{{zzzywotn                     atyz{||}}}}}}}}~~
~~~~}}}}}}}}}}}}}}}}}|||||{{{{{zzzxt>  qf             pttfqeqz{|}}}}}}}}~~~
~~~~~~}}}}}}}}}}}}}}}}}}||||||||{{zyxuxxxwvuq     svwwyzzzyr{||}}}}}}}~~~~~
~~~~~~~~}}}}}}}}}}}}}}}}}}}|||||||||{{zzzyxvn    Knwyz{{{{||||}}}}}}~~~~~~~
~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}|||||||||{{{zyxwoaqwxz{{{|||||}}}}}}~~~~~~~~~
~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}||||||||{{{zyvrwuW{|||||}}}}}}~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}|||||{zmt{{{||||}}}}}~~~~~~~~~~~~~~~~

It demonstrates two things: complex numbers and the magic of the
interactive environment. In other languages, like Java, you have to
create a file, compile it and run it, in Lisp you just paste it to
the REPL and you see the result immediatly.

That's the full article, with zooming extensions, a Scheme and Emacs
version etc.:

http://groups.google.de/groups?threadm=ceef5p%24cch%241%40newsreader2.netcologne.de

and, of course, my ASCII movie :-)

http://www.mynetcologne.de/~nc-buszfr/mandelbrot.mpg
http://groups.google.de/groups?selm=cej9kk%24d92%241%40newsreader2.netcologne.de

the TGA-images were created by a 122 line Lisp program, with the
TGA output encoding and without the charset definition (with
inline charset it is 1458 lines long).

Some other experiments by me:

http://groups.google.de/groups?threadm=cgrcvj%24oaa%241%40newsreader3.netcologne.de
http://groups.google.de/groups?threadm=co5sft%24bgl%241%40newsreader2.netcologne.de
http://www.frank-buss.de/lisp/aqueduct.html

And something you can't do as easy as in Lisp in languages like
Java:

http://www.frank-buss.de/lisp/functional.html

and the very nice variation by Geoffrey Summerhayes:

http://groups.google.de/groups?threadm=VqYMd.4693%24lw4.1005455%40news20.bellglobal.com


But I'm still not very experienced in Lisp, so the code might not look
like written by a Lisp professional, so before using it for a
presentation, you should post it again here to get some comments from
other Lisp programmers.

And last but not least:

http://www.gigamonkeys.com/book/

-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: David Steuber
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <87vf8758jk.fsf@david-steuber.com>
Edi Weitz <········@agharta.de> writes:

> On Fri, 4 Mar 2005 05:49:20 +0000 (UTC), Frank Buss <··@frank-buss.de> wrote:
> 
> > Do you think the "do" has to be on the next line, like all other
> > loop- clauses?
> 
> I put it on the next line or not depending on what follows.
> 
> Still waiting for good Emacs indentation of complex LOOP
> statements... :(

That's what happens when you don't use s-exp syntax.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Julian Stecklina
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <pan.2005.03.05.04.20.19.165077@web.de>
On Fri, 04 Mar 2005 17:51:43 -0500, David Steuber wrote:

> Edi Weitz <········@agharta.de> writes:
> 
>> On Fri, 4 Mar 2005 05:49:20 +0000 (UTC), Frank Buss <··@frank-buss.de> wrote:
>> 
>> > Do you think the "do" has to be on the next line, like all other
>> > loop- clauses?
>> 
>> I put it on the next line or not depending on what follows.
>> 
>> Still waiting for good Emacs indentation of complex LOOP
>> statements... :(
> 
> That's what happens when you don't use s-exp syntax.

Iterate is for you. :) Even you use it only because its properly indented. 

Regards,
-- 
Julian Stecklina

-- Common Lisp can do what C, C++, Java, PASCAL, PHP, Perl, (you --
-- name it) can do. Here's how:                                  --
--                                                               --
-- http://www.amazon.com/exec/obidos/ASIN/1590592395             --
From: Julian Stecklina
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <pan.2005.03.05.04.50.13.565603@web.de>
On Sat, 05 Mar 2005 05:20:24 +0100, Julian Stecklina wrote:

> On Fri, 04 Mar 2005 17:51:43 -0500, David Steuber wrote:
> 
>> Edi Weitz <········@agharta.de> writes:
>> 
>>> On Fri, 4 Mar 2005 05:49:20 +0000 (UTC), Frank Buss <··@frank-buss.de> wrote:
>>> 
>>> > Do you think the "do" has to be on the next line, like all other
>>> > loop- clauses?
>>> 
>>> I put it on the next line or not depending on what follows.
>>> 
>>> Still waiting for good Emacs indentation of complex LOOP
>>> statements... :(
>> 
>> That's what happens when you don't use s-exp syntax.
> 
> Iterate is for you. :) Even you use it only because its properly indented. 

I meant, "Even if you only use it, because it's properly indented." I hope
my former english teacher did not see the above sentence... ;)

> Regards,

-- 
Julian Stecklina

-- Common Lisp can do what C, C++, Java, PASCAL, PHP, Perl, (you --
-- name it) can do. Here's how:                                  --
--                                                               --
-- http://www.amazon.com/exec/obidos/ASIN/1590592395             --
From: Kenny Tilton
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <yJiWd.23059$rB3.4063160@twister.nyc.rr.com>
Julian Stecklina wrote:
> On Sat, 05 Mar 2005 05:20:24 +0100, Julian Stecklina wrote:
> 
> 
>>On Fri, 04 Mar 2005 17:51:43 -0500, David Steuber wrote:
>>
>>
>>>Edi Weitz <········@agharta.de> writes:
>>>
>>>
>>>>On Fri, 4 Mar 2005 05:49:20 +0000 (UTC), Frank Buss <··@frank-buss.de> wrote:
>>>>
>>>>
>>>>>Do you think the "do" has to be on the next line, like all other
>>>>>loop- clauses?
>>>>
>>>>I put it on the next line or not depending on what follows.
>>>>
>>>>Still waiting for good Emacs indentation of complex LOOP
>>>>statements... :(
>>>
>>>That's what happens when you don't use s-exp syntax.
>>
>>Iterate is for you. :) Even you use it only because its properly indented. 
> 
> 
> I meant, "Even if you only use it, because it's properly indented." I hope
> my former english teacher did not see the above sentence... ;)

"Even if you use it only because it is properly indented."

Julian's English teacher
From: Frank Buss
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <d041vv$ao2$2@newsreader2.netcologne.de>
Alexander Schreiber <···@usenet.thangorodrim.de> wrote:

> To show off the elegance and power of Lisp I'm looking for very short
> "magic" snippets of Lisp code: 

and a very nice link, if you want some magic for learning Lisp:

http://www.lisperati.com/

-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Brad Might
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <1109792696.481766.224240@g14g2000cwa.googlegroups.com>
Alexander Schreiber wrote:
> Hi!
>
> I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
> event in Germany.
>
>

I don't have the code handy here to show but this is a handy macro i
created that always impresses my java using friends (modify the
vars/paths to suit any particular demo):

(with-xml-paths  service-header
  ((pip-identifier
"/ServiceHeader/ProcessControl/ProcessIdentity/GlobalProcessIndicator")
   (version-identifier
"/ServiceHeader/ProcessControl/ProcessIdentity/VersionIdentifier"))
    (process-pip pip-identifier version-identifier))

What this macro does is accept parameter (service-header in this case)
which is expected to be a tree created by xmls...so it is xml in a
list/tree. At compile time, all the 'path' expressions are broken up
into each element, sorted by the path so that each path is only walked
once, and a 'walking' set of code is generated which will at runtime
traverse the document tree, touching each element only once during that
walk, and assigning the value within that document at that path to the
corresponding variable.
An elegant way to solve the painful problem of extracting values from
xml documents. I didn't need full xpath capability for this and i knew
the structure for the documents i would be working with, so itis not a
general purpose solution, but worked for all my needs.
From: Fred Gilham
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <u7mztlpv32.fsf@snapdragon.csl.sri.com>
>  - possible showing of some very useful Lisp features (like bignums,
>    crypto in < 1 K of Lisp code anyone?),


Here's some diffie-hellman stuff that lets you do key exchange.  Of
course this is susceptible to man-in-the-middle attacks but apart from
that it's remarkably simple in Lisp.


(defconstant *dh-base* 3)

(defconstant *dh-modulus* #xde9b707d4c5a4633c0290c95ff30a605aeb7ae864ff48370f13cf01d49adb9f23d19a439f753ee7703cf342d87f431105c843c78ca4df639931f3458fae8a94d1687e99a76ed99d0ba87189f42fd31ad8262c54a8cf5914ae6c28c540d714a5f6087a171fb74f4814c6f968d72386ef356a05180c3bec7ddd5ef6fe76b0531c3)

;;; Stolen from clmath package by Gerald Roylance.
(defun modpower (number exponent modulus)
  (declare (integer number exponent modulus))
  (do ((exp  exponent  (floor exp 2))
       (sqr  number (mod (* sqr sqr) modulus))
       (ans  1))
      ((zerop exp) ans)
    (declare (integer exp sqr ans))
    (if (oddp exp)
        (setq ans (mod (* ans sqr) modulus)))))


(defun compute-secret-key (dh-modulus)
  (declare (integer dh-modulus))
  (random dh-modulus (make-random-state t)))


(defun compute-public-key (base secret-key modulus)
  (declare (integer base secret-key modulus))
  (modpower base secret-key modulus))
		    

(defun compute-common-key (remote-public-key local-secret-key modulus)
  (declare (integer remote-public-key local-secret-key modulus))
  (modpower remote-public-key local-secret-key modulus))



So to use it, you and your partner each compute a secret key.  Then
you each use the secret key to compute a public key, which you give to
the other person.  This public key doesn't have to be kept secret.
Then you use the other person's public key and your secret key to
compute a "common key".  The other person will use your public key and
his secret key to make the same computation.  You will both wind up
with an identical "common key".  Each of you could then use a
symmetrical encryption algorithm, with the common key as the
encryption key, to exchange messages.

It's a little more than 1k because of my long variable names and
declarations.


-- 
Fred Gilham                                        ······@csl.sri.com
He thought he was speaking in a place that encourages uncircumscribed
intellectual explorations. He was not. He was on a university campus.
                                                       -- George Will
From: Wade Humeniuk
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <WWjVd.34396$ab2.11941@edtnps89>
Simple Lisp program generating an (X)HTML page:

(defun generate-calendar (title months)
   (with-output-to-string (*xhtml-stream*)
     (html ()
       (head ()
	(title () (content--> "Westmount Calendar"))
	(style (:type "text/css")
	  (content--> ·@import \"calendar.css\";")))
       (body ()
	(h2 () (content--> title))
	(loop for (month year) in months
	      do (insert-calendar-month month year))))))

Wade
From: Florian Weimer
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <87ll96qcai.fsf@deneb.enyo.de>
* Wade Humeniuk:

> Simple Lisp program generating an (X)HTML page:
>
> (defun generate-calendar (title months)
>   (with-output-to-string (*xhtml-stream*)
>     (html ()

Using libraries is cheating and doesn't count, IMHO. Showing how to
build the underlying library would be far better, but I'm not sure if
it matches Alex's constraints.
From: Wade Humeniuk
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <ctlVd.24896$TB.15117@edtnps84>
Florian Weimer wrote:
> * Wade Humeniuk:
> 
> 
>>Simple Lisp program generating an (X)HTML page:
>>
>>(defun generate-calendar (title months)
>>  (with-output-to-string (*xhtml-stream*)
>>    (html ()
> 
> 
> Using libraries is cheating and doesn't count, IMHO. Showing how to
> build the underlying library would be far better, but I'm not sure if
> it matches Alex's constraints.

Oh, come on!  There is no such thing as cheating.  The examples
should be relevant and understandable.  The macro that implements
the HTML would only be interesting for the most die hard
programmer and as far as I can tell that is not the audience.

Wade
From: William Bland
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <pan.2005.03.02.16.19.18.164176@abstractnonsense.com>
This one might seem a bit trivial, but I love it and see no easy way to
duplicate it in other languages.

I have a few variables to set up, which are quite similar.  Rather than
having to keep them in sync with each other, I want to simply specify
their relationship, specify just one of the variables, and generate the
others from it.

This is taken from real code, currently used at my place of work (it's a
compiler for a very small, but very useful, domain-specific language):

(defvar *operator-compilers* `((":" . ,#'compile-setstate) ; in precedence order
			       (">" . ,#'compile-pipeline)
			       ("!" . ,#'compile-exception)
			       (";" . ,#'compile-sequence)))

(defvar *operators* (mapcar #'first *operator-compilers*))

(defvar *operators-as-chars*
  (mapcar (lambda (x) (coerce x 'character)) *operators*))

Best wishes,
		Bill.
From: Joerg Hoehle
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <u8y4xkkzc.fsf@users.sourceforge.net>
Florian Weimer <··@deneb.enyo.de> writes:
> * Wade Humeniuk:
> > Simple Lisp program generating an (X)HTML page:
> > (defun generate-calendar (title months)
> >   (with-output-to-string (*xhtml-stream*)
> >     (html ()
> 
> Using libraries is cheating and doesn't count, IMHO. Showing how to
> build the underlying library would be far better, but I'm not sure if
> it matches Alex's constraints.

Then my HTML-template library is for you. It's the only library I know
that comes without code! :)
The reason is that
a) the HTML template is transformed into a set of
   standard CL (or pure Scheme) forms.
b) when you invoke it, you need nothing more than FUNCALL, APPLY and LAMBDA.

In short,
i) a preprocessed template looks like this (in Scheme), and I put it
   in a file where it can be (compiled and) loaded:
;Template specification: ((ang-liste aid ang-name ang-preis ang-start ang-ende ang-benutzergruppe ang-payment))
(define tmpl-angebote (list '((ang-liste aid ang-name ang-preis ang-start ang-ende ang-benutzergruppe ang-payment))
(lambda (ang-liste ) (display* "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\"http://www.w3.org/TR/REC-html40/loose.dtd\">
<HTML><head><title>Angebots�bersicht &amp; mehr</title>
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">
<link rel=\"stylesheet\" type=\"text/css\" href=\"PeMAP.css\">...))))

b) Servlet code looks like this (sql-repeat is from BRL):
(set! display* (lambda (x) (brl x)))
(tmpl-print
 tmpl-angebote
 ;Spezifikation: ((LOOP ang-liste aid Ang-Name Ang-Preis Ang-von Ang-bis Ang-Benutzergruppe Ang-Payment))
 (lambda (loopprinter)
   (sql-repeat st (aid name preis von bis a.gruppenId a.payment)
     ("SELECT a.AngebotsId, a.Name, k.Preis, k.gueltigStart, k.gueltigEnde,"
      "  k.BenutzergruppenID, k.Payment"
      " FROM Angebote a"
      " JOIN Konditionen k USING (KonditionsId)"
      " ORDER BY a.Name, AngebotsID")
     (loopprinter
      ;; Umformatierungen vornehmen (SQL->HTML):
      aid
      (brl-html-escape name)
      preis
      (brl-html-escape von)
      (brl-html-escape bis)
      (brl-html-escape a.gruppenId)
      (brl-html-escape a.payment)))))
That is a *complete* web page!
  database -> table -> HTML

c) If you really want a non-empty library, use this:
(define (tmpl-print template . variable-subtitutions)
  (apply (cadr template) variable-subtitutions))

Of course, I don't write the code in a) by hand. Instead, I use a
variation on Edi Weitz' parser. But at run-time (of e.g. a
web-server), no library is involved (except for the BRL or other
webapp environment, the OS etc.)!

My template engine's outstanding combination of features:
o supports streaming -- output as soon as possible, no need to build
  up a list of substitutions like in Edi's and many other people's
  template engines.
o supports static validation of the template -- users never see
  unsubstituted "$x" patterns in the browsers (unlike e.g. Sourceforge)
  (not shown here, it's the parser's job)
o supports X/HTML-validation of the template (to some extent)
  -- need not put in into the web engine and fill it to test it
o highly concise application code
o lexical scoping in the template language (e.g. in nested template LOOPs)
o efficient
  -- e.g. concatenates static output in a single princ
  -- use lexical variables instead of dictionary lookup
o security -- no executable code in the template
o and much more I forgot

Regards,
	Jorg Hohle
Telekom/T-Systems Technology Center
From: Joerg Hoehle
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <u4qflkjui.fsf@users.sourceforge.net>
Alexander Schreiber <···@usenet.thangorodrim.de> writes:
> What I want is one or two self-contained snippets (i.e. just pure Common
> Lisp, _no_ libraries involved

Pardon me to insist on my HTML-template. Here's code for 2 slides

;;; The output of the template compiler:
(define tmpl-demo
 (list '(date (LOOP name-list key name)) ; template specification
       (lambda (date name-list) ; not intended to be human-readable
	 (display* "<H2>Today ")(display* date)(display* "</H2><UL>")
	 (name-list (lambda (key name)
		      (display* "<LI>")(display* key)(display*"--")
		      (display* name)(display*"</LI>")))
	 (display* "</UL>"))))

;;; The "library"
;; The typical looper for ready-made lists
(define (generic-template-loop entries)
  (lambda (loopprinter)
    (map (lambda (row)
	   (apply loopprinter row))
	 entries)))

(define (tmpl-print template . variable-subtitutions)
  (apply (cadr template) variable-subtitutions))

;;; Instanciating the template
(tmpl-print tmpl-demo "Wednesday"
	 (generic-template-loop '((1 "one") (a "Ahh") ("mighty" "cool"))))

;;; The output
<H2>Today Wednesday</H2><UL><LI>1--one</LI><LI>a--Ahh</LI><LI>mighty--cool</LI></UL>

Translation from Scheme to CL is left as an exercise :-)

One could simplify the data structure by leaving out the template
specification.  It's is not used in this demo anyway.

Regards,
	Jorg Hohle
Telekom/T-Systems Technology Center
From: Paolo Amoroso
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <87mztmxhrk.fsf@plato.moon.paoloamoroso.it>
Alexander Schreiber <···@usenet.thangorodrim.de> writes:

> I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
> event in Germany.

Can you let us know about the feedback?


> To show off the elegance and power of Lisp I'm looking for very short
> "magic" snippets of Lisp code: 

You may check the archive of the small-cl-sources mailing list:

  http://www.hexapodia.net:8080/mailman/listinfo/small-cl-src

Right now I get an error message when accessing that site.

You may also include a slide with a Symbolics Genera screen shot, and
tell your audience that, although it is possible to present elegant
and powerful code snippets, Lisp probably gives its best for
developing large and complex systems.  Would a few `bash' snippets do
justice to Unix?


Paolo
-- 
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
Recommended Common Lisp libraries/tools (see also http://clrfi.alu.org):
- ASDF/ASDF-INSTALL: system building/installation
- CL-PPCRE: regular expressions
- UFFI: Foreign Function Interface
From: James Graves
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <d04mf6$mda$1@new7.xnet.com>
Here's something I was talking about which I think is really cool
(though perhaps not magic).  You may figure out a way to incorporate it
into your talk.

I was chatting with a friend about Lisp, and prefix notation when I
wrote this:

What I am learning, however is that it seems prefix notation allows for
some nice effects in and off itself.  I'm not talking about not having
'begin' and 'end' or stuff like that.

I was just studying numeric operations in CL.  One of the operators is
not-equals '/='.  So to return 'T' if A and B are not equal, you do:

    (/= X Y)

Pretty standard, and it maps exactly to this in C:

    X != Y

The interesting bit is that '/=' can take more than two arguments:

    (/= X Y Z)

Which is equivalant to:

    X != Y && X != Z && Y != Z

It gets exponentially worse with more comparisons, of course.  You
could, of course,  write a new function which takes multiple arguments
called all_not_equal() to do the equivanent of CL's '/=' function.

The point though is that in Lisp you just have one function (operator)
which does not-equals for numbers, and in C you need an operator and a
function to do the same kinds of things.  It is a greater conceptual load.

If you're learning C, for example, you've got to learn what '!=' does,
because that is pretty basic.  However, even if all_not_equal() was part
of a standard library, you wouldn't learn about it right away.  And even
if you did use it previously, you might forget to use it when you ought
to.

So I am looking at other ways in which this can cut down on the
conceptual size of Lisp languages in comparison to infix languages.

It seems to me that for ultimate flexibility, you need functions, not
just operators like '+' and '!='.  And if you're going to be using
more general functions anyway, why even bother with the operators in the
first place?

James Graves
From: Trent Buck
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <20050303053927.06735692@harpo.marx>
Spake James Graves:
> You could, of course,  write a new function which takes multiple arguments
> called all_not_equal() to do the equivanent of CL's '/=' function.

Not generically, in C.  Variadic generic C macros are impossible, even
with GNU extensions.

On that point, the OP might want to observe that

  - in Lisp, macros aren't a separate preprocessor (i.e. they can use
    the full power of the language)

  - in Lisp, macros can be recursive.

  - in Lisp, macros can use GENSYM.  It is not necessary to call
    variables "i_hate_variable_capture_dont_use_this_name".

  - in Lisp, DESTRUCTURING-BIND makes it easy to rip into the guts of a
    macro's parameters.

Of course, these benefits will only impress people who have recently
smashed headlong into the deficiencies of CPP and are still bloody and
reeling.

Another sexy thing in (Common) Lisp is lexical scoping.  A direct result
thereof is the ability to define closures:

	(let (stack)
	  (defun my-push (x)
	    (setq stac (cons x stack)))
	  (defun my-pop ()
	    ;; note the usefulness of VALUES.
	    (values (car stack)
	            (setq stack (cdr stack)))))

...and the ability to define functions at run-time (as opposed to simply
dispatching to pre-defined functions, which is all C can do).

Anonymous functions are very neat.  An example Sussman uses is

	(defun my-cons (a b)
	  (lambda (x)
	    (if x a b)))

	(defun my-car (x)
	  (funcall x t))

	(defun my-cdr (x)
	  (funcall x nil))

-- 
Trent Buck, Student Errant
"I'm not a liberal, I'm a militant radical."
"A radical is nothing but a liberal with a big mouth. And a militant
radical is nothing but a big-mouthed liberal with a Che costume."
From: Brian Downing
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <8FvVd.84781$tl3.23486@attbi_s02>
In article <·······················@harpo.marx>,
Trent Buck  <·········@tznvy.pbz> wrote:
> Spake James Graves:
> > You could, of course,  write a new function which takes multiple
> > arguments called all_not_equal() to do the equivanent of CL's '/='
> > function.
> 
> Not generically, in C.  Variadic generic C macros are impossible, even
> with GNU extensions.

I'm not sure what you mean by "generic", and I'm aware the following is
a crime against God and man (and that it's C99-only), but:

/* See the Order side of http://sourceforge.net/projects/chaos-pp/ */
#include "order/interpreter.h"

#define ORDER_PP_DEF_8seq_for_each_in_combinations                      \
    ORDER_PP_FN(                                                        \
        8fn(8F, 8S,                                                     \
            8cond((8seq_isnt_nil(8seq_tail(8S)),                        \
                   8seq_for_each(8fn(8E,                                \
                                     8ap(8F, 8seq_head(8S), 8E)),       \
                                 8seq_tail(8S)),                        \
                   8seq_for_each_in_combinations(8F, 8seq_tail(8S))))))

#define GEN_ne_conditional(a, b)                \
    ((a) != (b)) &&

#define ORDER_PP_DEF_8gen_ne_conditional                \
    ORDER_PP_FN(8fn(8A, 8B,                             \
                    8print(8quote(GEN_ne_conditional)   \
                           8tuple(8A, 8B)               \
                           8space)))

#define ALL_NOT_EQUAL(...)                              \
    (ORDER_PP(8seq_for_each_in_combinations             \
              (8gen_ne_conditional,                     \
               8tuple_to_seq(8quote((__VA_ARGS__))))) 1)

The Order author strongly believes that it is 100% compliant C99
preprocessor code, despite the fact that only GNU CPP and one other
preprocessor is non-buggy enough to run it.

ALL_NOT_EQUAL(a, b, c, d, e) expands to (all on one line, of course):

(((a) != (b)) && ((a) != (c)) && ((a) != (d)) && ((a) != (e)) && 
 ((b) != (c)) && ((b) != (d)) && ((b) != (e)) && 
 ((c) != (d)) && ((c) != (e)) && 
 ((d) != (e)) && 1);

Using GCC's statement expressions to make it safe against multiple
evaluations is left as an exercise for the reader.

Having committed this atrocity, however, let me express my EXTREME
preference for CL macros.  :)

-bcd
-- 
*** Brian Downing <bdowning at lavos dot net> 
From: Trent Buck
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <20050303193353.7d1903a4@harpo.marx>
Spake Brian Downing:
> > Not generically, in C.  Variadic generic C macros are impossible, even
> > with GNU extensions.
> 
> I'm not sure what you mean by "generic", and I'm aware the following is
> a crime against God and man (and that it's C99-only), but:

As in, it can take (in the case of C) floats or integers, or floats AND
integers.  An arbitrary number of them.

Common Lisp's + operator is both variadic and generic.

> [scary C macrology]

I think I need to lie down.

-- 
Trent Buck, Student Errant
<foo> Anybody ever wonder what would happen if we were suddenly flung
<foo> into a weird dimension and we were all in a room together?
<bar> I'd have to pull my pants up real quick, most likely.
From: Hannah Schroeter
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <d0mq3c$j2q$1@c3po.use.schlund.de>
Hallo!

Trent Buck  <·········@tznvy.pbz> wrote:
>[...]

>Anonymous functions are very neat.  An example Sussman uses is

>	(defun my-cons (a b)
>	  (lambda (x)
>	    (if x a b)))

>	(defun my-car (x)
>	  (funcall x t))

>	(defun my-cdr (x)
>	  (funcall x nil))

Using if for this... Why?

(defun my-cons (a b)
  (lambda (f) (funcall f a b)))

(defun my-car (c)
  (funcall c (lambda (a b) a)))

(defun my-cdr (c)
  (funcall c (lambda (a b) b)))

Kind regards,

Hannah.
From: John Thingstad
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <opsm0n4iwqpqzri1@mjolner.upc.no>
On Wed, 2 Mar 2005 08:57:37 +0100, Alexander Schreiber  
<···@usenet.thangorodrim.de> wrote:


Not quite sure where I dug this up from..

;;;;
;;;; turbo pi -- calculate pi to 1000 decimals >>>fast
;;;;
;;;;   It uses a spigot algorithm. More details in A spigot algorithm for  
the digits of pi,
;;;;   Stanley Rabinowitz and Stan Wagon, American Mathematical Monthly,  
March 1995, pp195-203.

(defun pi-2000 ()
   (let ((e 0)
         (f (make-array 3501 :initial-element 2000)))
     (loop for c from 3500 above 0 by 14 do
           (let ((d 0))
             (loop for b from c above 0 do
                   (let ((g (1- (* 2 b))))
                     (setf d (+ (* d b) (* (aref f b) 10000)))
                     (setf (aref f b) (mod d g))
                     (setf d (floor d g))))
             (multiple-value-bind (div mod) (floor d 10000)
               (format t "~4,'0D" (+ e div))
               (setf e mod))))))


> (pi-2000)
31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201 
98

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
From: Frank Buss
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <d04n1s$hub$1@newsreader2.netcologne.de>
"John Thingstad" <··············@chello.no> wrote:

> On Wed, 2 Mar 2005 08:57:37 +0100, Alexander Schreiber  
> <···@usenet.thangorodrim.de> wrote:
> 
> 
> Not quite sure where I dug this up from..

it was written by me:

http://groups.google.de/groups?selm=cn3e55%24367%241%40newsreader2.netcologne.de 

and the function must be named "pi-1000", but the original code was written
by someone in TCL, I've only ported it to Common Lisp.

-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Wade Humeniuk
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <e2mVd.34132$hN1.21263@clgrps13>
One of my favorites, "The Bottle Song"

http://www.99-bottles-of-beer.net/c.html#Common-Lisp-(format-string)

Wade
From: ···············@yahoo.com
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <1109791720.544705.186000@z14g2000cwz.googlegroups.com>
Cool!  But note the end of the web address.  The example under plain
"Common LISP" is straightforward but pedestrian.  The example under
"LISP" uses format intensively, hence is probably not good for the OP.
From: Peter Lewerin
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <b72f3640.0503030435.46b54257@posting.google.com>
Wade Humeniuk <··················@telus.net> wrote

[...]

While impressive, it seems more like a demonstration of the FORMAT
language to me.  How about this:

   (let ((n 99)
         (fmt "~(···@*~P ~2*~{~S ~}~)"))
     "'You're not expected to understand this' -- Dennis Ritchie"
     (macrolet ((n (what &rest rest)
                  `(format t "~%~S ·@?" n fmt ',what ',rest))
                (take (&rest rest)
                  `(format t ····@(~{~S ~}~)" (cons 'take ',rest)))
                (n-1 (what &rest rest)
                  (decf n)
                  `(format t "~%~[No more~:;~:*~S~] ·@?~%"
                           n fmt ',what ',rest)))
       "This should be easier to understand"
       (loop while (> n 0)
          do
          (n bottle of beer on the wall)
          (n bottle of beer)
          (take one down - pass it around)
          (n-1 bottle of beer on the wall))))
From: Brian Downing
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <%JGVd.87302$tl3.59926@attbi_s02>
In article <····························@posting.google.com>,
Peter Lewerin <·············@swipnet.se> wrote:
> Wade Humeniuk <··················@telus.net> wrote
> 
> [...]
> 
> While impressive, it seems more like a demonstration of the FORMAT
> language to me.  How about this:
> 
> [...]
>                 (n-1 (what &rest rest)
>                   (decf n)
>                   `(format t "~%~[No more~:;~:*~S~] ·@?~%"
>                            n fmt ',what ',rest)))

This should be something like:

               (n-1 (what &rest rest)
                 `(format t "~%~[No more~:;~:*~S~] ·@?~%"
                          (decf n) fmt ',what ',rest)))

...otherwise it's unlikely to work compiled.  (And indeed doesn't in
SBCL.)

-bcd
-- 
*** Brian Downing <bdowning at lavos dot net> 
From: Peter Seibel
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <m3ll94ptxm.fsf@gigamonkeys.com>
·············@swipnet.se (Peter Lewerin) writes:

> Wade Humeniuk <··················@telus.net> wrote
>
> [...]
>
> While impressive, it seems more like a demonstration of the FORMAT
> language to me.  How about this:
>
>    (let ((n 99)
>          (fmt "~(···@*~P ~2*~{~S ~}~)"))
>      "'You're not expected to understand this' -- Dennis Ritchie"
>      (macrolet ((n (what &rest rest)
>                   `(format t "~%~S ·@?" n fmt ',what ',rest))
>                 (take (&rest rest)
>                   `(format t ····@(~{~S ~}~)" (cons 'take ',rest)))
>                 (n-1 (what &rest rest)
>                   (decf n)
>                   `(format t "~%~[No more~:;~:*~S~] ·@?~%"
>                            n fmt ',what ',rest)))
>        "This should be easier to understand"
>        (loop while (> n 0)
>           do
>           (n bottle of beer on the wall)
>           (n bottle of beer)
>           (take one down - pass it around)
>           (n-1 bottle of beer on the wall))))

That's cool but it has a bug in it--the (decf n) should be part of the
expansion of N-1. Here's a fixed and slightly simplified version:

    (defun bottles-of-beer (&optional (n 99))
      "'You're not expected to understand this' -- Dennis Ritchie"
      (macrolet ((n (what &rest rest)
                   `(format 
                     t "~&~[No more~:;~:*~:(~r~)~] ~(~a~2:*~p ~*~{~S ~}~)~%" 
                     n ',what ',rest))
                 (take (&whole whole &rest ignore)
                   `(format t "~&·@(~{~S ~}~)" ',whole))
                 (n-1 (&rest rest)
                   `(progn (decf n) (n ,@rest) (terpri))))
        "This should be easier to understand"
        (loop while (> n 0) do
             (n bottle of beer on the wall)
             (n bottle of beer)
             (take one down - pass it around)
             (n-1 bottle of beer on the wall))))

-Peter

-- 
Peter Seibel                                     ·····@gigamonkeys.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Alan Crowe
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <868y55udjq.fsf@cawtech.freeserve.co.uk>
Alexander Schreiber seeks code
>  - should _not_ be obfuscated - I'm trying to get people interested
>    in Lisp, not scare them away,

This example talks about the intrinsic tendency of some kinds
of code to end up obfuscated, and how Common Lisp lets the
programmer fight back.

In the ancient Chinese game of GO, stones of the same colour
are connected if they are adjacent horizontally or
vertically. ``Being connected'' gathers the stones into
groups. Technically we regard ``being connected'' as a
relation and a group of stones is an equivalence class of
the transitive closure of the relation.

Since it is groups of stones that get captured even a
go-board program, for two humans to play each other, must
assemble the stones into groups, if it is to remove captured
stones from the board.

My code calculates the groups in two stages. The first stage
scans the array representing the board, top-to-bottom,
left-to-right, assigning group numbers to stones. It often
divides the stones into too many groups, but it realises
when it has gone wrong and provides enough information for
the second stage to merge surplus groups.

The first stage runs a counter and assigns a number to a
stone of the colour it is working on when it encounters it.
If there is a stone of the same colour to the left, the
stone on the left already has a group number assigned to it,
so that number should be reused. Similarly, if there is a
stone of the same colour immediately above, that will
already have a group number, which also should be reused.
If both cases apply and the numbers are different, the first
stage must take note that these two groups should be merged.

This kind of code is traditionally painful to write for two
reasons. First, everything about the code is in terms of
index arithmetic. Instead of talking about the stone on the
left, one talks about board[i][j-1]. The stone above is 
board[i-1][j]. One is plunged back into the world of machine
code or non-symbolic assemblers. Second, there is the
nine-way case split, into the four corners, the four sides,
and the interior. The notion of a bug in a corner case is to
be taken literally. Since there is usually some grouping of
cases, great care is needed to ensure that the tests on the
addresses are really grouping the cases in the way that the
programmer intended.

Here is my code:

(defun prelim-group-number (board colour)
  (let ((prelim-number-board (make-same-size-array board))
        (joins '())
        (count -1))
    (board-scan-case (above below right left middle prelim-number-board)
      (top-left
       (when (eql (middle board) colour)
         (setf middle (incf count))))
      ((top top-right)
       (when (eql (middle board) colour)
         (if left
             (setf middle left)
           (setf middle (incf count)))))
      ((left bottom-left)
       (when (eql (middle board) colour)
         (if above
             (setf middle above)
           (setf middle (incf count)))))
      ((interior right bottom bottom-right)
       (when (eql (middle board) colour)
         (if above
             (if left
                 (if (= above left)
                     (setf middle left)
                   (progn
                     (setf middle left)
                     (push (cons left above) joins)))
               (setf middle above))
           (if left
               (setf middle left)
             (setf middle (incf count)))))))
    (list prelim-number-board
          joins
          (+ count 1))))

It looks like pseudo-code. There is no sign of index
arithmetic. The grouping of the nine cases into four

1)top-left

2)top and top-right

3)left and bottom-left

4)interior, right, bottom, and bottom-right

is explicit in the source code.

Where has the nightmare of the address arithmetic gone?
It is hiding in the BOARD-SCAN-CASE macro, whose definition
has lines such as

(macrolet ((,north (board)
              `(aref ,board
                     (- ,',row-var 1)
                     ,',col-var))
           (,south (board)
              `(aref ,board
                     (+ ,',row-var 1)
                     ,',col-var)) ....

Ah well, there is no such thing as a free lunch.

It is not a free lunch, but it is actually very cheap.

1)The fiddly details of index arithmetic are defined in the
  macro once. Without such a macro they would be repeated
  several times in direct code.

2)The macro can be used in other places in the GO code such
  a counting liberties.

3)The macro is easy to test. It can be given bodies
  specifically designed to check all the cases. There is no
  comparable way of building confidence with direct code,
  because the index arithmetic must be typed in afresh for
  each slightly different application.

4)The approach suits work place demographics. The small
  number of expert programmers can write clever macros for
  the other programmers to use. This lets a software project
  fight back against the problem of having too few
  experienced programmers and too many raw recruits.

You can find the entire source file at

http://alan.crowe.name/lisp/go.lisp

just save it to disk and load it. It will automatically run
three demonstration cases.

This example gets away from the usual notions of code that
is especially short or clever. PRELIM-GROUP-NUMBER is well
over the 15 lines requested, and doesn't do anything
especially clever.

The idea is of using Common Lisp as an anti-obfuscation
tool. One tries to design out bugs and maintenance costs by
designing some macros so that the bulk of the code is easy
to read, easy enough that one can just see whether it is
correct or not.

Alan Crowe
Edinburgh
Scotland
From: Joe Marshall
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <ekexr8zc.fsf@ccs.neu.edu>
Alan Crowe <····@cawtech.freeserve.co.uk> writes:

   .... It looks like pseudo-code. ....

That's the essence of Lisp:  executable pseudo-code.
From: Dave Roberts
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <m38y551pu6.fsf@linux.droberts.com>
Joe Marshall <···@ccs.neu.edu> writes:

> Alan Crowe <····@cawtech.freeserve.co.uk> writes:
> 
>    .... It looks like pseudo-code. ....
> 
> That's the essence of Lisp:  executable pseudo-code.

Hmmmm... that may have just made my signature. ;-)

-- 
Dave Roberts
dave -remove- AT findinglisp DoT com
http://www.findinglisp.com/

The essence of Lisp: executable pseudo-code. -- Joe Marshall, comp.lang.lisp
From: David Steuber
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <87ekexk4sg.fsf@david-steuber.com>
No one posted the banal examples that are supposed to impress you as a
beginner:

(defun make-fib-gen ()
  (let ((a 1) (b 1))
    (lambda ()
      (let ((c (+ a b)))
        (rotatef a b c)
        c))))

(defun repl ()
  (loop (print (eval (read)))))

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Kalle Olavi Niemitalo
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <87r7itar5m.fsf@Astalo.kon.iki.fi>
David Steuber <·····@david-steuber.com> writes:

> (defun make-fib-gen ()
>   (let ((a 1) (b 1))
>     (lambda ()
>       (let ((c (+ a b)))
>         (rotatef a b c)
>         c))))

Simpler version:

(defun make-fib-gen ()
  (let ((a 1) (b 1))
    (lambda ()
      (shiftf a b (+ a b)))))
From: Wade Humeniuk
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <OIpVd.23164$LN5.7280@edtnps90>
This following code is a bit longer than you might like,
but it shows some GUI code (LW CAPI to be exact) that
provides a framework to prompt a user for a username and
password:

(capi:define-interface login-dialog ()
   ()
   (:panes
    (user capi:text-input-pane
          :text ""
          :callback-type :interface
          :callback 'exit-login-dialog)
    (pass capi:password-pane
          :text ""
          :callback-type :interface
          :callback 'exit-login-dialog)
    (ok capi:push-button
        :text "Login" :data 'login
        :callback 'exit-login-dialog)
    (cancel capi:push-button
            :text "Cancel" :data 'cancel
            :callback 'capi:abort-dialog))
   (:layouts
    (main capi:column-layout '(input-pane-layout buttons))
    (input-pane-layout capi:grid-layout
                       '("Username:" user
                         "Password:" pass))
    (buttons capi:row-layout '(ok cancel)))
   (:default-initargs
    :title "Login"
    :min-width 256))

(defun exit-login-dialog (login-dialog)
   (capi:exit-dialog
    (with-slots (user pass) login-dialog
      (list (capi:text-input-pane-text user)
            (capi:text-input-pane-text pass)))))
From: Andras Simon
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <vcdekexlrfm.fsf@csusza.math.bme.hu>
Alexander Schreiber <···@usenet.thangorodrim.de> writes:

> Hi!
> 
> I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
> event in Germany.
> 
> To show off the elegance and power of Lisp I'm looking for very short
> "magic" snippets of Lisp code: 
>  - does something tricky/complex/interesting in a (for Lisp)
>    simple and elegant way,
>  - possible showing of some very useful Lisp features (like bignums,
>    crypto in < 1 K of Lisp code anyone?),
>  - should fit in 15 lines by 50 characters (presentation foils),
>  - should _not_ be obfuscated - I'm trying to get people interested
>    in Lisp, not scare them away,
>  - credit will of course be given (or withheld, honouring the wishes
>    of the author of the Lisp snippet)
> 

I don't know if this fits the bill, but how about something like this: 

(defmacro nested-dotimes (vars-and-limits &body forms)
;; Warning: not scanned for hygiene!
  (if (null vars-and-limits)
    `(progn ,@forms)
    (loop for v-l in (reverse vars-and-limits)
      for call = `(dotimes ,v-l ,@forms) then `(dotimes ,v-l ,call)
      finally (return call))))

so that one can write 

(nested-dotimes ((i 100)(j 200) (k 300)) ( ... ))

instead of 

(dotimes (i 100) 
   (dotimes (j 200) 
      (dotimes (k 300) 
         ( ... ))))

Maybe it's a silly example, but the point is that it's very easy to
extend the language with new control structures. 

Andras
From: Joerg Hoehle
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <uy8cvk8ux.fsf@users.sourceforge.net>
Andras Simon <······@math.bme.hu> writes:
> (nested-dotimes ((i 100)(j 200) (k 300)) ( ... ))
> instead of 
> (dotimes (i 100) 
>    (dotimes (j 200) 
>       (dotimes (k 300) 
>          ( ... ))))

This expansion naturally(?) leads to a recursive solution. I feel that
your use of LOOP feels to me like a hammer for everything, and not
really appropriate here.

> (defmacro nested-dotimes (vars-and-limits &body forms)
> ;; Warning: not scanned for hygiene!
>   (if (null vars-and-limits)
>     `(progn ,@forms)
>     (loop for v-l in (reverse vars-and-limits)
>       for call = `(dotimes ,v-l ,@forms) then `(dotimes ,v-l ,call)
>       finally (return call))))

Plain recursion would have been straight forward and more readable IMHO.

How about:
(defmacro nested-dotimes (vars-and-limits &body forms)
  (if (consp vars-and-limits)
      `(dotimes ,(first vars-and-limits)
	 (nested-dotimes ,(rest vars-and-limits) .,forms))
    (cons 'progn forms)))
;(macroexpand-1'(nested-dotimes ((i 1)(j 2) (k 3)) (print (list i j k))))
and have the system recurse nested macros for you.

If you want it expanded in one go, read on.

The expansion above exhibits the pattern of a typical walk operation
over a list. As thus, it can be expressed using REDUCE:

(defmacro nested-dotimes (vars-and-limits &body forms)
  (reduce (lambda (iter body) (list 'dotimes iter body)) vars-and-limits
	  :from-end t :initial-value (cons 'progn forms)))

which leads us to a point where it clearly appears that our friends
from the functional programming (FP) and esp. Haskell camp may also
define a similar "control" structure in 2-3 lines of code.

If you prefer do-it-yourself:
(defmacro nested-dotimes (vars-and-limits &body forms)
  (labels ((nest (iters)
	     (if (consp iters)
		;;or (list 'dotimes (first iters) (nest (rest iters)))
		 `(dotimes ,(first iters)
		    ,(nest (rest iters)))
	       `(progn . ,forms))))
    (nest vars-and-limits)))
which is very close to my first macro.

IMHO, to have a chance of being adopted by more than one person, such
a macro must allow for declarations. Left as an exercise, esp. w.r.t. scoping.

Hey, I like this thread -- 3 posts already :)

Regards,
	Jorg Hohle
Telekom/T-Systems Technology Center
From: Philippe Brochard
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <87vf897ofl.fsf@grigri.elcforest>
Alexander Schreiber hat geschrieben:


> To show off the elegance and power of Lisp I'm looking for very short
> "magic" snippets of Lisp code: 

I don't know if that look like what you want, but here is what I plan
to use for propaganda :)

----------------------------------------------------------------------
(defparameter *xml-stream* t)

(defun print-space (n)
  (dotimes (i n)
    (format t " ")))

(defun produce-xml (tree &optional (level 0))
  (cond ((listp tree)
	 (print-space level)
	 (format *xml-stream* "~(<~A>~)~%" (first tree))
	 (dolist (subtree (rest tree))
	   (produce-xml subtree (+ 2 level)))
	 (print-space level)
	 (format *xml-stream* "~(</~A>~)~%"
		 (if (stringp (first tree))
		     (subseq (first tree) 0 (position #\Space (first tree)))
		   (first tree))))
	(t
	 (print-space level)
	 (format *xml-stream* "~(~A~)~%" tree))))


(defmacro with-xml (&rest rest)
  `(produce-xml ',@rest))


(with-xml
 (xml
  (title "A very long title.")
  (ref ·······@domain.foo)
  ("block id = \"foo\""
   (title bar
	  foo)
   (tartaz "a long symbol ;"
	   bar)
   (bazbaz
    "a block"
    "on multi"
    lines))
  ("block id = 123"
   (title "an other title")
   (ref ···@baz.foo))))

produce:

<xml>
  <title>
    a very long title.
  </title>
  <ref>
    ·······@domain.foo
  </ref>
  <block id = "foo">
    <title>
      bar
      foo
    </title>
    <tartaz>
      a long symbol ;
      bar
    </tartaz>
    <bazbaz>
      a block
      on multi
      lines
    </bazbaz>
  </block>
  <block id = 123>
    <title>
      an other title
    </title>
    <ref>
      ···@baz.foo
    </ref>
  </block>
</xml>
----------------------------------------------------------------------


----------------------------------------------------------------------
(defmacro progn-rev (&body body)
  `(progn
     ,@(reverse body)))

(progn-rev
  (print 1)
  (print 2)
  (print 3)
  (print 4))
4 
3 
2 
1 
----------------------------------------------------------------------

And a use: undo/redo with the same code:

----------------------------------------------------------------------
(defparameter *do* t)
(defparameter *var* 0)

(defun add (x)
  (if *do*
      (format t "~&Add ~A to ~A => ~A" *var* x (incf *var* x))
    (format t "~&Sub ~A to ~A => ~A" *var* x (decf *var* x))))


(defun sub (x)
  (if *do*
      (format t "~&Sub ~A to ~A => ~A" *var* x (decf *var* x))
    (format t "~&Add ~A to ~A => ~A" *var* x (incf *var* x))))


(defun mul (x)
  (if *do*
      (format t "~&Mul ~A with ~A => ~A" *var* x (setf *var* (* *var* x)))
    (format t "~&Div ~A with ~A => ~A" *var* x (setf *var* (/ *var* x)))))


(defun div (x)
  (if *do*
      (format t "~&Div ~A with ~A => ~A" *var* x (setf *var* (/ *var* x)))
    (format t "~&Mul ~A with ~A => ~A" *var* x (setf *var* (* *var* x)))))


(defmacro progn-norm (&body body)
  `(progn
     (setq *do* t)
     ,@body))

(defmacro progn-rev (&body body)
  `(progn
     (setq *do* nil)
     ,@(reverse body)))

(setq *var* 0)

> (progn-norm
   (add 10)
   (mul 3)
   (sub 15)
   (div 2)
   (add 150))
Add 0 to 10 => 10
Mul 10 with 3 => 30
Sub 30 to 15 => 15
Div 15 with 2 => 15/2
Add 15/2 to 150 => 315/2

*var* => 315/2

> (progn-rev
   (add 10)
   (mul 3)
   (sub 15)
   (div 2)
   (add 150))
Sub 315/2 to 150 => 15/2
Mul 15/2 with 2 => 15
Add 15 to 15 => 30
Div 30 with 3 => 10
Sub 10 to 10 => 0

*var* => 0
----------------------------------------------------------------------


But, I don't know if this is sufficiently "lispy" or elegant.

-- 
Philippe Brochard    <···········@SPAM_free.fr>
                      http://hocwp.free.fr
From: Philippe Brochard
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <87psyh7n1u.fsf@grigri.elcforest>
Philippe Brochard a �crit :


[...]


> (defun add (x)
>   (if *do*
>       (format t "~&Add ~A to ~A => ~A" *var* x (incf *var* x))
>     (format t "~&Sub ~A to ~A => ~A" *var* x (decf *var* x))))
>
>
> (defun sub (x)
>   (if *do*
>       (format t "~&Sub ~A to ~A => ~A" *var* x (decf *var* x))
>     (format t "~&Add ~A to ~A => ~A" *var* x (incf *var* x))))
>
Yoops, sorry, it's:

(format t "~&Add ~A to ~A => ~A" x *var* (incf *var* x))
(format t "~&Sub ~A to ~A => ~A" x *var* (decf *var* x))


And then:

(progn-norm  (add 10)  (mul 3)  (sub 15)  (div 2)  (add 150) ...
Add 10 to 0 => 10
Mul 10 with 3 => 30
Sub 15 to 30 => 15
Div 15 with 2 => 15/2
Add 150 to 15/2 => 315/2

(progn-rev  (add 10)  (mul 3)  (sub 15)  (div 2)  (add 150)) ...
Sub 150 to 315/2 => 15/2
Mul 15/2 with 2 => 15
Add 15 to 15 => 30
Div 30 with 3 => 10
Sub 10 to 10 => 0

[...]


-- 
Philippe Brochard    <···········@SPAM_free.fr>
                      http://hocwp.free.fr
From: ·············@abc.xyz
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <135d21li7ti5ooob58dsoaiqulasm6rip0@4ax.com>
; This isn't a 15-line snippet, but the usage examples
; at the end could be considered short snippets.


#|  To skip the implementation details and go straight to the demo,
    see the usage examples at the end, copy/paste this whole thing
    into Lispworks, and press the enter key, so the usage examples
    will be executed.  Lispworks can be downloaded free from
    www.lispworks.com
|#


#|  The compose macro takes any number of functions as its arguments
    and makes a composite function from them.  Use it wherever a
    function is expected, e.g. (mapcar (compose 1+ 1+) '(10 20 30))
    ==> (12 22 32)
    Note that the arguments to compose are unquoted, e.g. 1+ vs '1+.
|#
(defmacro compose (&rest funcs)
  (loop with code = 'x
        as func in (reverse funcs)
        do (setq code (list func code))
        finally (return `(lambda (x) ,code))))


#|  Kwd converts symbols or strings to a keyword, e.g.
    (kwd 'red "white" "BluE") ==> :redwhiteblue
|#
(defun kwd (&rest parts)
  (values
    (intern
      (apply 'concatenate 'string
        (loop as part in parts collect
          (string-upcase part)))
      'keyword)))


#| tabcolors-helper is invoked by tabcolors, which gives it a
   list of colors as keyword symbols.  They have to be colors
   known to Lispworks.  To make the usage of tabcolors neater,
   it converts ordinary unquoted symbols to keywords.
|#
(defun tabcolors-helper (colorkeys)
  (capi:contain
    (make-instance 'capi:tab-layout
      :items
        (loop as color in colorkeys
              as pane = (make-instance 'capi:output-pane
                          :background color)
              collect (list color pane))
      :print-function (compose string-capitalize car)
      :visible-child-function 'second)))

(defmacro tabcolors (&rest colors)
   `(tabcolors-helper
      ',(loop as c in colors
              collect (kwd c))))


; Usage:
; Usage is what matters most.  Common Lisp lets you make
; usage simple and elegant.  The following two examples
; show usage of tabcolors.

(tabcolors red orange yellow blue)
(tabcolors green gray)

; Note that the color arguments to tabcolors are unquoted symbols.

--
My email address is ··········@ISP.net where Name is
eric, Number is 9000, and ISP is earthlink.
From: Peter Seibel
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <m31xaxqq5e.fsf@gigamonkeys.com>
Alexander Schreiber <···@usenet.thangorodrim.de> writes:

> Hi!
>
> I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
> event in Germany.
>
> To show off the elegance and power of Lisp I'm looking for very short
> "magic" snippets of Lisp code: 

Hmmm. I'm a bit sceptical of this approach--something that small is
either likely to seem silly or, if it really does do a lot, scary
until you understand how it works which takes a lot of "back story".
At least that's been my experience. But you know your audience.
Anyway, that said, you might be able to find something to work with
in:

  <http://www.gigamonkeys.com/book/practical-building-a-unit-test-framework.html>

The final test framework in only 26 lines. And you'd also need to give
some examples of what it lets you write. Anyway, that chapter contains
about as compressed an introduction to The Common Lisp Way that I
could come up with. Feel free to adapt the material in that chapter
(or anything else from the book) however you see fit; just give
appropriate credit--i.e. plug my book. ;-)

-Peter

-- 
Peter Seibel                                     ·····@gigamonkeys.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Gisle Sælensminde
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <slrnd2di6j.gi0.gisle@kaktus.ii.uib.no>
On 2005-03-02, Alexander Schreiber <···@usenet.thangorodrim.de> wrote:
> Hi!
>
> I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
> event in Germany.
>
> To show off the elegance and power of Lisp I'm looking for very short
> "magic" snippets of Lisp code: 

One thing that is really cool with lisp, is that you can do thing that only
can be done by external tools, generating the code in other languages. Things
like lexers and lalr-parsers is usually generated by tools like lex or yacc,
that exists for most programming languages. Then this generated code will
do the job. In lisp you don't need to do this, since macros can do this 
in the language itself. For example, I had some data that was defined in form
of arrays in a little-known programming language, and wrote a parser for this
subset. The lexer looks like this:

(deflexer darwin-lex
  ("'[^\']*'"       'string)
  ("#.*$"           'comment)
  ("\\s+"           'ws)
  (":="             'assign)
  ("[\[]"           'lbrack)
  ("[\]]"           'rbrack)
  ("[\,]"           'comma)
  ("[\:]"           'colon)
  ("[\;]"           'semicolon)
  ("[+-]?([0-9]+[\.])?[0-9]+([eE][+-]?[0-9]+)?"  'float)
  ("[+-]?[0-9]+"    'integer)
  ("[a-zA-Z0-9_]+"  'id)
  ("."              'unknown)
  )

This expands to calls to Edi Weitz' cl-ppcre library. The macro is also
made by Edi Weitz. I asked him how I could make such a macro efficient 
using cl-ppcre, and he just returned the macro, that is 19 lines of code.
(But is using cl-ppcre that is much more of cause).  

If your audience knows the "dragon book stuff" this is a really cool example.
Otherwise it would probably just confuse them. 

-- 
Gisle S�lensminde, Phd student, Scientific programmer
Computational biology unit, University of Bergen, Norway
Email: ·····@cbu.uib.no | Complicated is easy, simple is hard.
From: John Thingstad
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <opsm1zqoegpqzri1@mjolner.upc.no>
On 3 Mar 2005 08:20:35 GMT, Gisle Sælensminde <·····@kaktus.ii.uib.no>  
wrote:

> subset. The lexer looks like this:
>
> (deflexer darwin-lex
>   ("'[^\']*'"       'string)
>   ("#.*$"           'comment)
>   ("\\s+"           'ws)
>   (":="             'assign)
>   ("[\[]"           'lbrack)
>   ("[\]]"           'rbrack)
>   ("[\,]"           'comma)
>   ("[\:]"           'colon)
>   ("[\;]"           'semicolon)
>   ("[+-]?([0-9]+[\.])?[0-9]+([eE][+-]?[0-9]+)?"  'float)
>   ("[+-]?[0-9]+"    'integer)
>   ("[a-zA-Z0-9_]+"  'id)
>   ("."              'unknown)
>   )
>

How do you tell the difference between a float and a integer?
Seems like every integer is also a legal float.
If your parser works from top to bottom you should never
generate a integer.

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
From: Gisle Sælensminde
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <slrnd2dm7f.m41.gisle@kaktus.ii.uib.no>
On 2005-03-03, John Thingstad <··············@chello.no> wrote:
> On 3 Mar 2005 08:20:35 GMT, Gisle Sælensminde <·····@kaktus.ii.uib.no>  
> wrote:
>
>> subset. The lexer looks like this:
>>
>> (deflexer darwin-lex
>>   ("'[^\']*'"       'string)
>>   ("#.*$"           'comment)
>>   ("\\s+"           'ws)
>>   (":="             'assign)
>>   ("[\[]"           'lbrack)
>>   ("[\]]"           'rbrack)
>>   ("[\,]"           'comma)
>>   ("[\:]"           'colon)
>>   ("[\;]"           'semicolon)
>>   ("[+-]?([0-9]+[\.])?[0-9]+([eE][+-]?[0-9]+)?"  'float)
>>   ("[+-]?[0-9]+"    'integer)
>>   ("[a-zA-Z0-9_]+"  'id)
>>   ("."              'unknown)
>>   )
>>
>
> How do you tell the difference between a float and a integer?
> Seems like every integer is also a legal float.
> If your parser works from top to bottom you should never
> generate a integer.
>

In the application in question it do not matter, and the application
does it's job. However, it should be fixed before used as an example of
cause. The decimal point should be mandatory, so the float expression
should probably be fixed to the following (untested):

([+-]?([0-9]+))?|0[\.][0-9]+([eE][+-]?[0-9]+)?

And this is of cause another example of regular expressions being hard
to read.

-- 
Gisle S�lensminde, Phd student, Scientific programmer
Computational biology unit, University of Bergen, Norway
Email: ·····@cbu.uib.no | Complicated is easy, simple is hard.
From: David Combs
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <d22o78$jum$1@reader1.panix.com>
In article <····················@kaktus.ii.uib.no>,
Gisle Sælensminde  <·····@kaktus.ii.uib.no> wrote:
>On 2005-03-02, Alexander Schreiber <···@usenet.thangorodrim.de> wrote:
...
>subset. The lexer looks like this:
>
>(deflexer darwin-lex
>  ("'[^\']*'"       'string)
>  ("#.*$"           'comment)

Naive question, I'm sure -- but what's that deflexer?


Or is it in that library you mentioned?

Thanks,

David
From: Pascal Costanza
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <d06qco$7d1$1@snic.vub.ac.be>
Alexander Schreiber wrote:
> Hi!
> 
> I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
> event in Germany.
> 
> To show off the elegance and power of Lisp I'm looking for very short
> "magic" snippets of Lisp code: 
[...]

Some time ago, I have checked the GoF patterns against Lisp programming 
practice. Here are a few examples.

Adapter pattern
~~~~~~~~~~~~~~~~

The Adapter pattern allows adding new methods to an existing class 
interface. You already have that in CLOS because methods are not defined 
as part of a class.


Chain of Responsibility pattern
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

At least one in a list of objects is able to handle a certain request. 
One of those is selected to actually handle the request.

(some (lambda (elem)
         (when (applicable-p elem)
           (dosomething)))
       list)


Command pattern
~~~~~~~~~~~~~~~

= first-class functions


Composite pattern
~~~~~~~~~~~~~~~~~

not needed because methods are not part of a class definition. Just 
store your stuff in one of the predefined data structures (list, tree, etc.)


Interpreter pattern
~~~~~~~~~~~~~~~~~~~

The purpose is to define an abstract grammar for a kind of 
domain-specific language and write an evaluator for that language. :-))


Iterator pattern
~~~~~~~~~~~~~~~~

To quote Richard Gabriel: "I would say that patterns are alive and well 
as a form of documentation and a quest for clever solutions to common 
programming problems, and pattern languages, QWAN, and the quest for a 
better future are now on their way to the sewage treatment plant � the 
same place they went to in the world of architecture. Down with quality, 
up with clever hacks. Why worry about what makes a user interface 
beautiful and usable when you can wonder how to do mapcar in C++."


Observer pattern
~~~~~~~~~~~~~~~~

Just write an after method on the writer function that you're interested 
  in.


Singleton pattern
~~~~~~~~~~~~~~~~~

I think this is one of the most useless patterns around.


Visitor pattern
~~~~~~~~~~~~~~~

This is the coolest one of all in Lisp: The purpose of the Visitor 
pattern is to group methods according to the functionality they provide, 
not according to the classes to which they belong. Assume you have the 
following classes and methods:

(defclass arithmetic-expression (expression)
   (op lhs rhs))

(defmethod typecheck ((expression arithmetic-expression))
   ...)

(defclass boolean-expression (expression)
   (op lhs rhs))

(defmethod typecheck ((expression boolean-expression))
   ...)

Now we apply the Visitor pattern:

(defclass arithmetic-expression (expression)
   (op lhs rhs))

(defclass boolean-expression (expression)
   (op lhs rhs))

(defmethod typecheck ((expression arithmetic-expression))
   ...)

(defmethod typecheck ((expression boolean-expression))
   ...)

Done. The Visitor pattern in Lisp is implemented by Ctrl-Meta-t. ;)


Pascal
From: M Jared Finder
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <42274745_3@x-privat.org>
Pascal Costanza wrote:
> Alexander Schreiber wrote:
> 
>> Hi!
>>
>> I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
>> event in Germany.
>>
>> To show off the elegance and power of Lisp I'm looking for very short
>> "magic" snippets of Lisp code: 
> 
> [...]
> 
> Some time ago, I have checked the GoF patterns against Lisp programming 
> practice. Here are a few examples.

I've been suspecting for a while that design patterns are just a more
formalized way of cut-n-paste coding, but without the advantages of Lisp
macros.  Thanks for doing all the work for me!  What really drove it
home for me was re-reading the last paragraph in section 1.1 of the GoF
book:

The choice of programming language is important because it influences
one's point of view.  Our patterns assume Smalltalk/C++-level language
features, and that choice determines what can and cannot be implemented
easily.  If we assumed procedural languages, we might have included
design patterns called "Inheritance," "Encapsulation," and
"Polymorphism."  Similarly, some of our patterns are supported directly
by the less common object-oriented languages.  CLOS has multi-methods,
for example, which lessen the need for a pattern such as Visitor.  In
fact, there are enough differences between Smalltalk and C++ to mean
that some patterns can be expressed more easily in one language than the
other.

When I read that paragraph after just a little bit of experience with
Lisp, I had an Aha! moment -- C++ is a hell of a lot more productive
language than C because it provides easy access to the fundamental OO
design patterns of Inheritance, Encapsulation, and Polymorphism, but why
stop there?  A language that provided easy access *any* design patterns
would be so much more productive than C++ to knock my socks off!  And
Lisp allows that easy access through just macros and lambdas.  Just look
at CLOS or Cells or Iterate or ....

The choice of programming language *is* important.

   -- MJF
From: John Thingstad
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <opsm2psxbupqzri1@mjolner.upc.no>
On Thu, 03 Mar 2005 11:54:16 +0100, Pascal Costanza <··@p-cos.net> wrote:

Yes. I noticed norvig discusses patterns in his slide representation
http://norvig.com/design-patterns/ppframe.htm

Note in particular:
Design patterns in dynamic languages and
Design patterns in Dylan and Lisp
-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
From: Rahul Jain
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <876505i921.fsf@nyct.net>
Pascal Costanza <··@p-cos.net> writes:

> Singleton pattern
> ~~~~~~~~~~~~~~~~~
>
> I think this is one of the most useless patterns around.

In an interview (not conducted by me), the interviewee called this
pattern the "simpleton pattern". How freudian. :)

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Jonathan Bartlett
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <42276ca8@news.tulsaconnect.com>
You could use eval-when to pregenerate lookup tables or something like 
that.  In other languages you have to compute them yourself and include 
the results.  In Lisp you can just use eval-when and only have to write 
how the tables are derived.  This is then done at compile-time.

Other macro-ish things are quite interesting.  Especially things like 
standardized reports and templates can be practically done-away with by 
converting the templates into macros.

Also with macros you can show how you can build a mini-language as a set 
of LISP macros to make coding easier, but still retain the full power of 
LISP for more difficult tasks.

Dynamic variables, although they should be used sparingly, are really 
quite useful for applications that must run functions in various modes, 
and switch between them.

Jon
From: Alexander Schreiber
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <slrnd2h6rc.554.als@mordor.angband.thangorodrim.de>
Peter Seibel <·····@gigamonkeys.com> wrote:
> Pascal Costanza <··@p-cos.net> writes:
> 
>> Alexander Schreiber wrote:
>>> Jonathan Bartlett <·······@eskimo.com> wrote:
>>> 
>>>> Also with macros you can show how you can build a mini-language as
>>>> a set of LISP macros to make coding easier, but still retain the
>>>> full power of LISP for more difficult tasks.
>>> For macros I'll use with-open-file, because with this example I can
>>> roll
>>> several things into one example:
>>>  - how macros rewrite code instead of doing text replacement is on
>>>    lesser languages,
>>>  - implementing large parts of Common Lisp using itself,
>>>  - the ability to implement guaranteed[0] cleanups using uncircumventable
>>>    language features
>>
>> I have used the with-open-file example in front of a Java audience,
>> and this doesn't seem to work. Java people don't seem to feel the
>> pain of having to use try-finally for making sure that a file is
>> closed. Furthermore, there could be Python programmers in the
>> audience that would start a discussion about how the garbage
>> collector could handle this, and you don't want that discussion
>> because it would miss the point.
> 
> Pascal's point is a good one but if you must go this route with Java
> programmers, you might have better luck a WITH-DATABASE-QUERY macro
> since in Java the idiom of try/catch/finally blocks necessary to open,
> use, and correctly close a database connection, statement, and result
> set in order to do a single query is much worse than the try/finally
> idiom needed to open, use, and close a single file. In other words,
> you can make the pain more obvious, even to your average numbed Java
> programmer.

That's indeed a good idea. Just this week I head to deal with Java
applications leaking database connections all over the place and thus
making the database rather unhappy after a while.

Yes, I think an (with-db-connection ...) example will work much better
than an (with-open-file ... ) one.

Regards,
      Alex.
-- 
"Opportunity is missed by most people because it is dressed in overalls and
 looks like work."                                      -- Thomas A. Edison
From: Dave Roberts
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <m3oedv7z70.fsf@linux.droberts.com>
Alexander Schreiber <···@usenet.thangorodrim.de> writes:

> That's indeed a good idea. Just this week I head to deal with Java
> applications leaking database connections all over the place and thus
> making the database rather unhappy after a while.
> 
> Yes, I think an (with-db-connection ...) example will work much better
> than an (with-open-file ... ) one.

I would look for examples that are relevent to your particular
audience. If you work with these guys and know their projects well,
it's far more powerful to say, "Guys, you know how we have this
problem... well, this is how Lisp would solve that simply and
elegantly." If that problem is databases, fine. If something else,
fine. Just make it personal to them. Then it's powerful.

In general, I'm not very impressed by the little "gee-wiz" examples
that people cook up, like rational numbers, etc. The problem is,
unless somebody has been struggling with round-off of floats for the
last two weeks, then it's nothing more than a stunt and what's going
through the guy's head is, "Okay, that's fine. You can say '(+ 1/3 1/3
1/3)' and the answer is 1. Fine. That's not my problem. And Lisp is
still slow and I hate the parenthesis."

-- 
Dave Roberts
dave -remove- AT findinglisp DoT com
http://www.findinglisp.com/
From: Paolo Amoroso
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <87bra0elv7.fsf@plato.moon.paoloamoroso.it>
Alexander Schreiber <···@usenet.thangorodrim.de> writes:

> I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
> event in Germany.
>
> To show off the elegance and power of Lisp I'm looking for very short
> "magic" snippets of Lisp code: 

Here is another one:

  (+ 1/3 1/3 1/3) => 1


Paolo
-- 
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
Recommended Common Lisp libraries/tools (see also http://clrfi.alu.org):
- ASDF/ASDF-INSTALL: system building/installation
- CL-PPCRE: regular expressions
- UFFI: Foreign Function Interface
From: Rob Warnock
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <1qydnbTIE4KaZrffRVn-rA@speakeasy.net>
Paolo Amoroso  <·······@mclink.it> wrote:
+---------------
| Alexander Schreiber <···@usenet.thangorodrim.de> writes:
| > I'm looking for very short "magic" snippets of Lisp code: 
| 
| Here is another one:
|   (+ 1/3 1/3 1/3) => 1
+---------------

I tend to start first with this one:

    (+ 1/3 1/6) => 1/2

Then you hit them with either this:

    (+ 1/3 1/4 1/5 1/6) => 19/20

or this:

    (+ 1/3 1/4 1/5 1/6 1/20) => 1


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: GP lisper
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <1110139207.aadf72b64b60714575efaa36424cb789@teranews>
On Sun, 06 Mar 2005 06:43:51 -0600, <····@rpw3.org> wrote:
> Then you hit them with either this:
>
>     (+ 1/3 1/4 1/5 1/6) => 19/20
> or this:
>     (+ 1/3 1/4 1/5 1/6 1/20) => 1


 (- 1 (+ 1/3 1/4 1/5 1/6))


-- 
Everyman has three hearts;
one to show the world, one to show friends, and one only he knows.
From: Rob Warnock
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <27idnTFj3sa_E6zfRVn-tQ@speakeasy.net>
GP lisper  <········@clouddancer.com> wrote:
+---------------
| <····@rpw3.org> wrote:
| > Then you hit them with either this:
| >     (+ 1/3 1/4 1/5 1/6) => 19/20
| > or this:
| >     (+ 1/3 1/4 1/5 1/6 1/20) => 1
| 
|  (- 1 (+ 1/3 1/4 1/5 1/6))
+---------------

Well, in *that* case, just this [showing how CL:- allows &rest]:

   (- 1 1/3 1/4 1/5 1/6)  =>  1/20


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pierre De Pascale
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <d0a3na$4j8$1@zrha118x.zrh.siemens.ch>
> I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
> event in Germany.
> 
> To show off the elegance and power of Lisp I'm looking for very short
> "magic" snippets of Lisp code:

What about some lines implementing a powerful, object oriented, functional, 
modular, natively compiled, efficient template languages similar to PHP, ASP,
JSP, ....

(define (read-template-file filename)
  (with-input-from-file filename
    (lambda ()
      (let loop ((ch (read-char))
                 (chars '()))
        (if (eof-object? ch)
            (list `(display ,(list->string (reverse chars))))
            (if (char=? ch ··@)
                (let ((exp (read))
                      (ch2 (··········@)))
                  (if (eof-object? ch2)
                      (error "missing closing @ character at end of file")
                      (cons `(display ,(list->string (reverse chars)))
                            (cons `(display ,exp) 
                                  (loop (read-char) '())))))
                (loop (read-char) (cons ch chars))))))))

(define (··········@)
  (let ((ch (read-char)))
    (if (eof-object? ch)
        ch
        (if (char=? ch ··@)
            ch
            (··········@)))))

(define-syntax define-template-file
  (lambda (e r c)
    (let ((name (caadr e))
          (args (cdadr e))
          (filename (caddr e))
          (%define (r 'define)))
      `(,%define (,name ,@args) ,@(read-template-file filename)))))

A typical usage would be:
(define-template-file (show-index title greetings) "index.html-template")

and in the file "index.html-template":

<html>
  <head><title> @ title @ </title></head>
  <body>  @ greetings @ </body>
</html>

Now calling (show-index "Hello World") displays the standard Hello World 
greetings.

Just a bit longer than 15 lines...

I know it is Scheme code and not Common Lisp. But I am confident that 
someone translate the code to CL, making it even shorter and more 
efficient. The code isn't particularly beautiful. There is some 
inefficiency and it is not hygienic. Nothing that could be corrected 
in a CL version though.

- Pierre.
From: Marco Baringer
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <m2u0nqxm15.fsf@soma.local>
Alexander Schreiber <···@usenet.thangorodrim.de> writes:

> Hi!
>
> I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
> event in Germany.
>
> To show off the elegance and power of Lisp I'm looking for very short
> "magic" snippets of Lisp code: 
>  - does something tricky/complex/interesting in a (for Lisp)
>    simple and elegant way,
>  - possible showing of some very useful Lisp features (like bignums,
>    crypto in < 1 K of Lisp code anyone?),
>  - should fit in 15 lines by 50 characters (presentation foils),
>  - should _not_ be obfuscated - I'm trying to get people interested
>    in Lisp, not scare them away,
>  - credit will of course be given (or withheld, honouring the wishes
>    of the author of the Lisp snippet)

------------------------------------------------------------------------

Simple CLOS [this may be too simple]

(defclass user ()
  ((first-name :reader first-name :initarg :first-name
               :type string :initform "First Name")
   (last-name  :accessor last-name :initarg :last-name
               :type string)))

[which in java is equivalent to]

public class User {
  
  public User(String first_name, String last_name) {
    if (first_name != null) {
      this.first_name = first_name;
    }
    if (last_name != null) {
      this.last_name = last_name;
    }
  }

  protected String first_name = "First Name";  
  public String getFirstName() { return this.first_name; }

  protected String last_name;
  public String getLastName() { return this.last_name; }
  public void setLastName(String last_name) { this.last_name = last_name; }  
}

------------------------------------------------------------------------
  
DBC implemented in CLOS [this is 20 lines, not 15, and probably
requires more explanation than a couple of slides can give. code at
http://www.gauss.muc.de/tools/dbc/dbc.lisp]:

(in-package :dbc)

(defclass test () 
  ((slot1 :accessor slot1 :initarg :slot1 :initform 0))
  (:invariant (lambda (class) 
	 	(format t "~& >> Invariant check for class ~A~%" class)
		(numberp (slot-value class 'slot1)))))

(defgeneric test-dbc (arg1 arg2)
  (:method-combination dbc :invariant-check nil)
  (:method :precondition "first arg zero"
      ((m test) (n test))
    (format t "~& >> precondition (test test)~%")
    (not (zerop (slot1 m))))
  (:method ((m test) (n test))
    (/ (slot1 n) (slot1 m))))

(test-dbc (make-instance 'test) (make-instance 'test))
(test-dbc (make-instance 'test :slot1 2) (make-instance 'test :slot1 8))

------------------------------------------------------------------------

Cocoon's Flow can kiss my ass. :) [this an UnCommon Web action]

(defaction number-guess ((w window))
  (loop with target = (random 100)
        for num-guesses upfrom 0
        for guess = (call 'guess-first-number)
               then (call 'guess-another-number 
                          :higher (< guess target)
                          :num-guesses num-guesses)
        until (= guess target)
        finally (call 'congrats :num-guesses num-guesses)))

------------------------------------------------------------------------

It's really too bad you can't condense SLIME to a slide.

------------------------------------------------------------------------

Lots of Irritating Stupid Parentheses: [this may be counter productive
since it simply shows that lisp's shortcomings (assuming you consider
prefix syntax to be a shortcoming) can be worked aorund.

http://www-2.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/syntax/infix/infix.cl]

#I(
if x < y <= z then 
  f(x) = x^^2 + y^^2 
else 
  f(x) = x^^2 - y^^2
)

------------------------------------------------------------------------

Lisp's only data types are lists and symbols

(make-hash-table :test 'equalp)

(make-array '(4 4 4) :initial-element 0)

(make-array 10 :element-type 'character :adustablep t :fill-pointer 0)

(make-string-output-stream)

(make-echo-stream)

(translate-logical-pathname)

------------------------------------------------------------------------

Lisp is an interpreted language

CL-USER> (compile nil '(lambda () 4))
#<Anonymous Function #x6584FDE>
CL-USER> (disassemble *)
  (TWNEI NARGS 0)
  (MFLR LOC-PC)
  (BLA .SPSAVECONTEXTVSP)
  (LI ARG_Z '4)
  (BA .SPPOPJ)

------------------------------------------------------------------------

hth.

-- 
-Marco
Ring the bells that still can ring.
Forget the perfect offering.
There is a crack in everything.
That's how the light gets in.
	-Leonard Cohen
From: ivant
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <1110102252.027957.314970@g14g2000cwa.googlegroups.com>
How about implementing the so much hyped Java 5 brand new hot, etc, etc
feature "for in"?  Doh!  It's already implemented, but let's pretend it
isn't, and let's also pretend that we use Java like collections with
iterators:

(defmacro for-in ((var collection) &body body)
  (let ((iter (gensym)))
    `(let ((,iter (new-iterator ,collection)))
       (do ((,var (value ,iter) (next-value ,iter)))
           ((not ,var))
         (symbol-macrolet ((,var (value ,iter)))
           ,@body)))))

And here is some test code:

(defclass iterator ()
  ((collection :initarg :collection :accessor collection)))

(defclass list-iterator (iterator)
  ())

(defgeneric new-iterator (collection))
(defgeneric value (iter))
(defgeneric next-value (iter))

(defmethod new-iterator ((list list))
  (make-instance 'list-iterator :collection list))

(defmethod value ((iter list-iterator))
  (car (collection iter)))

(defmethod (setf value) (val (iter list-iterator))
  (setf (car (collection iter)) val))

(defmethod next-value ((iter list-iterator))
  (with-slots (collection) iter
    (pop collection)
    collection))

(defvar *aa* (list 1 2 3))

(for-in (v *aa*) (print v) (incf v))

*aa* => (2 3 4)
From: Eugene Tyurin
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <iOmdnbk5k4KyY7HfRVn-jg@comcast.com>
This code idea is not mine - Daniel Barlow generously helped me on #lisp 
about a year ago.

The purpose is to:

1) find all nearest neighbors of a cell in an array of arbitrary dimensions
2) perform an operation on them (in this example - simple summation)

I think this would make a good example, because it has:

1) regression
2) loop
3) mapcar
4) funcall and apply


(defun nearest (this upper-limits)
   "Returns a list of all the nearest neighbors of this cell including 
this (in the car position)"
   (if this
       (let ((head (car this))
	    (head-limit (car upper-limits))
	    (tails (funcall #'nearest (cdr this) (cdr upper-limits))))
	(loop for tail in tails
	   collect (cons head tail)
	   if (< head head-limit) collect (cons (1+ head) tail)
	   if (> head 0) collect (cons (1- head) tail)))
     (list nil)))

(defun sum-nearest (this arr)
   (loop for coordinate in
      ;; cdr removes this from summation
        (cdr (nearest this (mapcar #'1- (array-dimensions arr))))
        sum (apply #'aref arr coordinate)))

;;;; Test:

(setq *a* (make-array '(3 3 3)
         :initial-contents '(((1 0 0) (2 0 0) (0 0 0))
			    ((0 0 0) (0 0 0) (0 0 200))
			    ((0 0 0) (0 0 0) (0 0 1000)))))

(sum-nearest '(0 0 0) *a*)
;;; 2

(sum-nearest '(1 1 1) *a*)
;;; 1203


-- 
"Most people use statistics the way a drunkard uses a lamp post,
more for support than illumination."  	       	    --Mark Twain

Anti-spam: remove slashes (/)
From: Steven E. Harris
Subject: Re: Wanted: Magic Lisp snippets
Date: 
Message-ID: <jk4br9t2727.fsf@W003275.na.alarismed.com>
Eugene Tyurin <·····@tyurin/.com> writes:

> 1) find all nearest neighbors of a cell in an array of arbitrary
>    dimensions
> 2) perform an operation on them (in this example - simple summation)

I was interested in the example, so I teased it apart then put it back
together.


(defun combine (lists)
  "Given a list of lists, returns the combinations drawing
 one item from each list.

 ((a b)) => ((a) (b))
 ((a b) (c d)) => ((a c) (a d) (b c) (b d))"
  (when lists
    (flet ((join (head tails)
             (mapcar #'(lambda (tail)
                         (cons head tail))
                     tails)))
      (let ((tails (combine (cdr lists))))
        (if tails
          (mapcan #'(lambda (head)
                      (join head tails))
                  (car lists))
          (mapcar #'list (car lists)))))))


(defun nearest-slice (start upper-bound)
  (when (< start upper-bound)
    (let ((nearest nil))
      (when (plusp start)
        (push (1- start) nearest))
      (when (< start (1- upper-bound))
        (push (1+ start) nearest))
      (cons start nearest))))


(defun nearest-slices (starts upper-bounds)
  (mapcar #'(lambda (start upper-bound)
              (nearest-slice start upper-bound))
          starts upper-bounds))


(defun nearest (starts upper-bounds)
  (combine (nearest-slices starts upper-bounds)))


(defun sum-nearest (point array)
  (loop for coordinate in
    (rest (nearest point (array-dimensions array)))
    sum (apply #'aref array coordinate)))

-- 
Steven E. Harris
From: Alexander Schreiber
Subject: Lisp talk wrapup (was: Wanted: Magic Lisp snippets)
Date: 
Message-ID: <slrnd2pv81.tio.als@mordor.angband.thangorodrim.de>
Alexander Schreiber <···@usenet.thangorodrim.de> wrote:
> 
> I'm currently preparing propaganda^Wa talk on Lisp for a large Linux
> event in Germany.

The event took place last weekend[0]. There about 80 talks total (5
parallel tracks), 12 workshops, quite a lot of booths (companies and
free projects) over 2 days. The attendance numbers seem to point to 
about 2500 visitors (not official numbers).

My Lisp talk took place in one of the smaller rooms which was fine with
me since I (and the team organizing the event) just expected a rather
moderate interest in the talk, even though I couldn't resist to use a
slightly provocative title: "Common Lisp - a lot more than just silly
parentheses"[1]. Turned out I was _seriously_ mistaken. The room was
_packed_.

Judging from both the attentiveness of the audience and the questions
asked during the Q&A part of the talk, they were seriously interested
and the talk was a full success.
According to the feedback both directly after the talk and during the
remainder of the event, I managed to further propagate the Lisp bug and
get people interested enough so they'll give Common Lisp a try. ;-)

Especially while answering questions I found myself emphasising the
following points:
 - Lisp is _not_ slow, it is not an interpreter only language, we have
   damn good compilers for it (fighting a seemingly very common
   misconception),
 - Lisp as the programmable programming language, the availability of
   the full language during all 3 phases (read, compile, run), and
   the enormous power & flexibility stemming from this,
 - enforced cleanup via unwind-protect combined with macros to
   make handling of expensive ressources simple and easy,
 - the power of an interactive system: hot-replacing code via REPL
   access while the application is running,

Those interested in learning Common Lisp I pointed to 
 - the web sites for CLISP/CMUCL/SBCL (and the commercial Lisps too),
 - http://www.cliki.net/
 - Lisp books, most prominently
   - Peter Seibels excellent "Practical Common Lisp"
   - David S. Touretzky's Gentle Introduction to Symbolic Computation

I wish to thank the group not only for answering my request for 
propaganda ammunition for this talk, but also for the amount of
knowledge and interesting information about Lisp I was able to soak up
here just by (mostly) lurking.

For those interested, the (german!) presentation for the talk can be 
found here:

http://www.thangorodrim.de/papers/CLT2005/commonlisp-clt2005.pdf

Regards,
       Alex.
[0] http://chemnitzer.linux-tage.de/2005
[1] Translated title, the talk was held in german
-- 
"Opportunity is missed by most people because it is dressed in overalls and
 looks like work."                                      -- Thomas A. Edison
From: Ulrich Hobelmann
Subject: Re: Lisp talk wrapup
Date: 
Message-ID: <394s90F5vvb2nU1@individual.net>
Alexander Schreiber wrote:
> For those interested, the (german!) presentation for the talk can be 
> found here:
> 
> http://www.thangorodrim.de/papers/CLT2005/commonlisp-clt2005.pdf

Sieht klasse aus!
Werd ich als Referenz behalten, falls mich jemand nach Lisp fragt...
From: Julian Stecklina
Subject: Re: Lisp talk wrapup (was: Wanted: Magic Lisp snippets)
Date: 
Message-ID: <pan.2005.03.08.13.19.14.650960@web.de>
On Tue, 08 Mar 2005 02:16:50 +0100, Alexander Schreiber wrote:

> My Lisp talk took place in one of the smaller rooms which was fine with
> me since I (and the team organizing the event) just expected a rather
> moderate interest in the talk, even though I couldn't resist to use a
> slightly provocative title: "Common Lisp - a lot more than just silly
> parentheses"[1]. Turned out I was _seriously_ mistaken. The room was
> _packed_.

You managed to get a member of the BSD-Crew Dresden seriously interested
in Common Lisp. :) I hope he jumps on the train.

Regards,
-- 
Julian Stecklina

-- Common Lisp can do what C, C++, Java, PASCAL, PHP, Perl, (you --
-- name it) can do. Here's how:                                  --
--                                                               --
-- http://www.amazon.com/exec/obidos/ASIN/1590592395             --