As some of you may know I am developing a new variant of Lisp. I am
currently figuring out iteration constructs. In particular, I am
experimenting with a method of iteration that iterates in parallel over
several lazy sequences, stopping when any of them terminates. I have
found this useful to replace several uses of the LOOP macro in my code.
However, I know the LOOP macro is too powerful for any one man to
comprehend. Hence, I request that you post the most impressive,
succinct, and elegant examples of the LOOP macro in action, so that I
can use them as goalposts for my language's iteration constructs.
Here's one of mine (I invented this one myself):
; Prints the first 16 rows of Pascal's triangle
; not tested, I'm writing it from memory right here!
(loop repeat 16
for list = '(1) then (mapcar #'+ (cons 0 list) (append list
'(0)))
do (format t "~{~6D~^,~}~%" list))
That's definitely one of the most beautiful pieces of code I've ever
written. I wrote it for a programming language comparison contest, and
blew every other language out of the water, except Mathematica, of
course. ;-)
Tron3k
These requests have been made in the past for some other projects.
Googling in the archives of comp.lang.lisp should give you some ideas.
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
>That's definitely one of the most beautiful pieces of code I've ever
>written.
Warning: slippery slope.
mkb.
Thanks. I did, in fact, google for cool Lisp snippets before posting
this and found some interesting ones such as the one that prints the
Mandelbrot set using ASCII characters. I just thought that it would be
fun to have a thread for everyone to share the cool snippets they have
tucked away ... I've done this on other forums and people usually enjoy
it.
???
> currently figuring out iteration constructs. In particular, I am
> experimenting with a method of iteration that iterates in parallel over
> several lazy sequences, stopping when any of them terminates. I have
> found this useful to replace several uses of the LOOP macro in my code.
I also have a way of replacing uses of LOOP: MACROEXPAND.
Paolo
--
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
Recommended Common Lisp libraries/tools:
- ASDF/ASDF-INSTALL: system building/installation
- CL-PPCRE: regular expressions
- UFFI: Foreign Function Interface
>Greetings fellow Common Lispers.
>
>As some of you may know I am developing a new variant of Lisp. I am
>currently figuring out iteration constructs. In particular, I am
>experimenting with a method of iteration that iterates in parallel over
>several lazy sequences, stopping when any of them terminates. I have
>found this useful to replace several uses of the LOOP macro in my code.
>However, I know the LOOP macro is too powerful for any one man to
>comprehend. Hence, I request that you post the most impressive,
>succinct, and elegant examples of the LOOP macro in action, so that I
>can use them as goalposts for my language's iteration constructs.
Here is one neat loop I wrote. Not very efficient, though...
;Continous fractions: 47/350 -> (0 (1 3) (4 2 8 5 7 1))
(defun contdivstuff (a b &key (base 10))
(multiple-value-bind (whole r) (floor (/ a b))
(loop for tr = (* base r) then (* base (- tr (floor tr)))
for tail = (member tr past)
until tail
collecting tr into past
finally (return (list whole (mapcar #'floor (ldiff past tail))
(mapcar #'floor tail))))))
--
|a\o/r|,-------------.,---------- Timofei Shatrov aka Grue ------------.
| m"a ||FC AMKAR PERM|| mail: grue at mail.ru http://grue3.tripod.com |
| k || PWNZ J00 || Kingdom of Loathing: Grue3 lvl 18 Seal Clubber |
`-----'`-------------'`-------------------------------------------[4*72]
Its expansion is hideous, but I don't think that's what you meant.
You're saying that it's stupid to hate a tool if it works. You're
fitting me into your pre-existing archetype of the mindless anti-LOOP
bigot. Well, there are reasons I'm not going to translate all the code
for LOOP into my new Lisp. First of all, it would be hard to get right.
Second of all, I'm trying to make this language simple to implement,
since as PG says, source code is often the best spec. So I'm trying to
find a good combination of simple but powerful constructs that are
equivalent in expressivity to LOOP.
I had your more specific request in mind, wrt examples using LOOP. There
were a number of examples posted in conjunction with LinJ.
Fantastic! I actually found it:
This is like a gold mine! Thanks!
Tron3k
> Paolo Amoroso wrote:
[...]
>> I also have a way of replacing uses of LOOP: MACROEXPAND.
>
> Its expansion is hideous, but I don't think that's what you meant.
>
> You're saying that it's stupid to hate a tool if it works. You're
> fitting me into your pre-existing archetype of the mindless anti-LOOP
> bigot. Well, there are reasons I'm not going to translate all the code
No.
> Here's one of mine (I invented this one myself):
>
> ; Prints the first 16 rows of Pascal's triangle
> ; not tested, I'm writing it from memory right here!
> (loop repeat 16
> for list = '(1) then (mapcar #'+ (cons 0 list) (append list
> '(0)))
> do (format t "~{~6D~^,~}~%" list))
>
> That's definitely one of the most beautiful pieces of code I've ever
> written. I wrote it for a programming language comparison contest,
> and blew every other language out of the water, except Mathematica,
> of course. ;-)
Hmmm. I'm not sure any code that repeatedly APPENDs to the end of a
growing list can be all that elegant. If you're into this sort of
thin, both the versions below, while slightly longer in terms of
number of characters than yours, are, I'd argue, algorithmically more
elegant:
(loop repeat 16 for list = '(1)
then (maplist #'(lambda (cons) (+ (car cons) (or (cadr cons) 0))) (cons 0 list))
do (format t "~{~6D~^,~}~%" list))
(loop repeat 16 for list = '(1)
then (maplist #'(lambda (cons) (apply #'+ (ldiff cons (cddr cons)))) (cons 0 list))
do (format t "~{~6D~^,~}~%" list))
-Peter
--
Peter Seibel * pe...@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp * http://www.gigamonkeys.com/book/
> Hmmm. I'm not sure any code that repeatedly APPENDs to the end of a
> growing list can be all that elegant. If you're into this sort of
> thin, both the versions below, while slightly longer in terms of
> number of characters than yours, are, I'd argue, algorithmically more
> elegant:
>
> (loop repeat 16 for list = '(1)
> then (maplist #'(lambda (cons) (+ (car cons) (or (cadr cons) 0))) (cons 0 list))
> do (format t "~{~6D~^,~}~%" list))
>
> (loop repeat 16 for list = '(1)
> then (maplist #'(lambda (cons) (apply #'+ (ldiff cons (cddr cons)))) (cons 0 list))
> do (format t "~{~6D~^,~}~%" list))
Maybe even
(loop repeat 16
for list = '(1)
then (cons 1 (loop for (a b) on list
collecting (+ a (or b 0))))
do (format t "~&~{~6D~^,~}~%" list))
Yeah, I know. The contest was to create the shortest code though. :-)
Oh, so you were just wasting everyone's time with a thoroughly useless
comment. Ok then.
True. Yet many CL programmers find it valuable that CL implementors spend
this effort. I wonder if the programming community for your new language
will be as forgiving of you not bothering to put forth the effort.
> Second of all, I'm trying to make this language simple to implement
More and more, it sure sounds like you would be happier in the Scheme
community. They share much of your aesthetic sense. For example: Lisp-1,
small language spec, simple to implement, etc.
You sure don't sound like someone trying to improve Common Lisp. You sound
like a Scheme guy who is trying to convert the "enemy".
> since as PG says, source code is often the best spec.
Leaving aside whether Paul Graham is the Prophet of Lisp, such that his
every word must become our law ... how is this even related? "Source code
being the best spec" means that a sufficiently powerful language would allow
you to express most of what is usually in documentation, directly in the
language itself.
How does that have anything to do with whether the language is easy to
implement or not?
-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org/ d...@geddis.org
Writing about music is like dancing about architecture.
>> > Paolo Amoroso wrote:
>> [...]
>> >> I also have a way of replacing uses of LOOP: MACROEXPAND.
[...]
> Oh, so you were just wasting everyone's time with a thoroughly useless
> comment. Ok then.
It was a joke. As for wasting everyone's time, everyone can decide
for himself/herself.
Guile Scheme:
(use-modules (ice-9 format)) ; CL-style format
(let recur ((lst '(1))) (and (< (length lst) 17)
(format #t "~{~6D~^,~}~%" lst)
(recur (map + (cons 0 lst) (append lst '(0))))))
Common Lisp:
(defmacro llet (name vars &body body)
(let ((start-tag (gentemp)))
`(prog ,vars
,start-tag
(macrolet
((,name (&rest args)
(append '(progn)
(loop for arg in args and var in ',vars
collect `(setq ,(if (consp var)
(first var)
var)
,arg))
(list (list 'go ',start-tag)))))
(locally ,@body)))))
(llet recur ((list '(1)))
(when (< (length list) 17)
(format t "~{~6D~^,~}~%" list)
(recur (mapcar '+ (cons 0 list) (append list '(0))))))
llet looks exactly like Scheme's named let. Cool, that's what I miss
in CL. Thanks.
- Yuri
Actually, it should expand into a LABELS to approach Scheme's
semantics.
(defmacro nlet (name vars &body body)
`(labels ((,name ,(mapcar 'first vars) ,@body))
(,name ,@(mapcar 'second vars))))
It is an old macro. Older than the original thread the SLDJ troll
responded to :)
cheers
--
MA
The idea was that it provides kind of a LOOP without need to support
TCO,
Thus no LABELS.
Right, this is what I like the most.
- Yuri
Well, this day and age, I assume a good CL implementation *will*
provide TCO. Besides, while it is true that Scheme named let is used
mostly for loops, you could use it in non-TCO settings.
(let fact ((x 4))
(if (= x 0)
1
(* x (fact (- x 1)))))
The above is Scheme.
Cheers
--
Marco
Does ABCL on the JVM??? Interpreted CLISP?
Also: it is possible that your code will be TCO, but not necessarily.
TCO in CL is tricky. It requires that the compiler runs in the right
mode, a compiler is used (does any CL interpreter do TCO) and a few
restrictions are not violated (say, dynamic bindings).
CLISP does optimize recursive tail calls (but no other tail calls).
--
Fine. I'll grant you all of that. Yet, Scheme "named let" implies
LABELS semantics.
Cheers
--
Marco
The Interpreter, the Compiler or both?
> --
> Greetings fellow Common Lispers.
>
> As some of you may know I am developing a new variant of Lisp. I am
> currently figuring out iteration constructs. In particular, I am
> experimenting with a method of iteration that iterates in parallel over
> several lazy sequences, stopping when any of them terminates. I have
> found this useful to replace several uses of the LOOP macro in my code.
> However, I know the LOOP macro is too powerful for any one man to
> comprehend. Hence, I request that you post the most impressive,
> succinct, and elegant examples of the LOOP macro in action, so that I
> can use them as goalposts for my language's iteration constructs.
>
> Here's one of mine (I invented this one myself):
>
> ; Prints the first 16 rows of Pascal's triangle
> ; not tested, I'm writing it from memory right here!
> (loop repeat 16
> for list = '(1) then (mapcar #'+ (cons 0 list) (append list
> '(0)))
> do (format t "~{~6D~^,~}~%" list))
>
> That's definitely one of the most beautiful pieces of code I've ever
> written. I wrote it for a programming language comparison contest, and
> blew every other language out of the water, except Mathematica, of
> course. ;-)
Really? It didn't blow MatzLisp out of the water.
The first 10 rows ouput by your code:
1
1, 1
1, 2, 1
1, 3, 3, 1
1, 4, 6, 4, 1
1, 5, 10, 10, 5, 1
1, 6, 15, 20, 15, 6, 1
1, 7, 21, 35, 35, 21, 7, 1
1, 8, 28, 56, 70, 56, 28, 8, 1
1, 9, 36, 84, 126, 126, 84, 36, 9, 1
The Ruby code and output:
r = [1]
13.times{puts r.map{|n| n.to_s.center 4}.join.center 79
r = ([0]+r).zip(r << 0).map{|a,b| a+b}}
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1
Much prettier.
Common Lisp:
CL-USER 221 > (llet recur ((list '(1)))
(when (< (length list) 12)
(format t "~60:@<~{~5D~^~}~>~%" list)
(recur (mapcar '+ (cons 0 list) (append list
'(0))))))
Ah, you are right. The compiler does, but not the interpreter. I had a
misconception about how CLISP worked.
--
BTW, what does the frist 'l' in llet stand for?
- Yuri
Another case where many CL implementations fail is CLOS methods: Since
many implementations use an internal special variable to bind the list
of next methods that call-next-method can invoke, it's likely that TCO
is not possible in cases that you would actually expect it to work. (To
the best of my knowledge, only SBCL gets this one right.)
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
I had thought about the 'l' for about a minute.
It is the loop-let... ;-)