From: ·············@craigslist.org
Subject: A style question
Date: 
Message-ID: <TF4Fh.35083$p9.32292@bignews7.bellsouth.net>
A friend passed on an article regarding the difficulty job candidates 
had in producing even simple programs (simple as in should take a minute 
or less). One example was a program to print the numbers 1 to 100 except 
that "Fizz" should be substituted for numbers divisible by 3, "Buzz" 
should be substituted for numbers divisible by 5, and "FizzBuzz" should 
be substituted for numbers divisible by both 3 and 5.

So, having received my "ANSI Common Lisp" and "Practical Common Lisp" 
books two days ago (still waiting for "Structure and Interpretation of 
Computer Programs") and having a *couple hours* of Lisp under my belt, I 
cranked out a Lisp version. It seems a bit clunky, so I thought I'd see 
if anyone had suggestions for improvements.

Here's a Ruby version for comparison:

def fizz_buzz n
   1.upto(n) do |i|
     print "Fizz" if fizz = (i % 3) == 0
     print "Buzz" if buzz = (i % 5) == 0
     puts fizz || buzz ? "" : i
   end
end

fizz_buzz 100

and the Lisp version

(defun fizz-buzz (n)
   (do ((i 1 (+ i 1)))
     ((> i n))
     (let
       ((fizz (= 0 (mod i 3)))
        (buzz (= 0 (mod i 5))))
       (if fizz (format t "Fizz"))
       (if buzz (format t "Buzz"))
       (format t "~A~%"
               (if (or fizz buzz) "" i)))))

(fizz-buzz 100)

By the way, it seems more folks recommend starting with "Practical 
Common Lisp" instead of "ANSI Common Lisp" (when both are mentioned), 
but being a newbie myself, it seems that the latter is a better 
introduction to the language.

Brian

From: Paul Wallich
Subject: Re: A style question
Date: 
Message-ID: <es2ov7$er8$1@reader2.panix.com>
·············@craigslist.org wrote:
> A friend passed on an article regarding the difficulty job candidates 
> had in producing even simple programs (simple as in should take a minute 
> or less). One example was a program to print the numbers 1 to 100 except 
> that "Fizz" should be substituted for numbers divisible by 3, "Buzz" 
> should be substituted for numbers divisible by 5, and "FizzBuzz" should 
> be substituted for numbers divisible by both 3 and 5.
> 
> So, having received my "ANSI Common Lisp" and "Practical Common Lisp" 
> books two days ago (still waiting for "Structure and Interpretation of 
> Computer Programs") and having a *couple hours* of Lisp under my belt, I 
> cranked out a Lisp version. It seems a bit clunky, so I thought I'd see 
> if anyone had suggestions for improvements.
> 
> Here's a Ruby version for comparison:
> 
> def fizz_buzz n
>   1.upto(n) do |i|
>     print "Fizz" if fizz = (i % 3) == 0
>     print "Buzz" if buzz = (i % 5) == 0
>     puts fizz || buzz ? "" : i
>   end
> end
> 
> fizz_buzz 100
> 
> and the Lisp version
> 
> (defun fizz-buzz (n)
>   (do ((i 1 (+ i 1)))
>     ((> i n))
>     (let
>       ((fizz (= 0 (mod i 3)))
>        (buzz (= 0 (mod i 5))))
>       (if fizz (format t "Fizz"))
>       (if buzz (format t "Buzz"))
>       (format t "~A~%"
>               (if (or fizz buzz) "" i)))))

In both cases, what the local variables add in supposed elegance seems 
to me lost by the clunkiness of setting them in the first place (which 
you haven't done correctly).

I'd probably brute-force the problem with a simple cond with a nested 
conditions, along the lines of
(cond ((zerop (mod i 5))
        (cond ((zerop (mod i 3)) (print "FizzBuzz"))
              (t (print "Buzz"))))
       ((zerop (mod i 3))
        (print "Fizz"))
       (t (print i)))

Someone else can do the loop version, the version with a macro that 
generates any possible fizz-buzz function of two small integers, the ver
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <ep6Fh.416$8j.398@newsfe12.lga>
Paul Wallich wrote:
> ·············@craigslist.org wrote:
> 
>> A friend passed on an article regarding the difficulty job candidates 
>> had in producing even simple programs (simple as in should take a 
>> minute or less). One example was a program to print the numbers 1 to 
>> 100 except that "Fizz" should be substituted for numbers divisible by 
>> 3, "Buzz" should be substituted for numbers divisible by 5, and 
>> "FizzBuzz" should be substituted for numbers divisible by both 3 and 5.
>>
>> So, having received my "ANSI Common Lisp" and "Practical Common Lisp" 
>> books two days ago (still waiting for "Structure and Interpretation of 
>> Computer Programs") and having a *couple hours* of Lisp under my belt, 
>> I cranked out a Lisp version. It seems a bit clunky, so I thought I'd 
>> see if anyone had suggestions for improvements.
>>
>> Here's a Ruby version for comparison:
>>
>> def fizz_buzz n
>>   1.upto(n) do |i|
>>     print "Fizz" if fizz = (i % 3) == 0
>>     print "Buzz" if buzz = (i % 5) == 0
>>     puts fizz || buzz ? "" : i
>>   end
>> end
>>
>> fizz_buzz 100
>>
>> and the Lisp version
>>
>> (defun fizz-buzz (n)
>>   (do ((i 1 (+ i 1)))
>>     ((> i n))
>>     (let
>>       ((fizz (= 0 (mod i 3)))
>>        (buzz (= 0 (mod i 5))))
>>       (if fizz (format t "Fizz"))
>>       (if buzz (format t "Buzz"))
>>       (format t "~A~%"
>>               (if (or fizz buzz) "" i)))))
> 
> 
> In both cases, what the local variables add in supposed elegance seems 
> to me lost by the clunkiness of setting them in the first place (which 
> you haven't done correctly).
> 
> I'd probably brute-force the problem with a simple cond with a nested 
> conditions, along the lines of
> (cond ((zerop (mod i 5))
>        (cond ((zerop (mod i 3)) (print "FizzBuzz"))
>              (t (print "Buzz"))))
>       ((zerop (mod i 3))
>        (print "Fizz"))
>       (t (print i)))

I would object to using cond to implement if, and the redundant code 
testing for (mod i 3) and associating it with Fizz.

Otherwise, I am bothered by the spec. Is the FizzBuzz on 15 tied to it 
factoring to 3 and 5 and those substitutions, or is that coincidental? 
ie, Could an RFE come thru for 15 to translate to Bang? Also, is this 
list expected to expand? If so, will the test always be even divisibility?

This is how I get thrown out of most tech interviews.

kt

-- 
"I don't like being tested."
    -- Tangina, Poltergeist
From: ·············@craigslist.org
Subject: Re: A style question
Date: 
Message-ID: <QG6Fh.42507$19.31966@bignews3.bellsouth.net>
Ken Tilton wrote:
> Paul Wallich wrote:
>> ·············@craigslist.org wrote:
>>
>>> A friend passed on an article regarding the difficulty job candidates 
>>> had in producing even simple programs (simple as in should take a 
>>> minute or less). One example was a program to print the numbers 1 to 
>>> 100 except that "Fizz" should be substituted for numbers divisible by 
>>> 3, "Buzz" should be substituted for numbers divisible by 5, and 
>>> "FizzBuzz" should be substituted for numbers divisible by both 3 and 5.
>>>
>> I'd probably brute-force the problem with a simple cond with a nested 
>> conditions, along the lines of
>> (cond ((zerop (mod i 5))
>>        (cond ((zerop (mod i 3)) (print "FizzBuzz"))
>>              (t (print "Buzz"))))
>>       ((zerop (mod i 3))
>>        (print "Fizz"))
>>       (t (print i)))
> 
> I would object to using cond to implement if, and the redundant code 
> testing for (mod i 3) and associating it with Fizz.

I agree. I expect mod is fast, but I don't like to repeat myself.

> Otherwise, I am bothered by the spec. Is the FizzBuzz on 15 tied to it 
> factoring to 3 and 5 and those substitutions, or is that coincidental? 
> ie, Could an RFE come thru for 15 to translate to Bang? Also, is this 
> list expected to expand? If so, will the test always be even divisibility?

Yes, the FizzBuzz on 15 is because the spec said to print FizzBuzz 
instead of i for any i that is divisible by both 3 and 5. Regarding 
enhancements, I'll be including one in a reply to Paul in a few minutes.

> This is how I get thrown out of most tech interviews.
> 
> kt
> 
From: Vassil Nikolov
Subject: Re: A style question
Date: 
Message-ID: <yy8v3b4rlzan.fsf@eskimo.com>
On Tue, 27 Feb 2007 22:30:06 -0500, ·············@craigslist.org said:

| Ken Tilton wrote:
| ...
|| I would object to using cond to implement if, and the redundant code 
|| testing for (mod i 3) and associating it with Fizz.

| I agree. I expect mod is fast, but I don't like to repeat myself.

  But this isn't about the speed of MOD (after all, we can justifiably
  expect the compiler to arrange for the respective call to be made
  no more than once), but---to reuse the expression---about getting
  thrown out of the interview because of introducing the DIVISIBLE-BY-3,
  DIVISIBLE-BY-5, and ANY-NUMBER classes, and doing it with method
  combination to address these concerns:

|| Otherwise, I am bothered by the spec. Is the FizzBuzz on 15 tied to it 
|| factoring to 3 and 5 and those substitutions, or is that coincidental? 
|| ie, Could an RFE come thru for 15 to translate to Bang? Also, is this 
|| list expected to expand? If so, will the test always be even divisibility?

|| This is how I get thrown out of most tech interviews.

  ---Vassil.

-- 
mind mate, n.
  One of two persons mentally compatible with each other (cf. soul mate).
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <nT6Fh.796$8j.213@newsfe12.lga>
·············@craigslist.org wrote:
> Ken Tilton wrote:
> 
>> Paul Wallich wrote:
>>
>>> ·············@craigslist.org wrote:
>>>
>>>> A friend passed on an article regarding the difficulty job 
>>>> candidates had in producing even simple programs (simple as in 
>>>> should take a minute or less). One example was a program to print 
>>>> the numbers 1 to 100 except that "Fizz" should be substituted for 
>>>> numbers divisible by 3, "Buzz" should be substituted for numbers 
>>>> divisible by 5, and "FizzBuzz" should be substituted for numbers 
>>>> divisible by both 3 and 5.
>>>>
>>> I'd probably brute-force the problem with a simple cond with a nested 
>>> conditions, along the lines of
>>> (cond ((zerop (mod i 5))
>>>        (cond ((zerop (mod i 3)) (print "FizzBuzz"))
>>>              (t (print "Buzz"))))
>>>       ((zerop (mod i 3))
>>>        (print "Fizz"))
>>>       (t (print i)))
>>
>>
>> I would object to using cond to implement if, and the redundant code 
>> testing for (mod i 3) and associating it with Fizz.
> 
> 
> I agree. I expect mod is fast, but I don't like to repeat myself.
> 
>> Otherwise, I am bothered by the spec. Is the FizzBuzz on 15 tied to it 
>> factoring to 3 and 5 and those substitutions, or is that coincidental? 
>> ie, Could an RFE come thru for 15 to translate to Bang? Also, is this 
>> list expected to expand? If so, will the test always be even 
>> divisibility?
> 
> 
> Yes, the FizzBuzz on 15 is because the spec said to print FizzBuzz 
> instead of i for any i that is divisible by both 3 and 5. Regarding 
> enhancements, 

Sorry, I threw in that translation to 15 myself. But the question still 
stands: could an RFE come along saying "if divisible by 3 and 5 print 
BANG"? Or was the spec trying (and failing to say): the translations are 
3 this and five that, where multiple matches occur print all. Then my 
next question is: 45 is FizzFizzBuzz?

I have had managers lunge acroos the table to get at me.

kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: ·············@craigslist.org
Subject: Re: A style question
Date: 
Message-ID: <Q77Fh.42519$19.2456@bignews3.bellsouth.net>
Ken Tilton wrote:
> ·············@craigslist.org wrote:
>> Ken Tilton wrote:
>>> Paul Wallich wrote:
>>>> ·············@craigslist.org wrote:
>>>>> A friend passed on an article regarding the difficulty job 
>>>>> candidates had in producing even simple programs (simple as in 
>>>>> should take a minute or less). One example was a program to print 
>>>>> the numbers 1 to 100 except that "Fizz" should be substituted for 
>>>>> numbers divisible by 3, "Buzz" should be substituted for numbers 
>>>>> divisible by 5, and "FizzBuzz" should be substituted for numbers 
>>>>> divisible by both 3 and 5.
>>>>>
>>> Otherwise, I am bothered by the spec. Is the FizzBuzz on 15 tied to 
>>> it factoring to 3 and 5 and those substitutions, or is that 
>>> coincidental? ie, Could an RFE come thru for 15 to translate to Bang? 
>>> Also, is this list expected to expand? If so, will the test always be 
>>> even divisibility?
>>
>> Yes, the FizzBuzz on 15 is because the spec said to print FizzBuzz 
>> instead of i for any i that is divisible by both 3 and 5. Regarding 
>> enhancements, 
> 
> Sorry, I threw in that translation to 15 myself. But the question still 
> stands: could an RFE come along saying "if divisible by 3 and 5 print 
> BANG"? Or was the spec trying (and failing to say): the translations are 
> 3 this and five that, where multiple matches occur print all. Then my 
> next question is: 45 is FizzFizzBuzz?

Gotcha. Well, I just posted a reply to Paul with a generalization of 
passing in a 2nd list parameter containing pairs of (integer, string) 
with the intent of concatenating the strings for all integers that 
evenly divide i.

So for the list '((2 "a")(3 "b")(5 "c")) we'd have
1
a
b
ac
5
ab
7
ac
b
a
11
abc

So, 45 would just be "FizzBuzz"

> 
> I have had managers lunge acroos the table to get at me.
> 
> kt
> 
From: ·············@craigslist.org
Subject: Re: A style question
Date: 
Message-ID: <Yw7Fh.42526$19.13833@bignews3.bellsouth.net>
·············@craigslist.org wrote:
> Ken Tilton wrote:
> Gotcha. Well, I just posted a reply to Paul with a generalization of 
> passing in a 2nd list parameter containing pairs of (integer, string) 
> with the intent of concatenating the strings for all integers that 
> evenly divide i.
> 

Oops, I guess it's getting late. The output doesn't match the list - I 
mistakenly used the following instead when I ran the program:
(fizz-buzz 12 '((2 "a") (3 "b") (4 "c")))
that's why 4 is ac and 12 is abc ...

> So for the list '((2 "a")(3 "b")(5 "c")) we'd have
> 1
> a
> b
> ac
> 5
> ab
> 7
> ac
> b
> a
> 11
> abc
> 
> So, 45 would just be "FizzBuzz"
> 
>>
>> I have had managers lunge acroos the table to get at me.
>>
>> kt
>>
From: John Thingstad
Subject: Re: A style question
Date: 
Message-ID: <op.togh14uopqzri1@pandora.upc.no>
On Wed, 28 Feb 2007 04:30:06 +0100, <·············@craigslist.org> wrote:

> Ken Tilton wrote:
>> Paul Wallich wrote:
>>> ·············@craigslist.org wrote:
>>>
>>>> A friend passed on an article regarding the difficulty job candidates  
>>>> had in producing even simple programs (simple as in should take a  
>>>> minute or less). One example was a program to print the numbers 1 to  
>>>> 100 except that "Fizz" should be substituted for numbers divisible by  
>>>> 3, "Buzz" should be substituted for numbers divisible by 5, and  
>>>> "FizzBuzz" should be substituted for numbers divisible by both 3 and  
>>>> 5.
>>>>
>>> I'd probably brute-force the problem with a simple cond with a nested  
>>> conditions, along the lines of
>>> (cond ((zerop (mod i 5))
>>>        (cond ((zerop (mod i 3)) (print "FizzBuzz"))
>>>              (t (print "Buzz"))))
>>>       ((zerop (mod i 3))
>>>        (print "Fizz"))
>>>       (t (print i)))
>>  I would object to using cond to implement if, and the redundant code  
>> testing for (mod i 3) and associating it with Fizz.
>
> I agree. I expect mod is fast, but I don't like to repeat myself.
>

rem is fast.. mod conses on fractions on the heap

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Dan Bensen
Subject: Re: A style question
Date: 
Message-ID: <es30u9$c28$1@wildfire.prairienet.org>
Paul Wallich wrote:
> In both cases, what the local variables add in supposed elegance seems 
> to me lost by the clunkiness of setting them in the first place 
> I'd probably brute-force the problem with a simple cond

You can eliminate variables and repetition by making the string
do double duty:

   (let ((str (concatenate 'string
			  ""
			  (if (zerop (mod n 3)) "fizz" "")
			  (if (zerop (mod n 5)) "buzz" ""))))
     (write-line
      (if (string= str "") (format nil "~D" n) str)))

-- 
Dan
www.prairienet.org/~dsb
From: ·············@craigslist.org
Subject: Re: A style question
Date: 
Message-ID: <rV6Fh.42514$19.9170@bignews3.bellsouth.net>
Paul Wallich wrote:
> ·············@craigslist.org wrote:
>> (defun fizz-buzz (n)
>>   (do ((i 1 (+ i 1)))
>>     ((> i n))
>>     (let
>>       ((fizz (= 0 (mod i 3)))
>>        (buzz (= 0 (mod i 5))))
>>       (if fizz (format t "Fizz"))
>>       (if buzz (format t "Buzz"))
>>       (format t "~A~%"
>>               (if (or fizz buzz) "" i)))))
> 
> In both cases, what the local variables add in supposed elegance seems 
> to me lost by the clunkiness of setting them in the first place (which 
> you haven't done correctly).

Can you elaborate about how I incorrectly set the local variables? The 
program functions correctly, so maybe you're referring to using zerop 
instead?

> I'd probably brute-force the problem with a simple cond with a nested 
> conditions, along the lines of
> (cond ((zerop (mod i 5))
>        (cond ((zerop (mod i 3)) (print "FizzBuzz"))
>              (t (print "Buzz"))))
>       ((zerop (mod i 3))
>        (print "Fizz"))
>       (t (print i)))
> 
> Someone else can do the loop version, the version with a macro that 
> generates any possible fizz-buzz function of two small integers, the ver

I haven't made it to the chapter on macros yet, but would it be better 
Lisp style to write a macro to be able to handle any two integers, or 
just add 2 parameters e.g. (defun fizz-buzz (n a b) ... ), or maybe it 
would be more Lisp-like to pass a list as the 2nd param (defun fizz-buzz 
(n lst) ... ) where each element in the list would contain an integer 
and the replacement string - something like:

(defun fizz-buzz (n lst)
   (do ((i 1 (+ i 1)))
     ((> i n))
     (let
       ((fizzed nil))
       (dolist (obj lst)
         (let ((a (car obj))
               (str (car (cdr obj))))
           (when (zerop (mod i a))
             (princ str)
             (setf fizzed t))))
       (if (not fizzed)
         (princ i))
       (terpri))))

(fizz-buzz 100 '((3 "Fizz") (5 "Buzz")))

I know this is butt ugly, but the principle of generalizing with a 2nd 
list parameter seems like a reasonable enhancement. Since I'm not to the 
point of "thinking in Lisp", this would be my first approach, but maybe 
macros would be the way to go here. Hopefully, I'll have a feel for that 
after chapter 10 :)

Brian
From: ·············@craigslist.org
Subject: Re: A style question
Date: 
Message-ID: <x09Fh.35581$p9.32652@bignews7.bellsouth.net>
·············@craigslist.org wrote:
> def fizz_buzz n
>   1.upto(n) do |i|
>     print "Fizz" if fizz = (i % 3) == 0
>     print "Buzz" if buzz = (i % 5) == 0
>     puts fizz || buzz ? "" : i
>   end
> end
> 
> fizz_buzz 100
> 
> (defun fizz-buzz (n)
>   (do ((i 1 (+ i 1)))
>     ((> i n))
>     (let
>       ((fizz (= 0 (mod i 3)))
>        (buzz (= 0 (mod i 5))))
>       (if fizz (format t "Fizz"))
>       (if buzz (format t "Buzz"))
>       (format t "~A~%"
>               (if (or fizz buzz) "" i)))))
> 
> (fizz-buzz 100)

Another friend of mine commenting on the same FizzBuzz thread supplied 
the following Python code. It certainly is concise:

for i in xrange(1,101):
   print(str(i), "Fizz", "Buzz", "FizzBuzz")[(i%3==0)|(i%5==0)<<1]

I thought about retrofitting my Ruby version as an exercise, but alas, 
Ruby doesn't allow shifting truth to the left :)

Forgive my ignorance, but is anything like the boolean bit shifting 
technique used in the Python code above possible in Lisp? No big loss if 
it isn't, just curious.

I suppose it's unreasonable to expect the Lisp version to be as concise 
as the Python version - not only is this a toy example, but I think a 
language with more syntax will be able to provide more brevity in 
certain situations. That's a tradeoff I'm willing to accept given the 
benefits of a syntax that's more readily parsed and manipulated.

Brian
From: Joel Wilsson
Subject: Re: A style question
Date: 
Message-ID: <1172650620.200934.297590@q2g2000cwa.googlegroups.com>
On Feb 28, 7:09 am, ·············@craigslist.org wrote:
> Another friend of mine commenting on the same FizzBuzz thread supplied
> the following Python code. It certainly is concise:
>
> for i in xrange(1,101):
>    print(str(i), "Fizz", "Buzz", "FizzBuzz")[(i%3==0)|(i%5==0)<<1]
>
> I thought about retrofitting my Ruby version as an exercise, but alas,
> Ruby doesn't allow shifting truth to the left :)

While it's "nice" in this case, I think it's a sign of a weak type
system.
Even Java has a boolean type.

> Forgive my ignorance, but is anything like the boolean bit shifting
> technique used in the Python code above possible in Lisp? No big loss if
> it isn't, just curious.

No, but of course you could easily make it.
(flet ((num-zerop (x)
         (if (zerop x)
             1
             0)))
  (defun fizz-buzz (n)
    (dotimes (i (1+ n))
      (format t "~A~%" (nth (logior (num-zerop (mod i 3))
                                    (ash (num-zerop (mod i 5)) 1))
                            (list i "Fizz" "Buzz" "FizzBuzz"))))))

> I suppose it's unreasonable to expect the Lisp version to be as concise
> as the Python version

Due to the nature of the problem I don't think any language where
equality
testing returns true booleans can be shorter than that Python version.
This is closer to Common Lisp style I think, and slightly more
verbose:

(defun fizz-buzz (n)
  (dotimes (i (1+ n))
    (format t "~A~%" (nth (+ (if (zerop (mod i 3)) 1 0)
                             (if (zerop (mod i 5)) 2 0))
                          (list i "Fizz" "Buzz" "FizzBuzz")))))

In my opinion some of the first versions posted in this thread were
the
best, since they were much easier to read and understand. We're just
doing obfuscated stuff now, might as well go all out:

(defun fizz-buzz (n)
  (format t "~{~A~%~}" (reduce (lambda (h r)
                                 (cons (nth (reduce (lambda (x y)
                                                      (if (zerop (mod
h (1+ (* 2 y))))
                                                          (+ y x)
                                                          x))
                                                    '(1 2) :initial-
value 0)
                                            (list h "Fizz" "Buzz"
"FizzBuzz")) r))
                               (reduce (lambda (x y)
                                         (cons (decf n) y))
                                       (make-list (incf n)) :from-end
t)
                               :from-end t :initial-value nil)))


As for your question about loop, you really should learn it. Even if
you don't use it much yourself, plenty of code written by others does.

Regards,
  Joel
From: Rob Warnock
Subject: Re: A style question
Date: 
Message-ID: <zZSdnVArCY40vHjYnZ2dnUVZ_ruknZ2d@speakeasy.net>
<·············@craigslist.org> wrote:
+---------------
| Another friend of mine commenting on the same FizzBuzz thread supplied 
| the following Python code. It certainly is concise:
| 
| for i in xrange(1,101):
|    print(str(i), "Fizz", "Buzz", "FizzBuzz")[(i%3==0)|(i%5==0)<<1]
| 
| I thought about retrofitting my Ruby version as an exercise, but alas, 
| Ruby doesn't allow shifting truth to the left :)
| 
| Forgive my ignorance, but is anything like the boolean bit shifting 
| technique used in the Python code above possible in Lisp? No big loss if 
| it isn't, just curious.
+---------------

Well, sort of... ;-}  ;-}

This one is both efficient -- *no* MOD calls at all! --
*and* so ugly only a parent could love it:  ;-}  ;-}

    (defun fizz-buzz (n)
      (loop for i from 1 to n 
	    and three-p in '#3=(nil nil t . #3#)
	    and five-p in '#5=(nil nil nil nil t . #5#)
	do (format t "~a~%" (cond
			      ((and three-p five-p) "FizzBuzz")
			      (three-p "Fizz")
			      (five-p "Buzz")
			      (t i)))))


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <lI9Fh.810$8j.279@newsfe12.lga>
Rob Warnock wrote:
> <·············@craigslist.org> wrote:
> +---------------
> | Another friend of mine commenting on the same FizzBuzz thread supplied 
> | the following Python code. It certainly is concise:
> | 
> | for i in xrange(1,101):
> |    print(str(i), "Fizz", "Buzz", "FizzBuzz")[(i%3==0)|(i%5==0)<<1]
> | 
> | I thought about retrofitting my Ruby version as an exercise, but alas, 
> | Ruby doesn't allow shifting truth to the left :)
> | 
> | Forgive my ignorance, but is anything like the boolean bit shifting 
> | technique used in the Python code above possible in Lisp? No big loss if 
> | it isn't, just curious.
> +---------------
> 
> Well, sort of... ;-}  ;-}
> 
> This one is both efficient -- *no* MOD calls at all! --
> *and* so ugly only a parent could love it:  ;-}  ;-}
> 
>     (defun fizz-buzz (n)
>       (loop for i from 1 to n 
> 	    and three-p in '#3=(nil nil t . #3#)
> 	    and five-p in '#5=(nil nil nil nil t . #5#)
> 	do (format t "~a~%" (cond
> 			      ((and three-p five-p) "FizzBuzz")
> 			      (three-p "Fizz")
> 			      (five-p "Buzz")
> 			      (t i)))))

Yer a sick puppy, Rob, but I like it.

kt
From: ·············@craigslist.org
Subject: Re: A style question
Date: 
Message-ID: <GeaFh.35601$p9.9869@bignews7.bellsouth.net>
Ken Tilton wrote:
> 
> 
> Rob Warnock wrote:
>> <·············@craigslist.org> wrote:
>> +---------------
>> | Another friend of mine commenting on the same FizzBuzz thread 
>> supplied | the following Python code. It certainly is concise:
>> | | for i in xrange(1,101):
>> |    print(str(i), "Fizz", "Buzz", "FizzBuzz")[(i%3==0)|(i%5==0)<<1]
>> | | I thought about retrofitting my Ruby version as an exercise, but 
>> alas, | Ruby doesn't allow shifting truth to the left :)
>> | | Forgive my ignorance, but is anything like the boolean bit 
>> shifting | technique used in the Python code above possible in Lisp? 
>> No big loss if | it isn't, just curious.
>> +---------------
>>
>> Well, sort of... ;-}  ;-}
>>
>> This one is both efficient -- *no* MOD calls at all! --
>> *and* so ugly only a parent could love it:  ;-}  ;-}
>>
>>     (defun fizz-buzz (n)
>>       (loop for i from 1 to n         and three-p in '#3=(nil nil t . 
>> #3#)
>>         and five-p in '#5=(nil nil nil nil t . #5#)
>>     do (format t "~a~%" (cond
>>                   ((and three-p five-p) "FizzBuzz")
>>                   (three-p "Fizz")
>>                   (five-p "Buzz")
>>                   (t i)))))
> 
> Yer a sick puppy, Rob, but I like it.

Yeah, I know I should just turn away, but I can't help myself :)

I'll have to file this away and come back to it when I've learned enough 
to understand it. Looks like read macros are involved, but I don't want 
to get ahead of myself...

> 
> kt
From: Rob Warnock
Subject: Re: A style question
Date: 
Message-ID: <48GdnfyyrLfcrnjYnZ2dnUVZ_rWnnZ2d@speakeasy.net>
<·············@craigslist.org> wrote:
+---------------
| I'll have to file this away and come back to it when I've
| learned enough  to understand it. Looks like read macros
| are involved, but I don't want  to get ahead of myself...
+---------------

When you're ready, see:

    http://www.lisp.org/HyperSpec/Body/sec_2-4-8-15.html
    2.4.8.15 Sharpsign Equal-Sign

    http://www.lisp.org/HyperSpec/Body/sec_2-4-8-16.html
    2.4.8.16 Sharpsign Sharpsign

Just remember to (SETF *PRINT-CIRCLE* T) before trying
experiments at the REPL...


-Rob

p.s. The fact that I used #3= and #5= carried no semantics;
it was just for documentation. They could have been any two
distinct non-zero positive integers.

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Raffael Cavallaro
Subject: Re: A style question
Date: 
Message-ID: <2007022811370143658-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2007-02-28 02:33:08 -0500, ·············@craigslist.org said:

> Looks like read macros are involved, but I don't want to get ahead of myself...

To clarify, rather than use mod, Rob's version has loop iterate on two 
circular lists, one representing (mod i 3) the other representing (mod 
i 5). The #integer= and #integer# notations allow the lisp reader to 
construct wholly or partially self-referential list structure. Heed 
Rob's warning about setting *print-circle* to t unless you want a stack 
overflow.
From: ········@gmail.com
Subject: Re: A style question
Date: 
Message-ID: <1172683939.247966.220650@s48g2000cws.googlegroups.com>
Rob Warnock wrote:
> <·············@craigslist.org> wrote:
> +---------------
> | Another friend of mine commenting on the same FizzBuzz thread supplied
> | the following Python code. It certainly is concise:
> |
> | for i in xrange(1,101):
> |    print(str(i), "Fizz", "Buzz", "FizzBuzz")[(i%3==0)|(i%5==0)<<1]
> |
> | I thought about retrofitting my Ruby version as an exercise, but alas,
> | Ruby doesn't allow shifting truth to the left :)
> |
> | Forgive my ignorance, but is anything like the boolean bit shifting
> | technique used in the Python code above possible in Lisp? No big loss if
> | it isn't, just curious.
> +---------------
>
> Well, sort of... ;-}  ;-}
>
> This one is both efficient -- *no* MOD calls at all! --
> *and* so ugly only a parent could love it:  ;-}  ;-}
>
>     (defun fizz-buzz (n)
>       (loop for i from 1 to n
> 	    and three-p in '#3=(nil nil t . #3#)
> 	    and five-p in '#5=(nil nil nil nil t . #5#)
> 	do (format t "~a~%" (cond
> 			      ((and three-p five-p) "FizzBuzz")
> 			      (three-p "Fizz")
> 			      (five-p "Buzz")
> 			      (t i)))))
>

This is awsome, Rob ;-) But I can make one that's faster AND uglier!

(defmacro def-fizz-buzz ()
  (let (l)
    (do* ((i 1 (incf i))
	  (m3p (zerop (mod i 3))
	       (zerop (mod i 3)))
	  (m5p (zerop (mod i 5))
	       (zerop (mod i 5))))
	 ((> i 15))
      (setq l
	    (list*  `(print ,(cond ((and m3p m5p) "FizzBuzz")
				   (m3p           "Buzz")
				   (m5p           "Fizz")
				   (t             'y)))
		    '(when (> y x) (return))
		    '(incf y)
		    l)))
    `(defun fizz-buzz (x)
      (let ((y 0))
	(loop ,@(reverse l))))))

CL-USER> (macroexpand-1 '(def-fizz-buzz))

=>

(DEFUN FIZZ-BUZZ (X)
  (LET ((Y 0))
    (LOOP (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT Y)
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT Y)
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT "Buzz")
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT Y)
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT "Fizz")
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT "Buzz")
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT Y)
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT Y)
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT "Buzz")
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT "Fizz")
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT Y)
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT "Buzz")
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT Y)
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT Y)
	  (INCF Y)
	  (WHEN (> Y X) (RETURN))
	  (PRINT "FizzBuzz"))))
From: Rob Warnock
Subject: Re: A style question
Date: 
Message-ID: <JrSdndwsgPE9y3vYnZ2dnUVZ_rmdnZ2d@speakeasy.net>
<········@gmail.com> wrote:
+---------------
| Rob Warnock wrote:
| > This one is both efficient -- *no* MOD calls at all! --
| > *and* so ugly only a parent could love it:  ;-}  ;-}
| >
| >     (defun fizz-buzz (n)
| >       (loop for i from 1 to n
| > 	    and three-p in '#3=(nil nil t . #3#)
| > 	    and five-p in '#5=(nil nil nil nil t . #5#)
| > 	do ...
| 
| This is awsome, Rob ;-) But I can make one that's faster AND uglier!
| 
| (defmacro def-fizz-buzz ()
|   (let (l)
|     (do* ((i 1 (incf i))
| 	  (m3p (zerop (mod i 3))
| 	       (zerop (mod i 3)))
| 	  (m5p (zerop (mod i 5))
| 	       (zerop (mod i 5))))
| 	 ((> i 15))
|       (setq l
| 	    (list*  `(print ,(cond ((and m3p m5p) "FizzBuzz")
| 				   (m3p           "Buzz")
| 				   (m5p           "Fizz")
| 				   (t             'y)))
| 		    '(when (> y x) (return))
| 		    '(incf y)
| 		    l)))
|     `(defun fizz-buzz (x)
|       (let ((y 0))
| 	(loop ,@(reverse l))))))
+---------------

Yes!! *That's* how to use macros to write code for you!!  ;-}

One minor tweak -- instead of:

    (INCF Y)
    (WHEN (> Y X) (RETURN))

you could use:
  	  
    (WHEN (> (INCF Y) X) (RETURN))

Another really minor tweak -- in the DO* variable bindings,
instead of (M3P (ZEROP (MOD I 3)) (ZEROP (MOD I 3)) you can
write (M3P #1=(ZEROP (MOD I 3)) #1#).

Now for *lots* of extra credit...  ;-}  ;-}

Write the general version of DEF-FIZZ-BUZZ that accepts a
function name (so we can tell them apart) and an alist of primes
and strings, and emits similarly-correct/fast code. E.g., the 
example we've been using all along would be generated like so:

    (def-fizz-buzz 'fizz-buzz '((3 "Fizz") (5 "Buzz")))


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: lojic
Subject: Re: A style question
Date: 
Message-ID: <1172723942.114271.314410@z35g2000cwz.googlegroups.com>
On Feb 28, 11:29 pm, ····@rpw3.org (Rob Warnock) wrote:
> Now for *lots* of extra credit...  ;-}  ;-}
>
> Write the general version of DEF-FIZZ-BUZZ that accepts a
> function name (so we can tell them apart) and an alist of primes
> and strings, and emits similarly-correct/fast code. E.g., the
> example we've been using all along would be generated like so:
>
>     (def-fizz-buzz 'fizz-buzz '((3 "Fizz") (5 "Buzz")))

That goes back to my earlier post of the following generalized
solution:

(defun fizz-buzz (n lst)
  (do ((i 1 (+ i 1)))
    ((> i n))
    (let
      ((fizzed nil))
      (dolist (obj lst)
        (let ((a (car obj))
              (str (car (cdr obj))))
          (when (zerop (mod i a))
            (princ str)
            (setf fizzed t))))
      (if (not fizzed)
        (princ i))
      (terpri))))

(fizz-buzz 15 '((3 "Fizz") (5 "Buzz")))

This was my off-the-cuff approach from a non-Lisp background. I would
like to see a macro-ized version and get some feedback from the group
regarding the appropriateness of macros in this case vs. a simple
function as in the above.

Brian Adkins

>
> -Rob
>
> -----
> Rob Warnock                     <····@rpw3.org>
> 627 26th Avenue                 <URL:http://rpw3.org/>
> San Mateo, CA 94403             (650)572-2607
From: Rob Warnock
Subject: Re: A style question
Date: 
Message-ID: <QZydndIw1N5JNnvYnZ2dnUVZ_rOqnZ2d@speakeasy.net>
lojic <···········@gmail.com> wrote:
+---------------
| ····@rpw3.org (Rob Warnock) wrote:
| > Write the general version of DEF-FIZZ-BUZZ that accepts a
| > function name (so we can tell them apart) and an alist of primes
| > and strings, and emits similarly-correct/fast code. E.g., the
| > example we've been using all along would be generated like so:
| >
| >     (def-fizz-buzz 'fizz-buzz '((3 "Fizz") (5 "Buzz")))
| 
| That goes back to my earlier post of the following generalized
| solution:
| 
| (defun fizz-buzz (n lst)
|   (do ((i 1 (+ i 1)))
|     ((> i n))
|     (let
|       ((fizzed nil))
|       (dolist (obj lst)
|         (let ((a (car obj))
|               (str (car (cdr obj))))
|           (when (zerop (mod i a))
|             (princ str)
|             (setf fizzed t))))
|       (if (not fizzed)
|         (princ i))
|       (terpri))))
| 
| (fizz-buzz 15 '((3 "Fizz") (5 "Buzz")))
+---------------

That's fine, for a run-time function. [I had a bit of a chuckle at what
(fizz-buzz 100 '((2 "Burp")(3 "Fizz") (5 "Buzz")(7 "Bang")(11 "Boom!")))
outputs...]

+---------------
| This was my off-the-cuff approach from a non-Lisp background.
+---------------

It's actually reasonably "Lispy" as is. Oh, sure, you might use
(DOTIMES (I N) ...) or (LOOP FOR I FROM 1 TO N DO ...) instead of DO;
and you might want to use CADR or SECOND instead of (CAR (CDR ...))
and hold off on fetching that until inside the WHEN; and also the
LET is formatted uncommonly; and use UNLESS instead of (IF (NOT...)...);
and call things LIST, not LST; little stuff like that, e.g.:

  (defun fizz-buzz (n list)
    (dotimes (i n)
      (let ((fizzed nil))
        (dolist (item list)
          (when (zerop (mod i (first item)))
	    (princ (second item))
	    (setf fizzed t)))
        (unless fizzed
          (princ i))
	(terpri))))

And you could use LOOP instead of the inner DOLIST and replace the
LET with a WITH term, but then it'd probably look *less* "Lispy"
to many people:

  (defun fizz-buzz (n list)
    (dotimes (i n)
      (loop with fizzed = nil
	    for item in list
	when (zerop (mod i (first item)))
	  do (princ (second item))
	     (setf fizzed t)
	finally (unless fizzed
		  (princ i))
	        (terpri))))

+---------------
| I would like to see a macro-ized version...
+---------------

Did you see <········@gmail.com>'s version for the case of a
hard-coded '((3 "Fizz") (5 "Buzz")) list?

+---------------
| ...and get some feedback from the group regarding the
| appropriateness of macros in this case vs. a simple
| function as in the above.
+---------------

A macro would fix the LIST at macroexpansion time, which allows
the macro to potentially generate better code [possibly *much*
better code, as <········@gmail.com> showed], but loses the
runtime flexibility of your above function.

One hybrid that might be useful would be a function that
looked at N and the length of LIST (and all the CARs) and
decided whether to do it the straightforward way (as above)
or whether to use an initialization step to pre-bake some
auxiliary tables to speed up the computation [e.g., like
the circular lists in my version, to avoid MOD, but computed
at runtime].


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Brian Adkins
Subject: Re: A style question
Date: 
Message-ID: <%5EFh.429$B7.4@bigfe9>
Rob Warnock wrote:
> lojic <···········@gmail.com> wrote:
> +---------------
> | ····@rpw3.org (Rob Warnock) wrote:
> | > Write the general version of DEF-FIZZ-BUZZ that accepts a
> | > function name (so we can tell them apart) and an alist of primes
> | > and strings, and emits similarly-correct/fast code. E.g., the
> | > example we've been using all along would be generated like so:
> | >
> | >     (def-fizz-buzz 'fizz-buzz '((3 "Fizz") (5 "Buzz")))
> | 
> | That goes back to my earlier post of the following generalized
> | solution:
> | 
> | (defun fizz-buzz (n lst)
> |   (do ((i 1 (+ i 1)))
> |     ((> i n))
> |     (let
> |       ((fizzed nil))
> |       (dolist (obj lst)
> |         (let ((a (car obj))
> |               (str (car (cdr obj))))
> |           (when (zerop (mod i a))
> |             (princ str)
> |             (setf fizzed t))))
> |       (if (not fizzed)
> |         (princ i))
> |       (terpri))))
> | 
> | (fizz-buzz 15 '((3 "Fizz") (5 "Buzz")))
> +---------------
> 
> That's fine, for a run-time function. [I had a bit of a chuckle at what
> (fizz-buzz 100 '((2 "Burp")(3 "Fizz") (5 "Buzz")(7 "Bang")(11 "Boom!")))
> outputs...]
> 
> +---------------
> | This was my off-the-cuff approach from a non-Lisp background.
> +---------------
> 
> It's actually reasonably "Lispy" as is. 

Thanks for the tips below. When I said, "non-Lisp background" I wasn't 
referring to the Lispyness of the implementation of the function (which 
I kind of slapped together with the tools I've accumulated through p.36 
of Graham's book), but the use of a runtime function vs. a macro.

> Oh, sure, you might use 

[tips deleted for brevity]

> +---------------
> | I would like to see a macro-ized version...
> +---------------
> 
> Did you see <········@gmail.com>'s version for the case of a
> hard-coded '((3 "Fizz") (5 "Buzz")) list?

Actually no :( I searched for posts by nallen05 and didn't see any on 
this thread, but Bellsouth had newsgroup server issues yesterday, they 
may have dropped a few posts. I'll try searching Google groups for it.

> +---------------
> | ...and get some feedback from the group regarding the
> | appropriateness of macros in this case vs. a simple
> | function as in the above.
> +---------------
> 
> A macro would fix the LIST at macroexpansion time, which allows
> the macro to potentially generate better code [possibly *much*
> better code, as <········@gmail.com> showed], but loses the
> runtime flexibility of your above function.
> 
> One hybrid that might be useful would be a function that
> looked at N and the length of LIST (and all the CARs) and
> decided whether to do it the straightforward way (as above)
> or whether to use an initialization step to pre-bake some
> auxiliary tables to speed up the computation [e.g., like
> the circular lists in my version, to avoid MOD, but computed
> at runtime].

Interesting

> -Rob
> 
> -----
> Rob Warnock			<····@rpw3.org>
> 627 26th Avenue			<URL:http://rpw3.org/>
> San Mateo, CA 94403		(650)572-2607
> 
From: Vassil Nikolov
Subject: Re: A style question
Date: 
Message-ID: <yy8vejo9eb1y.fsf@eskimo.com>
On Wed, 28 Feb 2007 22:29:20 -0600, ····@rpw3.org (Rob Warnock) said:
| ...
| Write the general version of DEF-FIZZ-BUZZ that accepts a
| function name (so we can tell them apart) and an alist of primes
| and strings, and emits similarly-correct/fast code. E.g., the 
| example we've been using all along would be generated like so:
|     (def-fizz-buzz 'fizz-buzz '((3 "Fizz") (5 "Buzz")))

  But there is nothing special about primes in this problem.  It is all
  about having a finite number of (possibly overlapping) classes (whose
  union does not necessarily cover the universe), and tagging values
  with regards to membership in said classes.  ("Class", of course, in
  the usual set-theoretical sense, not in the more specialized OO
  sense.)

  Here is a sketch of the nucleus of a solution that trivially scales
  into an arbitrary number of such classes, each specified by its
  predicate.  It uses divisibility-by-a-prime classes only to illustrate,
  but obviously the arithmetic aspect is abstracted away.  (For brevity,
  we take some shortcuts, e.g. by "collapsing" the tags and the predicates
  into the same list of symbols.)

    (defun classify (x)
      "Return a list of tags, one for each predicate satisfied by the argument.
    If all predicates are false, a list containing only the argument itself
    is returned.

    Implementation note: Writing a compiler from the return value into a
    FORMAT control string is left as an exercise for the reader."
      (classify-aux x '(quinque tres duo) '()))

    (defun classify-aux (x tags val)
      ;; correctness should be apparent; trivially DO-able
      (if (endp tags) (or val (list x))
        (classify-aux x
                      (rest tags)
                      (if (funcall (first tags) x)
                          (cons (first tags) val)
                        val))))

    (defun duo (i) (zerop (mod i 2)))
    (defun tres (i) (zerop (mod i 3)))
    (defun quinque (i) (zerop (mod i 5)))

    (classify 101) => (101)
    (classify (* 2 3 5)) => (duo tres quinque)

  Note: we do want to do each test exactly once for elegance, even if
  the predicates are tabulated.

  ---Vassil.


-- 
mind mate, n.
  One of two persons mentally compatible with each other (cf. soul mate).
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <U1vFh.53$XI4.26@newsfe12.lga>
Vassil Nikolov wrote:
> On Wed, 28 Feb 2007 22:29:20 -0600, ····@rpw3.org (Rob Warnock) said:
> | ...
> | Write the general version of DEF-FIZZ-BUZZ that accepts a
> | function name (so we can tell them apart) and an alist of primes
> | and strings, and emits similarly-correct/fast code. E.g., the 
> | example we've been using all along would be generated like so:
> |     (def-fizz-buzz 'fizz-buzz '((3 "Fizz") (5 "Buzz")))
> 
>   But there is nothing special about primes in this problem.  It is all
>   about having a finite number of (possibly overlapping) classes (whose
>   union does not necessarily cover the universe), and tagging values
>   with regards to membership in said classes.  ("Class", of course, in
>   the usual set-theoretical sense, not in the more specialized OO
>   sense.)
> 
>   Here is a sketch of the nucleus of a solution that trivially scales
>   into an arbitrary number of such classes, each specified by its
>   predicate.  It uses divisibility-by-a-prime classes only to illustrate,
>   but obviously the arithmetic aspect is abstracted away.

Thank you! Finally someone has come to grips with the problem scalably.

I say we move into beta testing Q2 of '07 and production Q3.

Is this what the OE (original employer) was looking for?

hth,kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Thomas A. Russ
Subject: Re: A style question
Date: 
Message-ID: <ymitzx35zud.fsf@sevak.isi.edu>
Vassil Nikolov <···············@pobox.com> writes:
> 
>   But there is nothing special about primes in this problem.  It is all
>   about having a finite number of (possibly overlapping) classes (whose
>   union does not necessarily cover the universe), and tagging values
>   with regards to membership in said classes.  ("Class", of course, in
>   the usual set-theoretical sense, not in the more specialized OO
>   sense.)
> 
>   Here is a sketch of the nucleus of a solution that trivially scales
>   into an arbitrary number of such classes, each specified by its
>   predicate.  It uses divisibility-by-a-prime classes only to illustrate,
>   but obviously the arithmetic aspect is abstracted away.  (For brevity,
>   we take some shortcuts, e.g. by "collapsing" the tags and the predicates
>   into the same list of symbols.)

Bravo!

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: ·····················@gmail.com
Subject: Re: A style question
Date: 
Message-ID: <1172968690.514523.193780@v33g2000cwv.googlegroups.com>
On Mar 1, 6:24 am, Vassil Nikolov <···············@pobox.com> wrote:

>   Note: we do want to do each test exactly once for elegance, even if
>   the predicates are tabulated.
>
>   ---Vassil.
Alternatively we could tabulate the responses instead...

(defun my-bool-hash-fun (bools)
   (let ((acc 0))
     (labels ((hash-fn (list)
		(setf acc (+ (* 2 acc)
			     (if (first list) 1 0)))
		(when (rest list)
		  (hash-fn (rest list)))))
       (hash-fn bools)
       acc)))

(defun make-response (&rest lambdas)
  (let ((fn-vector (make-array (length lambdas) :initial-contents
lambdas)))
    (lambda (&rest rest)
      (aref fn-vector (my-bool-hash-fun rest)))))

(let ((temp (make-response (lambda (x)(format t "~a~%" x))
			   (lambda (x)(declare (ignore x))(format t "Foo~%"))
			   (lambda (x)(declare (ignore x))(format t "Bar~%"))
			   (lambda (x)(declare (ignore x))(format t "FooBar~%")))))
  (defun  foobar (&rest rest) (apply temp rest)))

(dotimes (k 100)
    (funcall (foobar (zerop(mod k 3)) (zerop(mod k 5)))k))
From: Ari Johnson
Subject: Re: A style question
Date: 
Message-ID: <m21wk97dc9.fsf@hermes.theari.com>
····@rpw3.org (Rob Warnock) writes:

> <········@gmail.com> wrote:
> +---------------
> | Rob Warnock wrote:
> | > This one is both efficient -- *no* MOD calls at all! --
> | > *and* so ugly only a parent could love it:  ;-}  ;-}
> | >
> | >     (defun fizz-buzz (n)
> | >       (loop for i from 1 to n
> | > 	    and three-p in '#3=(nil nil t . #3#)
> | > 	    and five-p in '#5=(nil nil nil nil t . #5#)
> | > 	do ...
> | 
> | This is awsome, Rob ;-) But I can make one that's faster AND uglier!
> | 
> | (defmacro def-fizz-buzz ()
> |   (let (l)
> |     (do* ((i 1 (incf i))
> | 	  (m3p (zerop (mod i 3))
> | 	       (zerop (mod i 3)))
> | 	  (m5p (zerop (mod i 5))
> | 	       (zerop (mod i 5))))
> | 	 ((> i 15))
> |       (setq l
> | 	    (list*  `(print ,(cond ((and m3p m5p) "FizzBuzz")
> | 				   (m3p           "Buzz")
> | 				   (m5p           "Fizz")
> | 				   (t             'y)))
> | 		    '(when (> y x) (return))
> | 		    '(incf y)
> | 		    l)))
> |     `(defun fizz-buzz (x)
> |       (let ((y 0))
> | 	(loop ,@(reverse l))))))
> +---------------
>
> Yes!! *That's* how to use macros to write code for you!!  ;-}
>
> One minor tweak -- instead of:
>
>     (INCF Y)
>     (WHEN (> Y X) (RETURN))
>
> you could use:
>   	  
>     (WHEN (> (INCF Y) X) (RETURN))
>
> Another really minor tweak -- in the DO* variable bindings,
> instead of (M3P (ZEROP (MOD I 3)) (ZEROP (MOD I 3)) you can
> write (M3P #1=(ZEROP (MOD I 3)) #1#).
>
> Now for *lots* of extra credit...  ;-}  ;-}
>
> Write the general version of DEF-FIZZ-BUZZ that accepts a
> function name (so we can tell them apart) and an alist of primes
> and strings, and emits similarly-correct/fast code. E.g., the 
> example we've been using all along would be generated like so:
>
>     (def-fizz-buzz 'fizz-buzz '((3 "Fizz") (5 "Buzz")))

Syntax is slightly different, see comments below.  This uses all the
dirty tricks that I've seen discussed so far.

(setf *print-circle* t) ; You'll thank me later

(defun primep (n)
  ; Most naive and trusting function I've ever written:
  ; assume that all integers are prime
  (integerp n))

(defun compose-fizz-list-item (n fizzes)
  (apply #'concatenate 'string
         (mapcan #'(lambda (fizz)
                     (when (zerop (mod n (car fizz)))
                       (list (cadr fizz))))
                 fizzes)))

(defun compose-fizz-list (lcm fizzes)
  (let ((fizz-list
         (loop for n from 1 to lcm
            collect (compose-fizz-list-item n fizzes))))
    (setf fizz-list
          (mapcar #'(lambda (string) (if (string= string "") nil string))
                  fizz-list))
    (setf (nthcdr lcm fizz-list) fizz-list)
    fizz-list))

; (make-fizz fizz-buzz 100 (3 "Fizz") (5 "Buzz"))
(defmacro make-fizz (name ceiling &rest fizzes)
  (loop for fizz in fizzes
     when (or (not (primep (car fizz)))
              (not (stringp (cadr fizz))))
       do (error "syntax error"))
  (let* ((lcm (apply #'lcm (mapcar #'(lambda (fizz) (car fizz)) fizzes)))
         (fizz-list (compose-fizz-list lcm fizzes)))
    `(defun ,name ()
       ; Don't care about variable capture since we don't have a body
       (loop for n from 1 upto ,ceiling for fizz in ',fizz-list
          collect (if fizz fizz n)))))
From: ·········@gmail.com
Subject: Re: A style question
Date: 
Message-ID: <1172752138.046216.99790@n33g2000cwc.googlegroups.com>
On Mar 1, 2:32 am, ········@gmail.com wrote:
> Rob Warnock wrote:
> > This one is both efficient -- *no* MOD calls at all! --
> > *and* so ugly only a parent could love it:  ;-}  ;-}
>
> >     (defun fizz-buzz (n)
> >       (loop for i from 1 to n
> >        and three-p in '#3=(nil nil t . #3#)
> >        and five-p in '#5=(nil nil nil nil t . #5#)
> >    do (format t "~a~%" (cond
> >                          ((and three-p five-p) "FizzBuzz")
> >                          (three-p "Fizz")
> >                          (five-p "Buzz")
> >                          (t i)))))
>
> This is awsome, Rob ;-) But I can make one that's faster AND uglier!

But not general!

(defmacro def-fizz-buzz (name ls)
  (let* ((mods (mapcar #'car ls))
         (lcm (apply #'lcm mods))
         (len (length ls))
         (groups (make-array (expt 2 len) :initial-element '()))
         (n (gensym "n"))
         (count (gensym "i")))
    (do ((i 0 (+ i 1)))
        ((>= i lcm))
      (let ((group-index
             (do ((x (reverse (mapcar #'(lambda (m) (mod i m)) mods))
(cdr x))
                  (gi 0 (+ (ash gi 1) (if (zerop (car x)) 1 0))))
                 ((null x) gi))))
        (setf (aref groups group-index) (cons i (aref groups group-
index)))))
    `(defun ,name (,n)
       (do ((,count 1 (+ ,count 1)))
           ((> ,count ,n))
         (case (mod ,count ,lcm)
           ,@(loop for i from 1 to (- (expt 2 len) 1)
                   when (consp (aref groups i))
                   collect
                   `(,(reverse (aref groups i))
                     (format t "~A~%"
                      ,(let ((s ""))
                         (loop for j from 0 to (- len 1)
                               for str in ls
                               when (not (zerop (logand i (expt 2
j))))
                               do (setf s (concatenate 'string s (cadr
str))))
                         s))))
           (t (format t "~S~%" ,count)))))))


(def-fizz-buzz fizz-buzz ((3 "Fizz") (5 "Buzz") (6 "Gorp")))

=>

(defun fizz-buzz (n)
  (do ((i 1 (+ i 1)))
      ((> i n))
    (case (mod i 30)
      ((3 9 21 27) (format t "~A~%" "Fizz"))
      ((5 10 20 25) (format t "~A~%" "Buzz"))
      ((15) (format t "~A~%" "FizzBuzz"))
      ((6 12 18 24) (format t "~A~%" "FizzGorp"))
      ((0) (format t "~A~%" "FizzBuzzGorp"))
      (t (format t "~S~%" i)))))

Note the numbers don't need to be prime, or even
relatively prime.

There are no conditionals (which are many times
slower than MOD on modern processors), except for
a CASE that can easily be jump-tabled.

Outputting the same code as nalle would be a minor
modification, though if you're going to unroll the
loop it would be better to remove the WHEN's and
have a separate block to handle the (mod n lcm)
remaining few numbers after walking the loop in steps
of lcm.

--
Alex
From: Tim Bradshaw
Subject: Re: A style question
Date: 
Message-ID: <es4la4$npu$1$8302bc10@news.demon.co.uk>
On 2007-02-28 06:31:05 +0000, ····@rpw3.org (Rob Warnock) said:

> This one is both efficient -- *no* MOD calls at all! --
> *and* so ugly only a parent could love it:  ;-}  ;-}

I missed this.  It's also really good.  I think a combination of this 
and (a working version of) the one I posted just now ought to be 
something to be really proud of.

--tim
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <nalFh.25$XI4.20@newsfe12.lga>
Tim Bradshaw wrote:
> On 2007-02-28 06:31:05 +0000, ····@rpw3.org (Rob Warnock) said:
> 
>> This one is both efficient -- *no* MOD calls at all! --
>> *and* so ugly only a parent could love it:  ;-}  ;-}
> 
> 
> I missed this.  It's also really good.  I think a combination of this 
> and (a working version of) the one I posted just now ought to be 
> something to be really proud of.

Ok, let's take another week on this, total up the cumulative man-months 
and submit it for the 5-minute interview.

kt

ps. Me, I am not starting until we get the functional requirements 
cleared up. k


-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Rob Warnock
Subject: Re: A style question
Date: 
Message-ID: <woWdnWlfqrlgxnvYnZ2dnUVZ_q6vnZ2d@speakeasy.net>
Ken Tilton  <·········@gmail.com> wrote:
+---------------
| ps. Me, I am not starting until we get the functional requirements 
| cleared up. k
+---------------

See my reply to <········@gmail.com>'s MOD-free code-generating macro,
or take this instead:

    Macro DEF-FIZZ-BUZZ  -- Define a "fizz-buzz"-generating function

    Syntax:
    def-fizz-buzz fname alist ==> fname

    Arguments and Values:
    fname -- A symbol, the name of the function to be defined (as by DEFUN).

    alist -- an association list, whose keys are prime integers > 1
	     and whose values are strings.

    Description:

    DEF-FIZZ-BUZZ defines a function named FNAME of one argument,
    a positive integer. When called with an argument (say) N, FNAME
    will print each positive integer starting with 1 below N, followed
    by a newline, except that if any of the keys of the ALIST evenly
    divide the current integer, then the corresponding string value(s)
    of the key(s) dividing the current integer will be printed instead
    of the integer itself. Note: If multiple keys divide the current
    integer, all of the corresponding string values will be printed,
    in the same order as the elements of the ALIST. Only one copy
    of any string value will be printed for any current integer.

    Examples:

    (def-fizz-buzz 'fizz-buzz '((3 . "Fizz") (5 . "Buzz"))) ==> FIZZ-BUZZ

    (fizz-buzz 22)
    >> 1
    >> 2
    >> Fizz
    >> 4
    >> Buzz
    >> Fizz
    >> 7
    >> 8
    >> Fizz
    >> Buzz
    >> 11
    >> Fizz
    >> 13
    >> 14
    >> FizzBuzz
    >> 16
    >> 17
    >> Fizz
    >> 19
    >> Buzz
    >> Fizz
    >> 22
    ==> NIL

    (def-fizz-buzz 'very-fizzy
		   '((2 . "Burp") (3 . "Fizz") (5 . "Buzz") (7 . "Bang")))
    ==> VERY-FIZZY

    (very-fizzy 16)
    >> 1
    >> Burp
    >> Fizz
    >> Burp
    >> Buzz
    >> BurpFizz
    >> Bang
    >> Burp
    >> Fizz
    >> BurpBuzz
    >> 11
    >> BurpFizz
    >> 13
    >> BurpBang
    >> FizzBuzz
    >> Burp
    ==> NIL

There's your spec. Where's your code?  ;-}


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: ···············@gmail.com
Subject: Re: A style question
Date: 
Message-ID: <1172738585.952391.152940@v33g2000cwv.googlegroups.com>
<snip>
> There's your spec. Where's your code?  ;-}
>
> -Rob

OK, hello c.l.l from another noob lurker.  I guess this is as good a
way to jump in as any.  It's my first macro, so please be gentle.

I had to unquote the arguments to def-fizz-buzz in order to make it
work.  I'm wondering why, since macro arguments aren't evaluated, your
spec quoted both the name and the alist?

(defun new-counter (target true-value &optional (false-value ""))
  (let ((counter 0))
    #'(lambda ()
	(if (= (incf counter) target)
	    (progn
	      (setf counter 0)
	      true-value)
	    false-value))))


(defmacro def-fizz-buzz (name condition-list)
;;  sample call:  (def-fizz-buzz fizz-buzz ((3 . "Fizz") (5 .
"Buzz")))
  (let ((conditions (loop for e in condition-list collecting
			 (list 'new-counter (car e) (cdr e)))))
    `(defun ,name (n)
       (let ((conds (list ,@conditions)))
	 (loop for i from 1 to n do
	      (let ((print-value (apply #'concatenate 'string
					(mapcar #'funcall conds))))
		(if (string= print-value "")
		    (print i)
		    (print print-value))))))))


CL-USER> (def-fizz-buzz very-fizzy ((2 . "Burp") (3 . "Fizz") (5 .
"Buzz") (7 . "Bang")))

VERY-FIZZY
CL-USER> (very-fizzy 16)

1
"Burp"
"Fizz"
"Burp"
"Buzz"
"BurpFizz"
"Bang"
"Burp"
"Fizz"
"BurpBuzz"
11
"BurpFizz"
13
"BurpBang"
"FizzBuzz"
"Burp"
NIL
CL-USER>


Regards,

Themba
From: Brian Adkins
Subject: Re: A style question
Date: 
Message-ID: <FRDFh.396$B7.185@bigfe9>
···············@gmail.com wrote:
> OK, hello c.l.l from another noob lurker.  I guess this is as good a
> way to jump in as any.  It's my first macro, so please be gentle.

 From one newbie to another, that's a great first macro :)

I'd still like to get some experts to weigh in on the appropriateness of 
macros in this case.

For example, if we're only going to call fizzbuzz once for a given set 
of primes+strings (unlikely), then I think defining a function is 
sufficient:

(defun fizz-buzz (n lst)
   (do ((i 1 (+ i 1)))
     ((> i n))
     (let
       ((fizzed nil))
       (dolist (obj lst)
         (let ((a (car obj))
               (str (car (cdr obj))))
           (when (zerop (mod i a))
             (princ str)
             (setf fizzed t))))
       (if (not fizzed)
         (princ i))
       (terpri))))

(fizz-buzz 15 '((3 "Fizz") (5 "Buzz")))

And if it will be called repeatedly and we don't want to pass the list 
argument repeatedly, wouldn't defining a new function be sufficient?

(defun very-fizzy (n)
   (fizz-buzz n '((3 "Fizz") (5 "Buzz"))))

(very-fizzy 15)

Any advantages of macros over this?

> I had to unquote the arguments to def-fizz-buzz in order to make it
> work.  I'm wondering why, since macro arguments aren't evaluated, your
> spec quoted both the name and the alist?
> 
> (defun new-counter (target true-value &optional (false-value ""))
>   (let ((counter 0))
>     #'(lambda ()
> 	(if (= (incf counter) target)
> 	    (progn
> 	      (setf counter 0)
> 	      true-value)
> 	    false-value))))
> 
> 
> (defmacro def-fizz-buzz (name condition-list)
> ;;  sample call:  (def-fizz-buzz fizz-buzz ((3 . "Fizz") (5 .
> "Buzz")))
>   (let ((conditions (loop for e in condition-list collecting
> 			 (list 'new-counter (car e) (cdr e)))))
>     `(defun ,name (n)
>        (let ((conds (list ,@conditions)))
> 	 (loop for i from 1 to n do
> 	      (let ((print-value (apply #'concatenate 'string
> 					(mapcar #'funcall conds))))
> 		(if (string= print-value "")
> 		    (print i)
> 		    (print print-value))))))))
> 
> 
> CL-USER> (def-fizz-buzz very-fizzy ((2 . "Burp") (3 . "Fizz") (5 .
> "Buzz") (7 . "Bang")))
> 
> VERY-FIZZY
> CL-USER> (very-fizzy 16)
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <1PAFh.5741$2Y3.5349@newsfe12.lga>
Rob Warnock wrote:
> Ken Tilton  <·········@gmail.com> wrote:
> +---------------
> | ps. Me, I am not starting until we get the functional requirements 
> | cleared up. k
> +---------------
> 
> See my reply to <········@gmail.com>'s MOD-free code-generating macro,
> or take this instead:
> 
>     Macro DEF-FIZZ-BUZZ  -- Define a "fizz-buzz"-generating function
> 
>     Syntax:
>     def-fizz-buzz fname alist ==> fname
> 
>     Arguments and Values:
>     fname -- A symbol, the name of the function to be defined (as by DEFUN).
> 
>     alist -- an association list, whose keys are prime integers > 1
> 	     and whose values are strings.
> 
>     Description:
> 
>     DEF-FIZZ-BUZZ defines a function named FNAME of one argument,

er, two?

>     a positive integer. When called with an argument (say) N, FNAME
>     will print each positive integer starting with 1

I am concerned that we are misunderstanding each other, since 1 would 
never be divisible by any prime integer > 1.

> ... below N,

Did you mean "to N"? I ask only because that was the original spec and 
it sounded inclusive and I have not seen anything necessitating a 
change. Just want to make sure that was intended.

> followed
>     by a newline, except that if any of the keys of the ALIST evenly
>     divide the current integer, then the corresponding string value(s)
>     of the key(s) dividing the current integer will be printed instead
>     of the integer itself. Note: If multiple keys divide the current
>     integer, all of the corresponding string values will be printed,
>     in the same order as the elements of the ALIST. Only one copy
>     of any string value will be printed for any current integer.
> 
>     Examples:
> 
>     (def-fizz-buzz 'fizz-buzz '((3 . "Fizz") (5 . "Buzz"))) ==> FIZZ-BUZZ
> 
>     (fizz-buzz 22)
>     >> 1
>     >> 2
>     >> Fizz
>     >> 4
>     >> Buzz
>     >> Fizz
>     >> 7
>     >> 8
>     >> Fizz
>     >> Buzz
>     >> 11
>     >> Fizz
>     >> 13
>     >> 14
>     >> FizzBuzz
>     >> 16
>     >> 17
>     >> Fizz
>     >> 19
>     >> Buzz
>     >> Fizz
>     >> 22
>     ==> NIL
> 
>     (def-fizz-buzz 'very-fizzy
> 		   '((2 . "Burp") (3 . "Fizz") (5 . "Buzz") (7 . "Bang")))
>     ==> VERY-FIZZY
> 
>     (very-fizzy 16)
>     >> 1
>     >> Burp
>     >> Fizz
>     >> Burp
>     >> Buzz
>     >> BurpFizz
>     >> Bang
>     >> Burp
>     >> Fizz
>     >> BurpBuzz
>     >> 11
>     >> BurpFizz
>     >> 13
>     >> BurpBang
>     >> FizzBuzz
>     >> Burp
>     ==> NIL
> 
> There's your spec. Where's your code?  ;-}

Hunh? Right here:

"...print each positive integer starting with 1 below N, followed
by a newline, except that if any of the keys of the ALIST evenly
divide the current integer, then the corresponding string value(s)
of the key(s) dividing the current integer will be printed instead
of the integer itself. If multiple keys divide the current
integer, all of the corresponding string values will be printed,
in the same order as the elements of the ALIST. Only one copy
of any string value will be printed for any current integer."

I think most commercial Lisp compilers would accept that. if you are 
stuck with a "free" Lisp, try:

(defun fbuzz (n subs)
   (loop for i below n
         do (print (or
                     (loop for (d . sub) in subs
                        when (zerop (mod i d))
                        collect sub into chat
                        finally
                          (when chat
                             (return (apply 'concatenate 'string chat))))
                     i))))

kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <7_BFh.1$5b1.0@newsfe12.lga>
Ken Tilton wrote:
> 
> 
> Rob Warnock wrote:
> 
>> Ken Tilton  <·········@gmail.com> wrote:
>> +---------------
>> | ps. Me, I am not starting until we get the functional requirements | 
>> cleared up. k
>> +---------------
>>
>> See my reply to <········@gmail.com>'s MOD-free code-generating macro,
>> or take this instead:
>>
>>     Macro DEF-FIZZ-BUZZ  -- Define a "fizz-buzz"-generating function
>>
>>     Syntax:
>>     def-fizz-buzz fname alist ==> fname
>>
>>     Arguments and Values:
>>     fname -- A symbol, the name of the function to be defined (as by 
>> DEFUN).
>>
>>     alist -- an association list, whose keys are prime integers > 1
>>          and whose values are strings.
>>
>>     Description:
>>
>>     DEF-FIZZ-BUZZ defines a function named FNAME of one argument,
> 
> 
> er, two?
> 
>>     a positive integer. When called with an argument (say) N, FNAME
>>     will print each positive integer starting with 1
> 
> 
> I am concerned that we are misunderstanding each other, since 1 would 
> never be divisible by any prime integer > 1.
> 
>> ... below N,
> 
> 
> Did you mean "to N"? I ask only because that was the original spec and 
> it sounded inclusive and I have not seen anything necessitating a 
> change. Just want to make sure that was intended.
> 
>> followed
>>     by a newline, except that if any of the keys of the ALIST evenly
>>     divide the current integer, then the corresponding string value(s)
>>     of the key(s) dividing the current integer will be printed instead
>>     of the integer itself. Note: If multiple keys divide the current
>>     integer, all of the corresponding string values will be printed,
>>     in the same order as the elements of the ALIST. Only one copy
>>     of any string value will be printed for any current integer.
>>
>>     Examples:
>>
>>     (def-fizz-buzz 'fizz-buzz '((3 . "Fizz") (5 . "Buzz"))) ==> FIZZ-BUZZ
>>
>>     (fizz-buzz 22)
>>     >> 1
>>     >> 2
>>     >> Fizz
>>     >> 4
>>     >> Buzz
>>     >> Fizz
>>     >> 7
>>     >> 8
>>     >> Fizz
>>     >> Buzz
>>     >> 11
>>     >> Fizz
>>     >> 13
>>     >> 14
>>     >> FizzBuzz
>>     >> 16
>>     >> 17
>>     >> Fizz
>>     >> 19
>>     >> Buzz
>>     >> Fizz
>>     >> 22
>>     ==> NIL
>>
>>     (def-fizz-buzz 'very-fizzy
>>            '((2 . "Burp") (3 . "Fizz") (5 . "Buzz") (7 . "Bang")))
>>     ==> VERY-FIZZY
>>
>>     (very-fizzy 16)
>>     >> 1
>>     >> Burp
>>     >> Fizz
>>     >> Burp
>>     >> Buzz
>>     >> BurpFizz
>>     >> Bang
>>     >> Burp
>>     >> Fizz
>>     >> BurpBuzz
>>     >> 11
>>     >> BurpFizz
>>     >> 13
>>     >> BurpBang
>>     >> FizzBuzz
>>     >> Burp
>>     ==> NIL
>>
>> There's your spec. Where's your code?  ;-}
> 
> 
> Hunh? Right here:
> 
> "...print each positive integer starting with 1 below N, followed
> by a newline, except that if any of the keys of the ALIST evenly
> divide the current integer, then the corresponding string value(s)
> of the key(s) dividing the current integer will be printed instead
> of the integer itself. If multiple keys divide the current
> integer, all of the corresponding string values will be printed,
> in the same order as the elements of the ALIST. Only one copy
> of any string value will be printed for any current integer."
> 
> I think most commercial Lisp compilers would accept that. if you are 
> stuck with a "free" Lisp, try:
> 
> (defun fbuzz (n subs)
>   (loop for i below n

oops, "from 1"

And here is the less functional version:

(defun fbuzz2 (n subs)
   (loop for i from 1 below n
       do (loop with printed
              for (d . sub) in subs
              when (zerop (mod i d))
              do (setf printed t)
              (princ sub)
              finally (unless printed (princ i))
                (terpri))))

I just hate SETF. Which reminds me:

(defmd xlater ()
   xlates
   (xlation (c? (bwhen (v (^value))
                  (loop for (d . sub) in (^xlates)
                      when (zerop (mod v d))
                      collect sub))))
   (view (c? (bif (xl (^xlation))
               (apply 'concatenate 'string xl)
               (^value)))))

(defobserver view ((self xlater))
   (when new-value (print new-value)))

Test:

(loop with xl = (make-instance 'xlater
                   :value (c-in nil)
                   :xlates '((3 . "Fizz")(5 . "Buzz")))
       for n from 1 below 20
       do (setf (value xl) n))

Damn setf.

kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: ········@gmail.com
Subject: Re: A style question
Date: 
Message-ID: <1172798475.913365.110900@31g2000cwt.googlegroups.com>
Rob Warnock wrote:
> Ken Tilton  <·········@gmail.com> wrote:
> +---------------
> | ps. Me, I am not starting until we get the functional requirements
> | cleared up. k
> +---------------
>
> See my reply to <········@gmail.com>'s MOD-free code-generating macro,
> or take this instead:
>
>     Macro DEF-FIZZ-BUZZ  -- Define a "fizz-buzz"-generating function
>
>     Syntax:
>     def-fizz-buzz fname alist ==> fname
>
>     Arguments and Values:
>     fname -- A symbol, the name of the function to be defined (as by DEFUN).
>
>     alist -- an association list, whose keys are prime integers > 1
> 	     and whose values are strings.
>
>     Description:
>
>     DEF-FIZZ-BUZZ defines a function named FNAME of one argument,
>     a positive integer. When called with an argument (say) N, FNAME
>     will print each positive integer starting with 1 below N, followed
>     by a newline, except that if any of the keys of the ALIST evenly
>     divide the current integer, then the corresponding string value(s)
>     of the key(s) dividing the current integer will be printed instead
>     of the integer itself. Note: If multiple keys divide the current
>     integer, all of the corresponding string values will be printed,
>     in the same order as the elements of the ALIST. Only one copy
>     of any string value will be printed for any current integer.
>
>     Examples:
>
>     (def-fizz-buzz 'fizz-buzz '((3 . "Fizz") (5 . "Buzz"))) ==> FIZZ-BUZZ
>
>     (fizz-buzz 22)
>     >> 1
>     >> 2
>     >> Fizz
>     >> 4
>     >> Buzz
>     >> Fizz
>     >> 7
>     >> 8
>     >> Fizz
>     >> Buzz
>     >> 11
>     >> Fizz
>     >> 13
>     >> 14
>     >> FizzBuzz
>     >> 16
>     >> 17
>     >> Fizz
>     >> 19
>     >> Buzz
>     >> Fizz
>     >> 22
>     ==> NIL
>
>     (def-fizz-buzz 'very-fizzy
> 		   '((2 . "Burp") (3 . "Fizz") (5 . "Buzz") (7 . "Bang")))
>     ==> VERY-FIZZY
>
>     (very-fizzy 16)
>     >> 1
>     >> Burp
>     >> Fizz
>     >> Burp
>     >> Buzz
>     >> BurpFizz
>     >> Bang
>     >> Burp
>     >> Fizz
>     >> BurpBuzz
>     >> 11
>     >> BurpFizz
>     >> 13
>     >> BurpBang
>     >> FizzBuzz
>     >> Burp
>     ==> NIL
>
> There's your spec. Where's your code?  ;-}

ok, here ya go...

(defmacro def-fizz-buzz (name alist)
  (let (l
	(lcd (reduce #'* alist :key #'first)))
    (do ((n 1 (incf n)))
	((> n lcd))
      (push '(terpri) l)
      (let ((old l))
	(dolist (a alist)
	  (when (zerop (mod n (first a)))
	    (push `(princ ,(rest a)) l)))
	(when (eq l old)
	  (push '(princ y) l)))
      (push '(when (> (incf y) x) (return)) l))
    `(defun ,name (x)
      (let ((y 1))
	(loop ,@(nreverse l))))))


CL-USER> (macroexpand-1 '(def-fizz-buzz very-fizzy ((2 . "Burp") (3 .
"Fizz") (5 . "Buzz"))))
(DEFUN VERY-FIZZY (X)
 (LET ((Y 1))
  (LOOP (TERPRI)
	(PRINC Y)
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Fizz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Buzz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(PRINC "Fizz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC Y)
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Fizz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(PRINC "Buzz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC Y)
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(PRINC "Fizz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC Y)
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI) (PRINC "Burp")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI) (PRINC "Fizz")
	(PRINC "Buzz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI) (PRINC Y)
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(PRINC "Fizz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC Y)
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(PRINC "Buzz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Fizz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC Y)
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(PRINC "Fizz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Buzz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Fizz")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC Y)
	(WHEN (> (INCF Y) X) (RETURN))
	(TERPRI)
	(PRINC "Burp")
	(PRINC "Fizz")
	(PRINC "Buzz")
	(WHEN (> (INCF Y) X) (RETURN)))))
T
CL-USER>
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <mk9Fh.809$8j.132@newsfe12.lga>
·············@craigslist.org wrote:
> ·············@craigslist.org wrote:
> 
>> def fizz_buzz n
>>   1.upto(n) do |i|
>>     print "Fizz" if fizz = (i % 3) == 0
>>     print "Buzz" if buzz = (i % 5) == 0
>>     puts fizz || buzz ? "" : i
>>   end
>> end
>>
>> fizz_buzz 100
>>
>> (defun fizz-buzz (n)
>>   (do ((i 1 (+ i 1)))
>>     ((> i n))
>>     (let
>>       ((fizz (= 0 (mod i 3)))
>>        (buzz (= 0 (mod i 5))))
>>       (if fizz (format t "Fizz"))
>>       (if buzz (format t "Buzz"))
>>       (format t "~A~%"
>>               (if (or fizz buzz) "" i)))))
>>
>> (fizz-buzz 100)
> 
> 
> Another friend of mine commenting on the same FizzBuzz thread supplied 
> the following Python code. It certainly is concise:
> 
> for i in xrange(1,101):
>   print(str(i), "Fizz", "Buzz", "FizzBuzz")[(i%3==0)|(i%5==0)<<1]

But this is a programming disaster, stupid pet trick atop stupid pet 
trick. It collapses in a heap the minute anything changes. It builds 
into itself all sorts of things that just happen to be true. You have 
missed that what I am driving at is good programming, you are caught up 
in cleverness, the road to hell in programming.

Let me help you. If, as it seems, the spec is that FizzBuzz is not 
accidentally Fizz and Buzz together, then the strings Fizz and Buzz must 
appear only once in the program, as must the tests (mod x 3) and (mod x 5).

The punch line is that no good programmer could write anything in five 
minutes, unless the instructions included: "Just frickin make these 
results appear from this input."

kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Brian Adkins
Subject: Re: A style question
Date: 
Message-ID: <p6aFh.35598$p9.19111@bignews7.bellsouth.net>
Ken Tilton wrote:
> ·············@craigslist.org wrote:
>> ·············@craigslist.org wrote:
>> Another friend of mine commenting on the same FizzBuzz thread supplied 
>> the following Python code. It certainly is concise:
>>
>> for i in xrange(1,101):
>>   print(str(i), "Fizz", "Buzz", "FizzBuzz")[(i%3==0)|(i%5==0)<<1]
> 
> But this is a programming disaster, stupid pet trick atop stupid pet 
> trick. It collapses in a heap the minute anything changes. It builds 
> into itself all sorts of things that just happen to be true. You have 
> missed that what I am driving at is good programming, you are caught up 
> in cleverness, the road to hell in programming.

Agreed. Don't read too much into "It certainly is concise." My statement 
was intentionally terse.

In the context of the "FizzBuzz" toy example, it can be fun to look at 
some clever code, but don't infer that I'm "caught up in cleverness". In 
fact, I've counseled countless coders to comprehend the concealed costs 
of clever code.  *ducks*

> Let me help you. If, as it seems, the spec is that FizzBuzz is not 
> accidentally Fizz and Buzz together, then the strings Fizz and Buzz must 
> appear only once in the program, as must the tests (mod x 3) and (mod x 5).

I feel the same way; I guess my original Lisp hack wasn't so terrible - 
a couple 'o mods and a couple 'o strings. Incorporating some of the 
feedback from the group gives the following:

(defun fizz-buzz (n)
   (do ((i 1 (+ i 1))) ((> i n))
     (let
       ((fizz (zerop (mod i 3)))
        (buzz (zerop (mod i 5))))
       (when fizz (princ "Fizz"))
       (when buzz (princ "Buzz"))
       (format t "~A~%" (if (or fizz buzz) "" i)))))

(fizz-buzz 100)

Now on to chapter 3 "Lists"  :)

> The punch line is that no good programmer could write anything in five 
> minutes, unless the instructions included: "Just frickin make these 
> results appear from this input."
> 
> kt
> 
From: Rainer Joswig
Subject: Re: A style question
Date: 
Message-ID: <joswig-39587D.09241428022007@news-europe.giganews.com>
In article <····················@bignews7.bellsouth.net>,
 Brian Adkins <·····@lojic.com> wrote:

> Ken Tilton wrote:
> > ·············@craigslist.org wrote:
> >> ·············@craigslist.org wrote:
> >> Another friend of mine commenting on the same FizzBuzz thread supplied 
> >> the following Python code. It certainly is concise:
> >>
> >> for i in xrange(1,101):
> >>   print(str(i), "Fizz", "Buzz", "FizzBuzz")[(i%3==0)|(i%5==0)<<1]
> > 
> > But this is a programming disaster, stupid pet trick atop stupid pet 
> > trick. It collapses in a heap the minute anything changes. It builds 
> > into itself all sorts of things that just happen to be true. You have 
> > missed that what I am driving at is good programming, you are caught up 
> > in cleverness, the road to hell in programming.
> 
> Agreed. Don't read too much into "It certainly is concise." My statement 
> was intentionally terse.
> 
> In the context of the "FizzBuzz" toy example, it can be fun to look at 
> some clever code, but don't infer that I'm "caught up in cleverness". In 
> fact, I've counseled countless coders to comprehend the concealed costs 
> of clever code.  *ducks*
> 
> > Let me help you. If, as it seems, the spec is that FizzBuzz is not 
> > accidentally Fizz and Buzz together, then the strings Fizz and Buzz must 
> > appear only once in the program, as must the tests (mod x 3) and (mod x 5).
> 
> I feel the same way; I guess my original Lisp hack wasn't so terrible - 
> a couple 'o mods and a couple 'o strings. Incorporating some of the 
> feedback from the group gives the following:
> 
> (defun fizz-buzz (n)
>    (do ((i 1 (+ i 1))) ((> i n))
>      (let
>        ((fizz (zerop (mod i 3)))
>         (buzz (zerop (mod i 5))))
>        (when fizz (princ "Fizz"))
>        (when buzz (princ "Buzz"))
>        (format t "~A~%" (if (or fizz buzz) "" i)))))

In DO you can have more than one clauses for iteration.
So you could get rid of the extra LET.

> 
> (fizz-buzz 100)
> 
> Now on to chapter 3 "Lists"  :)
> 
> > The punch line is that no good programmer could write anything in five 
> > minutes, unless the instructions included: "Just frickin make these 
> > results appear from this input."
> > 
> > kt
> >
From: lojic
Subject: Re: A style question
Date: 
Message-ID: <1172716443.463124.193390@t69g2000cwt.googlegroups.com>
On Feb 28, 3:24 am, Rainer Joswig <······@lisp.de> wrote:
> > (defun fizz-buzz (n)
> >    (do ((i 1 (+ i 1))) ((> i n))
> >      (let
> >        ((fizz (zerop (mod i 3)))
> >         (buzz (zerop (mod i 5))))
> >        (when fizz (princ "Fizz"))
> >        (when buzz (princ "Buzz"))
> >        (format t "~A~%" (if (or fizz buzz) "" i)))))
>
> In DO you can have more than one clauses for iteration.
> So you could get rid of the extra LET.

Isn't let required to set the fizz and buzz local vars within the
loop?

Brian
From: =?ISO-8859-15?Q?Andr=E9_Thieme?=
Subject: Re: A style question
Date: 
Message-ID: <es45kv$j6p$1@registered.motzarella.org>
·············@craigslist.org schrieb:

> Another friend of mine commenting on the same FizzBuzz thread supplied 
> the following Python code. It certainly is concise:
> 
> for i in xrange(1,101):
>   print(str(i), "Fizz", "Buzz", "FizzBuzz")[(i%3==0)|(i%5==0)<<1]
> 
> Forgive my ignorance, but is anything like the boolean bit shifting 
> technique used in the Python code above possible in Lisp? No big loss if 
> it isn't, just curious.

In principle you could do exactly that - if you also provide this
strange shifting operator:

 >>> (11%3==0)|(11%5==0)
False
 >>> (12%3==0)|(12%5==0)
True
 >>> (20%3==0)|(20%5==0)
True
 >>> (30%3==0)|(30%5==0)
True


And:

 >>> False<<1
0
 >>> True<<1
2

Okay, so we expect << to throw out 0, 2, 2 and 2 for the three cases.
But:

 >>> (11%3==0)|(11%5==0)<<1
0
 >>> (12%3==0)|(12%5==0)<<1
1
 >>> (20%3==0)|(20%5==0)<<1
2
 >>> (30%3==0)|(30%5==0)<<1
3

It seems truth values would be structs in Lisp. They not only have a
boolean value of t or nil, but they also represent some number.

Anyway, let's say you provide <<, then you could say:

(loop for i upto 100 do
   (print (nth (<< (mod i 3) (mod i 5)) (list i "Fizz" "Buzz" "FizzBuzz")))

This version has now a smaller complexity with its 20 tokens as the
Python version with its 28 tokens.
Okay, if you count the definition of << in Lisp, then Python wins here,
because it already is defined there.


> I suppose it's unreasonable to expect the Lisp version to be as concise 
> as the Python version

No, it is reasonable. And as you see: Python is complexity wise 40% worse.


 > - not only is this a toy example, but I think a
> language with more syntax will be able to provide more brevity in 
> certain situations.

You are right. For people who are happy to write scripts Python will
be an excellent choice. Scripting is the domain of Python and usually
it will do very well with 10 line programs.
But if we are talking about something that goes beyond 3k LOC things
change. Then Lisp will have a more specialized syntax and win.
So it is the question of complexity. For easy problems Lisp will most
likely not be much better than Python - but probably also not worse.
But as complexity grows you are better off with Lisp.



> That's a tradeoff I'm willing to accept given the 
> benefits of a syntax that's more readily parsed and manipulated.

Clever choice.


Andr�
--
From: Lars Rune Nøstdal
Subject: Re: A style question
Date: 
Message-ID: <45e4e426$0$5388$c83e3ef6@nn1-read.tele2.net>
My first try:


(loop :for i :from 1 :upto 100
   :doing (cond
            ((= 0 (mod i 3) (mod i 5)) (write-line "FizzBuzz"))
            ((= 0 (mod i 3)) (write-line "Fizz"))
            ((= 0 (mod i 5)) (write-line "Buzz"))
            (t (format t "~A~%" i))))


..then..


(loop :for i :from 1 :upto 100
   :doing
   (let ((fizz-or-buzz nil))
     (when (= 0 (mod i 3)) (princ "Fizz") (setf fizz-or-buzz t))
     (when (= 0 (mod i 5)) (princ "Buzz") (setf fizz-or-buzz t))
     (unless fizz-or-buzz (princ i))
     (terpri)))


I suppose one could write a version of cond with a :when-no-clauses clause
or something to do some hiding. Maybe `loop' already has something? Well,
gonna try:


(defmacro cond* (&body body)
  `(let ((any-clause-p nil))
     ,@(mapcar (lambda (clause-form)
                 (if (eq :unless-till-now (first clause-form))
                     `(unless any-clause-p ,(second clause-form))
                     `(when ,(first clause-form)
                        ,(second clause-form)
                        (setf any-clause-p t))))
               body)))


(loop :for i :from 1 :upto 100
   :doing
   (cond*
     ((= 0 (mod i 3)) (princ "Fizz"))
     ((= 0 (mod i 5)) (princ "Buzz"))
     (:unless-till-now (princ i)))
   (terpri))


":unless-till-now" .. not sure about the name, but I'm thinking "unless
any clause has been true up to now". So it works in the middle too.

Now, hoping that I've not made too many mistakes; is there anyone who would
like to pay me to do tasks like this? :}


-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Lars Rune Nøstdal
Subject: Re: A style question
Date: 
Message-ID: <45e4e7d7$0$5388$c83e3ef6@nn1-read.tele2.net>
On Wed, 28 Feb 2007 02:08:39 +0000, Lars Rune Nøstdal wrote:

> (defmacro cond* (&body body)
>   `(let ((any-clause-p nil))


Yup; I forgot the gensym:


(defmacro cond* (&body body)
  (let ((any-clause-p (gensym)))
    `(let ((,any-clause-p nil))
       ,@(mapcar (lambda (clause-form)
                   (if (eq :unless-till-now (first clause-form))
                       `(unless ,any-clause-p ,(second clause-form))
                       `(when ,(first clause-form)
                          ,(second clause-form)
                          (setf ,any-clause-p t))))
                 body))))

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Alain Picard
Subject: Re: A style question
Date: 
Message-ID: <873b4momr9.fsf@memetrics.com>
Lars Rune Nøstdal <···········@gmail.com> writes:

> My first try:
>
>
> (loop :for i :from 1 :upto 100
>    :doing (cond
>             ((= 0 (mod i 3) (mod i 5)) (write-line "FizzBuzz"))
>             ((= 0 (mod i 3)) (write-line "Fizz"))
>             ((= 0 (mod i 5)) (write-line "Buzz"))
>             (t (format t "~A~%" i))))
>

Stylistic hint: you don't need all those keywords in there.
(loop for i from 1 ...  does just fine.

[Does anyone know where this bizarre habit of using keywords
for loop operators came from?  It seems relatively new.]

                        --ap
From: Lars Rune Nøstdal
Subject: Re: A style question
Date: 
Message-ID: <45ea0b3b$0$29074$c83e3ef6@nn1-read.tele2.net>
On Sat, 03 Mar 2007 17:38:02 +1100, Alain Picard wrote:

> Lars Rune Nøstdal <···········@gmail.com> writes:
> 
>> My first try:
>>
>>
>> (loop :for i :from 1 :upto 100
>>    :doing (cond
>>             ((= 0 (mod i 3) (mod i 5)) (write-line "FizzBuzz"))
>>             ((= 0 (mod i 3)) (write-line "Fizz"))
>>             ((= 0 (mod i 5)) (write-line "Buzz"))
>>             (t (format t "~A~%" i))))
>>
> 
> Stylistic hint: you don't need all those keywords in there.
> (loop for i from 1 ...  does just fine.

I am aware of this. However I very much prefer using keywords here because
I can easily separate stuff then. Emacs highlights keywords with a
different color making it even clearer.

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Lars Rune Nøstdal
Subject: Re: A style question
Date: 
Message-ID: <45ea0b66$0$29074$c83e3ef6@nn1-read.tele2.net>
On Sat, 03 Mar 2007 23:56:43 +0000, Lars Rune Nøstdal wrote:

> On Sat, 03 Mar 2007 17:38:02 +1100, Alain Picard wrote:
> 
>> Lars Rune Nøstdal <···········@gmail.com> writes:
>> 
>>> My first try:
>>>
>>>
>>> (loop :for i :from 1 :upto 100
>>>    :doing (cond
>>>             ((= 0 (mod i 3) (mod i 5)) (write-line "FizzBuzz"))
>>>             ((= 0 (mod i 3)) (write-line "Fizz"))
>>>             ((= 0 (mod i 5)) (write-line "Buzz"))
>>>             (t (format t "~A~%" i))))
>>>
>> 
>> Stylistic hint: you don't need all those keywords in there.
>> (loop for i from 1 ...  does just fine.
> 
> I am aware of this. However I very much prefer using keywords here because
> I can easily separate stuff then. Emacs highlights keywords with a
> different color making it even clearer.
>

What I should have done was use `zerop' though. :)

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Pascal Bourguignon
Subject: Re: A style question
Date: 
Message-ID: <87irdeaek6.fsf@voyager.informatimago.com>
Alain Picard <············@memetrics.com> writes:

> Lars Rune N�stdal <···········@gmail.com> writes:
>
>> My first try:
>>
>>
>> (loop :for i :from 1 :upto 100
>>    :doing (cond
>>             ((= 0 (mod i 3) (mod i 5)) (write-line "FizzBuzz"))
>>             ((= 0 (mod i 3)) (write-line "Fizz"))
>>             ((= 0 (mod i 5)) (write-line "Buzz"))
>>             (t (format t "~A~%" i))))
>>
>
> Stylistic hint: you don't need all those keywords in there.
> (loop for i from 1 ...  does just fine.
>
> [Does anyone know where this bizarre habit of using keywords
> for loop operators came from?  It seems relatively new.]

Apart from the special font-locking done by emacs on the keywords
mentionned by Lars, the point of using keywords in LOOP is to avoid
symbol name colision when, like me, you have a package that exports
macros named WHILE or UNTIL, that you may use (like in USE-PACKAGE)
after writting a LOOP.

Note that WHILE is NOT exported from CL, to the difference from LOOP
or DOLIST.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
        Un chat errant
se soulage
        dans le jardin d'hiver
                                        Shiki
From: Wade Humeniuk
Subject: Re: A style question
Date: 
Message-ID: <EM5Fh.756$Xi2.423@edtnps89>
Another style

(defun fbv (n)
   (or (remove nil (list (and (zerop (mod n 3)) "Fizz")
                         (and (zerop (mod n 5)) "Buzz")))
       (list n)))


(defun fizz-buzz (n)
   (loop for i from 1 to n do (format t "~{~A~}~%" (fbv i))))

Wade
From: Wade Humeniuk
Subject: Re: A style question
Date: 
Message-ID: <ah6Fh.765$Xi2.16@edtnps89>
Wade Humeniuk wrote:
> Another style
> 
> (defun fbv (n)
>   (or (remove nil (list (and (zerop (mod n 3)) "Fizz")
>                         (and (zerop (mod n 5)) "Buzz")))
>       (list n)))
> 
> 
> (defun fizz-buzz (n)
>   (loop for i from 1 to n do (format t "~{~A~}~%" (fbv i))))
> 
> Wade

And with a few macros,

;--- Part of a handy kit
(defun prinl (list)
   (map nil 'princ list)
   (terpri))

(defmacro over (i start end &body body)
   `(loop for ,i from ,start to ,end do ,@body))
(defmacro no-nulls (&body tests)
   `(remove nil (list ,@tests)))
;----------------------------------------------

(defun fbv (n)
   (or (no-nulls
         (and (zerop (mod n 3)) "Fizz")
         (and (zerop (mod n 5)) "Buzz"))
       (list n)))


(defun fizz-buzz (n)
   (over i 1 n (prinl (fbv i))))

Wade
From: Frank Buss
Subject: Re: A style question
Date: 
Message-ID: <63e7vwwonn0e.1g6qis0qakdp4$.dlg@40tude.net>
·············@craigslist.org wrote:

> I cranked out a Lisp version. It seems a bit clunky, so I thought I'd see 
> if anyone had suggestions for improvements.

looks ok, but I would use loop and organize the body of the loop a bit
different:

(defun fizz-buzz (n)
  (loop for i from 1 to n
        for fizz = (zerop (mod i 3))
        for buzz = (zerop (mod i 5)) do
        (when fizz (princ "Fizz"))
        (when buzz (princ "Buzz"))
        (when (not (or fizz buzz)) (princ i))
        (terpri)))

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: ·············@craigslist.org
Subject: Re: A style question
Date: 
Message-ID: <Yo5Fh.35097$p9.1892@bignews7.bellsouth.net>
Frank Buss wrote:
> ·············@craigslist.org wrote:
> 
>> I cranked out a Lisp version. It seems a bit clunky, so I thought I'd see 
>> if anyone had suggestions for improvements.
> 
> looks ok, but I would use loop and organize the body of the loop a bit
> different:
> 
> (defun fizz-buzz (n)
>   (loop for i from 1 to n
>         for fizz = (zerop (mod i 3))
>         for buzz = (zerop (mod i 5)) do
>         (when fizz (princ "Fizz"))
>         (when buzz (princ "Buzz"))
>         (when (not (or fizz buzz)) (princ i))
>         (terpri)))
> 

Thanks. Some questions/comments:

1) In "ANSI Common Lisp", Graham makes the following comments:
    "The loop macro was originally designed to help inexperienced Lisp 
users write iterative code...Unfortunately, loop is more like English 
than its designers ever intended...to understand it in the abstract is 
almost impossible...For such reasons, the use of loop cannot be 
recommended."

    Is this a minority view? One of the things that attracted me to Lisp 
was the simplicity, consistency, etc. of the language, so when I read 
the above, it seemed reasonable.

2) Thanks for the zerop tip. I like (zerop (mod m n)) better than (= 0 
(mod m n))

3) Any reason why you chose (when fizz (princ "Fizz")) instead of (if 
fizz (princ "Fizz")) ?

4) Curious about the history of "terpri" - I guess it's shorter than 
"newline" but not very intuitive :)

I'm really enjoying learning Lisp. I realize at this stage I still have 
some "the grass is greener" and "oh cool, something new to learn!" 
influences, but I expect as that wears off the merits of the language 
will continue to shine through.

Brian
From: Pillsy
Subject: Re: A style question
Date: 
Message-ID: <1172630308.076388.326110@t69g2000cwt.googlegroups.com>
On Feb 27, 9:02 pm, ·············@craigslist.org wrote:
[...]
> Thanks. Some questions/comments:

> 1) In "ANSI Common Lisp", Graham makes the following comments:

>     "The loop macro was originally designed to help inexperienced
> Lisp users write iterative code...Unfortunately, loop is more like
> English than its designers ever intended...to understand it in the
> abstract is almost impossible...For such reasons, the use of loop
> cannot be recommended."

>     Is this a minority view?

I think it is. I cordially despise LOOP myself, but almost everyone
uses it for simple stuff some of the time. You can avoid it entirely
if you want, but it can make your life unneccessarily difficult do.

You should spend some time becoming familiar with it. At the very
least, you need a basic understanding to read other people's
code. Then you can make an informed decision to avoid it. :)

> One of the things that attracted me to Lisp was the simplicity,
> consistency, etc. of the language, so when I read the above, it
> seemed reasonable.

Common Lisp is in some ways simple, and pretty consistent, but it's
also huge and not particularly "pure". Personally, I like the sense of
compromise and age.

Others prefer Scheme, which is a different dialect of Lisp which is
all about being small and elegant and pure. I find it sterile and
spare and unfun myself.

> 3) Any reason why you chose (when fizz (princ "Fizz")) instead of (if
> fizz (princ "Fizz")) ?

It's a little bit of Common Lisp style. If you are only going to use
the true branch of the conditional, use "when", and if you're only
going to use the false branch, use "unless".

Hope you continue to have fun.

Cheers,
Pillsy
From: GP lisper
Subject: Re: A style question
Date: 
Message-ID: <slrneua0cu.38t.spambait@phoenix.clouddancer.com>
On 27 Feb 2007 18:38:28 -0800, <·········@gmail.com> wrote:
> On Feb 27, 9:02 pm, ·············@craigslist.org wrote:
>
>>     "The loop macro was originally designed to help inexperienced
>> Lisp users write iterative code...Unfortunately, loop is more like
>> ...
>
>>     Is this a minority view?
>
> I think it is. I cordially despise LOOP myself, but almost everyone
> uses it...
>
> You should spend some time becoming familiar with it.

When I needed to learn loop, I found that by reading the chapter in
Common Lisp, the Language I gained the best understanding.

Loop is a Domain Specific Language, something that many loop haters
overlook, as they will also cheer DSLs as a Lisp strength.

-- 
There are no average Common Lisp programmers
Reply-To: email is ignored.

-- 
Posted via a free Usenet account from http://www.teranews.com
From: Pillsy
Subject: Re: A style question
Date: 
Message-ID: <1172664913.523142.219990@a75g2000cwd.googlegroups.com>
On Feb 27, 11:14 pm, GP lisper <········@CloudDancer.com> wrote:
[...]
> Loop is a Domain Specific Language, something that many loop haters
> overlook, as they will also cheer DSLs as a Lisp strength.

Oh, I know it's a DSL. I just think it's a crappy DSL. ITERATE is the
same sort of DSL, but is much better---easier for editors to indent
right, Lispy looking, and straightforward to extend with macros.

Cheers,
Pillsy
From: Vassil Nikolov
Subject: Re: A style question
Date: 
Message-ID: <yy8v4pp7m0dm.fsf@eskimo.com>
On Tue, 27 Feb 2007 21:02:46 -0500, ·············@craigslist.org said:
|...
| 1) In "ANSI Common Lisp", Graham makes the following comments:
|     "The loop macro was originally designed to help inexperienced Lisp 
| users write iterative code...Unfortunately, loop is more like English 
| than its designers ever intended...to understand it in the abstract is 
| almost impossible...For such reasons, the use of loop cannot be 
| recommended."

|     Is this a minority view? One of the things that attracted me to Lisp 
| was the simplicity, consistency, etc. of the language, so when I read 
| the above, it seemed reasonable.

  Gain experience with Common Lisp; in particular, learn (in alphabetical
  order) DO, DOLIST, DOTIMES, and LOOP.  Use them and see how others have
  used them.  Then form your own opinion.


| ...
| 4) Curious about the history of "terpri" - I guess it's shorter than 
| "newline" but not very intuitive :)

  Interesting---I was checking how googlable that was, and it turns out
  there is even http://terpri.org/ (q.v.).

  ---Vassil.

-- 
mind mate, n.
  One of two persons mentally compatible with each other (cf. soul mate).
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <3w6Fh.794$8j.514@newsfe12.lga>
·············@craigslist.org wrote:
> Frank Buss wrote:
> 
>> ·············@craigslist.org wrote:
>>
>>> I cranked out a Lisp version. It seems a bit clunky, so I thought I'd 
>>> see if anyone had suggestions for improvements.
>>
>>
>> looks ok, but I would use loop and organize the body of the loop a bit
>> different:
>>
>> (defun fizz-buzz (n)
>>   (loop for i from 1 to n
>>         for fizz = (zerop (mod i 3))
>>         for buzz = (zerop (mod i 5)) do
>>         (when fizz (princ "Fizz"))
>>         (when buzz (princ "Buzz"))
>>         (when (not (or fizz buzz)) (princ i))
>>         (terpri)))
>>
> 
> Thanks. Some questions/comments:
> 
> 1) In "ANSI Common Lisp", Graham makes the following comments:
>    "The loop macro was originally designed to help inexperienced Lisp 
> users write iterative code...Unfortunately, loop is more like English 
> than its designers ever intended...to understand it in the abstract is 
> almost impossible...For such reasons, the use of loop cannot be 
> recommended."
> 
>    Is this a minority view? One of the things that attracted me to Lisp 
> was the simplicity, consistency, etc. of the language, so when I read 
> the above, it seemed reasonable.

I was anti-loop bigot for years, now I cannot even remember the syntax 
of dolist. PG is a closet Schemer. Look at Arc. Pure minimalist. He does 
not like CLOS either. Now it may be that /you/ are a latent Schemer and 
that would be fine, but the spirit of Common Lisp is the more mud the 
better. LOOP rocks.

> 
> 2) Thanks for the zerop tip. I like (zerop (mod m n)) better than (= 0 
> (mod m n))
> 
> 3) Any reason why you chose (when fizz (princ "Fizz")) instead of (if 
> fizz (princ "Fizz")) ?
> 
> 4) Curious about the history of "terpri" - I guess it's shorter than 
> "newline" but not very intuitive :)
> 
> I'm really enjoying learning Lisp. I realize at this stage I still have 
> some "the grass is greener" and "oh cool, something new to learn!" 
> influences, but I expect as that wears off the merits of the language 
> will continue to shine through.

It does not wear off:

    http://wiki.alu.org/RtL_Highlight_Film

Now get to work:

    http://wiki.alu.org/The_Road_to_Lisp_Survey

Anybody want to let me know about Roads they have added over the past 
years that never made it to the highlight film? I mean, it /is/ a wiki, 
but I would be happy to play editor and pick out the sound bites from 
anyone not yet in the highlight film.

kzo

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: JK
Subject: Re: A style question
Date: 
Message-ID: <45e89d5d$0$16693$4c368faf@roadrunner.com>
Ken Tilton wrote:

[scissors of brevity]

> I was anti-loop bigot for years, now I cannot even remember the syntax 
> of dolist. PG is a closet Schemer. Look at Arc. Pure minimalist. He does 
> not like CLOS either. Now it may be that /you/ are a latent Schemer and 
> that would be fine, but the spirit of Common Lisp is the more mud the 
> better. LOOP rocks.

I put off learning LOOP for a long while, based on PG's assessment.
I wrote iteration almost exclusively using recursion, due to long
exposure to Prolog and some Scheme; and I find DO to be unreadable.
Last weekend I learned LOOP just for the hell of it while writing
a dinky little app, and damn if it isn't like crack -- I can't
stop using it now!  Every time I want to iterate, a LOOP form just
pops into my brain.

I was a little concerned about the efficiency of the code generated
by LOOP, but it seems to all be TAGBODYs and GOs (at least in CLISP),
which intuitively seems more efficient both speed- and space-wise
than the recursive loops I used to write. (Though I'm aware intuition
isn't necessarily a reliable guide to such things.)

-- JK
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <OV1Gh.219$ZB6.74@newsfe12.lga>
JK wrote:
> Ken Tilton wrote:
> 
> [scissors of brevity]
> 
>> I was anti-loop bigot for years, now I cannot even remember the syntax 
>> of dolist. PG is a closet Schemer. Look at Arc. Pure minimalist. He 
>> does not like CLOS either. Now it may be that /you/ are a latent 
>> Schemer and that would be fine, but the spirit of Common Lisp is the 
>> more mud the better. LOOP rocks.
> 
> 
> I put off learning LOOP for a long while, based on PG's assessment.
> I wrote iteration almost exclusively using recursion, due to long
> exposure to Prolog and some Scheme; and I find DO to be unreadable.
> Last weekend I learned LOOP just for the hell of it while writing
> a dinky little app, and damn if it isn't like crack -- I can't
> stop using it now!  Every time I want to iterate, a LOOP form just
> pops into my brain.

Don't know how quick a study you are, but wait until you have it down 
code and can toss off a thereis without thinking twice, or do on vs. (in 
vs. across) without thinking! I guess there some Mavis Beacon showoffs 
out there who just forever typing lambda, not me.

> 
> I was a little concerned about the efficiency of the code generated
> by LOOP, but it seems to all be TAGBODYs and GOs (at least in CLISP),
> which intuitively seems more efficient both speed- and space-wise
> than the recursive loops I used to write. (Though I'm aware intuition
> isn't necessarily a reliable guide to such things.)

Actually, that is a big part of what turned me on to LOOP. I am pretty 
sure it expands into pretty optimal code. eg, collect keeping a record 
of the tail so not even a final nreverse is needed. And of course it 
makes sense that they would do it that way since it was menat to be a 
language extension.

kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Tim Bradshaw
Subject: Re: A style question
Date: 
Message-ID: <1172658813.746823.247380@p10g2000cwp.googlegroups.com>
On Feb 28, 2:02 am, ·············@craigslist.org wrote:

>
> 1) In "ANSI Common Lisp", Graham makes the following comments:
>     "The loop macro was originally designed to help inexperienced Lisp
> users write iterative code...Unfortunately, loop is more like English
> than its designers ever intended...to understand it in the abstract is
> almost impossible...For such reasons, the use of loop cannot be
> recommended."

Reading Paul Graham is a bit like reading reviews of films by a good
critic: he is almost always wrong about everything, but has
interesting things to say and it's possible to reliably predict
whether you'll like something from what he says about it (though often
you will differ from him on whether you like it, due to the above-
mentioned almost-always-being-wrong thing).  He's kind of the Barry
Norman of Lisp, really.

>
>     Is this a minority view? One of the things that attracted me to Lisp
> was the simplicity, consistency, etc. of the language, so when I read
> the above, it seemed reasonable.

Simplicity? consistency?  I think you're thinking of some other
language there.  CL is this vast industrial thing full of enormous
machines, oil and rust.  Some compartments are full of water, and no
one knows what some of the machines do, if anything.  Many parts of it
use a mixture of Whitworth & BSF threads (some left-handed), though
much has now been converted to BA or metric, sometimes by use of taps
& dies, sometimes with a hammer.

CL's closest living relative is FORTRAN: always remember that.

Incidentally, I'm deeply disappointed in the quality of answers in
this thread.  In the elder days there would have been at least a few
followups showing how to do this in the proper "FORMAT string
indistinguishable from line noise" way.  No true CL programmer ever
uses any other construct when the problem can be solved with a
combination of FORMAT, LOOP & GO (FORMAT being always preferable,
obviously).  There may yet be those reading cll who know this, though
I suspect they have all gone into the west now.

--tim (who has used the FORMAT string mentioned in
http://www.tfeb.org/lisp/obscurities.html in anger)
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <f4fFh.5$M24.0@newsfe12.lga>
Tim Bradshaw wrote:
> On Feb 28, 2:02 am, ·············@craigslist.org wrote:
> 
> 
>>1) In "ANSI Common Lisp", Graham makes the following comments:
>>    "The loop macro was originally designed to help inexperienced Lisp
>>users write iterative code...Unfortunately, loop is more like English
>>than its designers ever intended...to understand it in the abstract is
>>almost impossible...For such reasons, the use of loop cannot be
>>recommended."
> 
> 
> Reading Paul Graham is a bit like reading reviews of films by a good
> critic: he is almost always wrong about everything, but has
> interesting things to say and it's possible to reliably predict
> whether you'll like something from what he says about it (though often
> you will differ from him on whether you like it, due to the above-
> mentioned almost-always-being-wrong thing).  He's kind of the Barry
> Norman of Lisp, really.
> 
> 
>>    Is this a minority view? One of the things that attracted me to Lisp
>>was the simplicity, consistency, etc. of the language, so when I read
>>the above, it seemed reasonable.
> 
> 
> Simplicity? consistency?  I think you're thinking of some other
> language there.  CL is this vast industrial thing full of enormous
> machines, oil and rust.  Some compartments are full of water, and no
> one knows what some of the machines do, if anything.  Many parts of it
> use a mixture of Whitworth & BSF threads (some left-handed), though
> much has now been converted to BA or metric, sometimes by use of taps
> & dies, sometimes with a hammer.
> 
> CL's closest living relative is FORTRAN: always remember that.
> 
> Incidentally, I'm deeply disappointed in the quality of answers in
> this thread.  In the elder days there would have been at least a few
> followups showing how to do this in the proper "FORMAT string
> indistinguishable from line noise" way.

Oh, absolutely, long overdue in this thread. Is this going to become a 
lost art? The village elders need to step up, methinks. I started 
playing with it, but I am just an elder, not a Lisp elder. Screams for a 
nested thingy, yes?

>  No true CL programmer ever
> uses any other construct when the problem can be solved with a
> combination of FORMAT, LOOP & GO (FORMAT being always preferable,
> obviously).  There may yet be those reading cll who know this, though
> I suspect they have all gone into the west now.

Well, I did not want to get morbid, but that is what I was thinking. As 
Lisp reaches fifty we can expect to see its legends start scrolling off 
the top of the screen.

kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Pillsy
Subject: Re: A style question
Date: 
Message-ID: <1172692882.062996.129900@m58g2000cwm.googlegroups.com>
On Feb 28, 8:03 am, Ken Tilton <·········@gmail.com> wrote:
> Tim Bradshaw wrote:
[...]
> > Incidentally, I'm deeply disappointed in the quality of answers in
> > this thread.  In the elder days there would have been at least a few
> > followups showing how to do this in the proper "FORMAT string
> > indistinguishable from line noise" way.

> Oh, absolutely, long overdue in this thread. Is this going to become a
> lost art? The village elders need to step up, methinks. I started
> playing with it, but I am just an elder, not a Lisp elder. Screams for a
> nested thingy, yes?

Well, if you're going to throw down the gauntlet like that, I'm
just going to have to respond in the hopes of provoking someone
into besting my wimpy attempt.

(apply #'format t ··@{ ··@{~D ~}~^~*Fizz ~D ~*Buzz~
                       ~*Fizz ··@{~D ~} ~*Buzz ~D ~*Fizz~
                       ··@{~D ~} ~*FizzBuzz ~%~}"
       (loop
	  :for i :from 1 to 100
	  :collect i))

Cheers,
Pillsy
From: Vassil Nikolov
Subject: Re: A style question
Date: 
Message-ID: <yy8vfy8peear.fsf@eskimo.com>
On 28 Feb 2007 12:01:22 -0800, "Pillsy" <·········@gmail.com> said:
| ...
| (apply #'format t ··@{ ··@{~D ~}~^~*Fizz ~D ~*Buzz~
|                        ~*Fizz ··@{~D ~} ~*Buzz ~D ~*Fizz~
|                        ··@{~D ~} ~*FizzBuzz ~%~}"
|        (loop
| 	  :for i :from 1 to 100
| 	  :collect i))

  But you want it to work for arbitrarily large values of 100...

  ---Vassil.


-- 
mind mate, n.
  One of two persons mentally compatible with each other (cf. soul mate).
From: Pillsy
Subject: Re: A style question
Date: 
Message-ID: <1172779447.740551.126280@30g2000cwc.googlegroups.com>
On Mar 1, 12:14 am, Vassil Nikolov <···············@pobox.com> wrote:
> On 28 Feb 2007 12:01:22 -0800, "Pillsy" <·········@gmail.com> said:

> | ...
> | (apply #'format t ··@{ ··@{~D ~}~^~*Fizz ~D ~*Buzz~
> |                        ~*Fizz ··@{~D ~} ~*Buzz ~D ~*Fizz~
> |                        ··@{~D ~} ~*FizzBuzz ~%~}"
> |        (loop
> |         :for i :from 1 to 100
> |         :collect i))

>   But you want it to work for arbitrarily large values of 100...

Good point!

(setf (symbol-value '|100|) 100)

(defun fb (stream arg colonp atsignp)
  (declare (ignore arg colonp atsignp))
  (incf *count*)
  (format stream "~[Fizz~[Buzz~:;~]~^~:;~[Buzz~^~:;~D~]~]"
	  (mod *count* 3) (mod *count* 5) *count*))

(let ((*count* 0))
  (format t "~v{~/fb/~%~}" |100| '#1=((). #1#)))

And I think this one actually works, too! :D

Cheers, Pillsy
From: Pillsy
Subject: Re: A style question
Date: 
Message-ID: <1172779584.160263.249830@31g2000cwt.googlegroups.com>
On Mar 1, 3:04 pm, "Pillsy" <·········@gmail.com> wrote:
> On Mar 1, 12:14 am, Vassil Nikolov <···············@pobox.com> wrote:
>
> > On 28 Feb 2007 12:01:22 -0800, "Pillsy" <·········@gmail.com> said:
> > | ...
> > | (apply #'format t ··@{ ··@{~D ~}~^~*Fizz ~D ~*Buzz~
> > |                        ~*Fizz ··@{~D ~} ~*Buzz ~D ~*Fizz~
> > |                        ··@{~D ~} ~*FizzBuzz ~%~}"
> > |        (loop
> > |         :for i :from 1 to 100
> > |         :collect i))
> >   But you want it to work for arbitrarily large values of 100...
>
> Good point!
>
> (setf (symbol-value '|100|) 100)
>
> (defun fb (stream arg colonp atsignp)
>   (declare (ignore arg colonp atsignp))
>   (incf *count*)
>   (format stream "~[Fizz~[Buzz~:;~]~^~:;~[Buzz~^~:;~D~]~]"
>           (mod *count* 3) (mod *count* 5) *count*))
>
> (let ((*count* 0))
>   (format t "~v{~/fb/~%~}" |100| '#1=((). #1#)))
>
> And I think this one actually works, too! :D

Well, as long as I copy-and-paste right, and don't leave the

(defvar *count*)

out!

Cheers,
Pillsy
From: Vassil Nikolov
Subject: Re: A style question
Date: 
Message-ID: <yy8vodncgvpx.fsf@eskimo.com>
On 1 Mar 2007 12:06:24 -0800, "Pillsy" <·········@gmail.com> said:
|| On Mar 1, 12:14 am, Vassil Nikolov <···············@pobox.com> wrote:
|| 
|| > On 28 Feb 2007 12:01:22 -0800, "Pillsy" <·········@gmail.com> said:
|| > | ...
|| > | (apply #'format t ··@{ ··@{~D ~}~^~*Fizz ~D ~*Buzz~
|| > |                        ~*Fizz ··@{~D ~} ~*Buzz ~D ~*Fizz~
|| > |                        ··@{~D ~} ~*FizzBuzz ~%~}"
|| > |        (loop
|| > |         :for i :from 1 to 100
|| > |         :collect i))
|| >   But you want it to work for arbitrarily large values of 100...
|| 
|| Good point!
|| 
|| (setf (symbol-value '|100|) 100)

  Er, I was objecting to the use of APPLY (see also CALL-ARGUMENTS-LIMIT).

  ---Vassil.


-- 
mind mate, n.
  One of two persons mentally compatible with each other (cf. soul mate).
From: Pillsy
Subject: Re: A style question
Date: 
Message-ID: <1172869840.699151.270590@30g2000cwc.googlegroups.com>
On Mar 1, 10:39 pm, Vassil Nikolov <···············@pobox.com> wrote:
[...]
>   Er, I was objecting to the use of APPLY (see also CALL-ARGUMENTS-LIMIT).
>
>   ---Vassil.

Oh, I'm so used to SBCL I just always assume it's MOST-POSITIVE-
FIXNUM. Bad habit, I guess.

Cheers,
Pillsy
From: Rob Warnock
Subject: Re: A style question
Date: 
Message-ID: <zfSdnauewaJT03vYnZ2dnUVZ_vqpnZ2d@speakeasy.net>
Pillsy <·········@gmail.com> wrote:
+---------------
| Ken Tilton <·········@gmail.com> wrote:
| > Tim Bradshaw wrote:
| [...]
| > > Incidentally, I'm deeply disappointed in the quality of answers in
| > > this thread.  In the elder days there would have been at least a few
| > > followups showing how to do this in the proper "FORMAT string
| > > indistinguishable from line noise" way.
| 
| > Oh, absolutely, long overdue in this thread. Is this going to become a
| > lost art? The village elders need to step up, methinks. I started
| > playing with it, but I am just an elder, not a Lisp elder. Screams for a
| > nested thingy, yes?
| 
| Well, if you're going to throw down the gauntlet like that, I'm
| just going to have to respond in the hopes of provoking someone
| into besting my wimpy attempt.
| 
| (apply #'format t ··@{ ··@{~D ~}~^~*Fizz ~D ~*Buzz~
|                        ~*Fizz ··@{~D ~} ~*Buzz ~D ~*Fizz~
|                        ··@{~D ~} ~*FizzBuzz ~%~}"
|        (loop :for i :from 1 to 100 :collect i))
+---------------

Very cute!! Except... it doesn't give correct answers:

     1 2 Fizz 4 BuzzFizz 7 8  Buzz 10 Fizz12 13  FizzBuzz 
     15 16 Fizz 18 BuzzFizz 21 22  Buzz 24 Fizz26 27  FizzBuzz 
     29 30 Fizz 32 BuzzFizz 35 36  Buzz 38 Fizz40 41  FizzBuzz 
     43 44 Fizz 46 BuzzFizz 49 50  Buzz 52 Fizz54 55  FizzBuzz 
     57 58 Fizz 60 BuzzFizz 63 64  Buzz 66 Fizz68 69  FizzBuzz 
     71 72 Fizz 74 BuzzFizz 77 78  Buzz 80 Fizz82 83  FizzBuzz 
     85 86 Fizz 88 BuzzFizz 91 92  Buzz 94 Fizz96 97  FizzBuzz 
     99 100 

- Those "BuzzFizz" should probably be "Buzz Fizz" (missing space).
- Missing spaces elsewhere, too.
- 9 is divisible by 3, not 5.
- 11 is *not* divisible by either 3 or 5.
- 12 *is* divisible by 3.
- 14 is *not* divisible by 3.
- Etc. etc...


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Richard M Kreuter
Subject: Re: A style question
Date: 
Message-ID: <87tzx6jnol.fsf@progn.net>
"Tim Bradshaw" <··········@tfeb.org> writes:

> Incidentally, I'm deeply disappointed in the quality of answers in
> this thread.  In the elder days there would have been at least a few
> followups showing how to do this in the proper "FORMAT string
> indistinguishable from line noise" way.  No true CL programmer ever
> uses any other construct when the problem can be solved with a
> combination of FORMAT, LOOP & GO (FORMAT being always preferable,
> obviously).  There may yet be those reading cll who know this, though
> I suspect they have all gone into the west now.

(dotimes (i 100)
  (format t "~[~[FizzBuzz~:;Fizz~]~:;~[Buzz~:;~D~]~]~%" (mod i 3) (mod i 5) i))

Best I could do on one cup of coffee.

--
RmK
From: Tim Bradshaw
Subject: Re: A style question
Date: 
Message-ID: <1172681622.054814.266470@8g2000cwh.googlegroups.com>
On Feb 28, 3:40 pm, Richard M Kreuter <·······@progn.net> wrote:

> (dotimes (i 100)
>   (format t "~[~[FizzBuzz~:;Fizz~]~:;~[Buzz~:;~D~]~]~%" (mod i 3) (mod i 5) i))
>
> Best I could do on one cup of coffee.

Good, but you'd get extra points for avoiding the explicit FizzBuzz in
there.  Off the top of my head I think:
(format t "~&~[Fizz~;~]~[Buzz~;~D~]~%" (mod i 3) (mod i 5) i).  But
I'd have to check, and it's not really squiggly enough.

--tim
From: Richard M Kreuter
Subject: Re: A style question
Date: 
Message-ID: <87ps7uji6v.fsf@progn.net>
"Tim Bradshaw" <··········@tfeb.org> writes:

> On Feb 28, 3:40 pm, Richard M Kreuter <·······@progn.net> wrote:
>
>> (dotimes (i 100)
>>   (format t "~[~[FizzBuzz~:;Fizz~]~:;~[Buzz~:;~D~]~]~%" (mod i 3) (mod i 5) i))
>>
>> Best I could do on one cup of coffee.
>
> Good, but you'd get extra points for avoiding the explicit FizzBuzz in
> there.  Off the top of my head I think:
> (format t "~&~[Fizz~;~]~[Buzz~;~D~]~%" (mod i 3) (mod i 5) i).  But
> I'd have to check, and it's not really squiggly enough.

I think you mean "~&~[Fizz~:;~]~[Buzz~:;~D~]~%"  right?

Something like that was my first hunch, but it will print the integer
next to Fizz when (and (zerop (mod i 3)) (plusp (mod i 5))),

* (let ((i 6)) (format t "~&~[Fizz~:;~]~[Buzz~:;~D~]~%" (mod i 3) (mod i 5) i))
-| Fizz6
=> NIL
* (let ((i 9)) (format t "~&~[Fizz~:;~]~[Buzz~:;~D~]~%" (mod i 3) (mod i 5) i))
-| Fizz9
=> NIL

Here's one that avoids the explicit FizzBuzz, and adds /seven/
squiggles to my first stab:

(dotimes (i 100)
  (format t "~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~]~%"
          (mod i 3) (mod i 5) i "Fizz" "Buzz"))

Better?

--
RmK
From: John Thingstad
Subject: Re: A style question
Date: 
Message-ID: <op.tog0qguppqzri1@pandora.upc.no>
On Wed, 28 Feb 2007 18:38:48 +0100, Richard M Kreuter <·······@progn.net>  
wrote:

>
> (dotimes (i 100)
>   (format t "~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~]~%"
>           (mod i 3) (mod i 5) i "Fizz" "Buzz"))
>
> Better?
>

Perfect! I rivals Perl in clarity of exposition..

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Tim Bradshaw
Subject: Re: A style question
Date: 
Message-ID: <es4l3f$2tr$1$8300dec7@news.demon.co.uk>
On 2007-02-28 17:38:48 +0000, Richard M Kreuter <·······@progn.net> said:
> 
> I think you mean "~&~[Fizz~:;~]~[Buzz~:;~D~]~%"  right?

Probably, yes.

> 
> (dotimes (i 100)
>   (format t "~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~]~%"
>           (mod i 3) (mod i 5) i "Fizz" "Buzz"))
> 

Really good, yes.  Almost impossible to work out what it does.  The 
perfectionist in me would insist on

	"~&~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~]~%"

- you do actually want that so you know it always starts a line 
properly, apart from being an extra bit of squigglines.  But that's 
trivial compared to the main drag of it.

I'm unhappy about the explicit looping however.  I can see two 
solutions to this:

* something really gratuitous involving GO
* something equally gratuitous involving a lot of LAMBDAs.

I think I may be too rusty to write this, but something like:

(defun fb (n)
  ((lambda (c p)
     (funcall c c p 1)
   (lambda (c p i)
     (or (> i n)
	 (funcall p c p i)))
   (lambda (c p i)
     (format t "~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~]~%"
	     (mod i 3) (mod i 5) i "Fizz" "Buzz")
     (funcall c c p (1+ i))))))

(I should point out that I don't have a CL on the system I'm writing this.)

--tim
From: Richard M Kreuter
Subject: Re: A style question
Date: 
Message-ID: <87d53ujam7.fsf@progn.net>
Tim Bradshaw <···@tfeb.org> writes:
> On 2007-02-28 17:38:48 +0000, Richard M Kreuter <·······@progn.net> said:

> I'm unhappy about the explicit looping however.  I can see two
> solutions to this:
>
> * something really gratuitous involving GO
> * something equally gratuitous involving a lot of LAMBDAs.

I'm sorry, but here's the best I can do for now.

(unwind-protect
     (prog ((i 0) mod3 mod5)
	(declare (special i mod3 mod5))
	(setf (symbol-function 'cl-user::format-eval)
	      (lambda (stream thing colon atsign)
		(declare (ignore stream colon atsign))
		(handler-bind ((warning #'muffle-warning))
		  (eval thing))))
	(setf mod3 (mod i 3)
	      mod5 (mod i 5))
	format
	(ecase
	    (catch 'go
	      (format
	       t
	       "~&~[~[··@··········@*~A~*~]~:;~[··@*~A~:;~D~2*~]~]~%~/CL-USER::FORMAT-EVAL/"
	       mod3 mod5 i "Fizz" "Buzz"
	       '(progn
		 (incf i) 
		 (setf
		  mod3 (mod i 3)
		  mod5 (mod i 5))
		 (if (> i 100)
		     (throw 'go 'quit)
		     (throw 'go 'format)))))
	  (format (go format))
	  (quit (go quit)))
	quit nil)
  (fmakunbound 'cl-user::format-eval))

I know, it doesn't have enough LAMBDAs.

--
RmK
From: Vassil Nikolov
Subject: Re: A style question
Date: 
Message-ID: <yy8vhct5eexj.fsf@eskimo.com>
On Wed, 28 Feb 2007 19:27:41 +0000, Tim Bradshaw <···@tfeb.org> said:
| ...
| (defun fb (n)
|   ((lambda (c p)
|      (funcall c c p 1)
|    (lambda (c p i)
|      (or (> i n)
| 	 (funcall p c p i)))
|    (lambda (c p i)
|      (format t "~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~]~%"
| 	     (mod i 3) (mod i 5) i "Fizz" "Buzz")
|      (funcall c c p (1+ i))))))
| (I should point out that I don't have a CL on the system I'm writing this.)

  I found just one misplaced parenthesis (the patched version is given below),
  but personally I'd prefer that the top-level call is the call to FORMAT,
  such as

    ((lambda (n) (format t "~:{~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~] ~}" (mapcar #'(lambda (i) `(,(mod i 3) ,(mod i 5) ,i fizz buzz)) (loop for i from 1 to n collect i)))) 100)

  (yes, this still uses LOOP, but it is somewhat buried).

    (defun fb (n)
      ((lambda (c p) (funcall c c p 1))
         (lambda (c p i)
           (or (> i n) (funcall p c p i)))
         (lambda (c p i)
           (format t "~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~]~%"
                     (mod i 3) (mod i 5) i "Fizz" "Buzz")
           (funcall c c p (1+ i)))))

  ---Vassil.


-- 
mind mate, n.
  One of two persons mentally compatible with each other (cf. soul mate).
From: ·········@gmx.net
Subject: Re: A style question
Date: 
Message-ID: <1172744176.173486.277530@p10g2000cwp.googlegroups.com>
On Mar 1, 6:00 am, Vassil Nikolov <···············@pobox.com> wrote:
>     ((lambda (n) (format t "~:{~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~] ~}" (mapcar #'(lambda (i) `(,(mod i 3) ,(mod i 5) ,i fizz buzz)) (loop for i from 1 to n collect i)))) 100)
>
>   (yes, this still uses LOOP, but it is somewhat buried).
>
>     (defun fb (n)
>       ((lambda (c p) (funcall c c p 1))
>          (lambda (c p i)
>            (or (> i n) (funcall p c p i)))
>          (lambda (c p i)
>            (format t "~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~]~%"
>                      (mod i 3) (mod i 5) i "Fizz" "Buzz")
>            (funcall c c p (1+ i)))))
>
>   ---Vassil.
>
> --
> mind mate, n.
>   One of two persons mentally compatible with each other (cf. soul mate).

Noobs allowed in this discussion? Well, I'll give it a try.
Using some previously posted ideas, I got rid of an explicit
loop by using:

(defvar *i* 0)
(defun foo (outstream format-string colon-p at-sign-p)
  (declare (ignore format-string colon-p at-sign-p))
  (prog1
      (format outstream "~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~]~
%"
              (mod *i* 3) (mod *i* 5) *i* "Fizz" "Buzz")
    (incf *i*)))

(defun fizzbuzz (n)
  (let ((*i* 1))
    (format t (format nil ·····@{~~/foo/~~:*~~}" n) nil)))

(fizzbuzz 15)

Total abuse of the language.

Albert
From: Harald Hanche-Olsen
Subject: Re: A style question
Date: 
Message-ID: <pcoirdmuedg.fsf@shuttle.math.ntnu.no>
You want squiggles?  How about

(format t "~&~:{ ·@[~A~]·@[~A~]~2:*~:[~:[~D~;~]~;~]~}~%"
        (loop for n from 1 to 100
           for fizz in '#3=(nil nil "Fizz" . #3#)
           for buzz in '#5=(nil nil nil nil "Buzz" . #5#)
           collect (list fizz buzz n)))

Or, if loop is for weenies, perhaps this one, with a few gratuitous
MAPs and NCONCs thrown in.

(format t "~&~:{ ·@[~A~]·@[~A~]~2:*~:[~:[·@[~C~]~C~;~]~;~]~}~%"
        (cdr
         (nconc
          (map 'list
               (lambda (ij f b) (cons f (cons b ij)))
               (apply #'nconc
                      (map 'list
                           (lambda (i)
                             (map 'list
                                  (lambda (j)
                                    (list (if (eql i #\0) nil i) j))
                                  #1="0123456789"))
                           #1#))
               '#3=("Fizz" nil nil . #3#)
               '#5=("Buzz" nil nil nil nil . #5#)))))

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
  when there is no ground whatsoever for supposing it is true.
  -- Bertrand Russell
From: Harald Hanche-Olsen
Subject: Re: A style question
Date: 
Message-ID: <pcoejoaue1n.fsf@shuttle.math.ntnu.no>
+ Harald Hanche-Olsen <······@math.ntnu.no>:

|            for fizz in '#3=(nil nil "Fizz" . #3#)
|            for buzz in '#5=(nil nil nil nil "Buzz" . #5#)

But I hadn't read the whole thread and missed Rob Warnock's use of
this same trick in <································@speakeasy.net>.

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
  when there is no ground whatsoever for supposing it is true.
  -- Bertrand Russell
From: Rob Warnock
Subject: Re: A style question
Date: 
Message-ID: <zfSdnaqewaKmz3vYnZ2dnUVZ_vrinZ2d@speakeasy.net>
Harald Hanche-Olsen  <······@math.ntnu.no> wrote:
+---------------
| + Harald Hanche-Olsen <······@math.ntnu.no>:
| |            for fizz in '#3=(nil nil "Fizz" . #3#)
| |            for buzz in '#5=(nil nil nil nil "Buzz" . #5#)
| 
| But I hadn't read the whole thread and missed Rob Warnock's use of
| this same trick in <································@speakeasy.net>.
+---------------

But yours is neater [== hackier], since it uses the actual non-NIL
generalized boolean values. Mine just used T & NIL in the circular
lists and had to provide the "Fizz" and "Buzz" elsewhere...


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Thomas A. Russ
Subject: Re: A style question
Date: 
Message-ID: <ymi3b4n7ezo.fsf@sevak.isi.edu>
Harald Hanche-Olsen <······@math.ntnu.no> writes:

> + Harald Hanche-Olsen <······@math.ntnu.no>:
> 
> |            for fizz in '#3=(nil nil "Fizz" . #3#)
> |            for buzz in '#5=(nil nil nil nil "Buzz" . #5#)
> 
> But I hadn't read the whole thread and missed Rob Warnock's use of
> this same trick in <································@speakeasy.net>.

Of course, this hack just calls out for generalization as well:

(defun make-mod-list (modulus &optional (true-value t))
  (let ((mod-list (make-list (1- modulus) :initial-element nil)))
    (setf (cdr (last mod-list))
          (cons true-value mod-list))
    mod-list))

Then you can try:

(setq *print-circle* t)
(make-mod-list 3 "Fizz")
(make-mod-list 5 "Buzz")

This can, of course, be combined with #. for even more fun.

As the next exercise, someone can rewrite make-mod-list to dispense with
the need to call LAST....

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Thomas Bakketun
Subject: Re: A style question
Date: 
Message-ID: <54p3n3F21mtijU1@mid.individual.net>
Richard M Kreuter wrote:

> Here's one that avoids the explicit FizzBuzz, and adds /seven/
> squiggles to my first stab:
> 
> (dotimes (i 100)
>   (format t "~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~]~%"
>           (mod i 3) (mod i 5) i "Fizz" "Buzz"))
> 
> Better?

Is this the shortest version possible?

(defun fizz-buzz ()
  (loop for i from 1 to 100 do
        (format t "~&~[Fizz~]~[·········@*~[~:;~*~A~]~]"
                (mod i 3) (mod i 5) i)))
From: P.L.Hayes
Subject: Re: A style question
Date: 
Message-ID: <87hct42ya2.fsf@wolfbone.ath.cx>
Thomas Bakketun <················@bakketun.net> writes:

> Richard M Kreuter wrote:
>
>> Here's one that avoids the explicit FizzBuzz, and adds /seven/
>> squiggles to my first stab:
>> 
>> (dotimes (i 100)
>>   (format t "~[~[··@··········@*~A~]~:;~[··@*~A~:;~D~]~]~%"
>>           (mod i 3) (mod i 5) i "Fizz" "Buzz"))
>> 
>> Better?
>
> Is this the shortest version possible?
>
> (defun fizz-buzz ()
>   (loop for i from 1 to 100 do
>         (format t "~&~[Fizz~]~[·········@*~[~:;~*~A~]~]"
>                 (mod i 3) (mod i 5) i)))


I think it would be if if it wasn't for the loop. When I had a go at
this at http://golf.shinh.org/p.rb?FizzBuzz the only way I could find
to get it down to the 90 characters others had managed was this:

(dotimes (i 101)
  (format t "~[~:;~&~[Fizz~[Buzz~]~:;~[Buzz~:;~A~]~]~]"
          i (mod i 3) (mod i 5) i))

[If you remove all unnecessary whitespace, it's 90 bytes long]

Cheers,
Paul.
From: Brian Adkins
Subject: Re: A style question
Date: 
Message-ID: <NsOFh.905$m7.292@bignews5.bellsouth.net>
P.L.Hayes wrote:
> I think it would be if if it wasn't for the loop. When I had a go at
> this at http://golf.shinh.org/p.rb?FizzBuzz the only way I could find
> to get it down to the 90 characters others had managed was this:

I'm extremely upset with you for posting that golf url! :)

I just wasted way too much time trying to squeeze my Ruby version down 
and can't get below 71 bytes. I'd love to know how the top guy did it in 
56. Sorry for being off topic with Ruby, but my Lisp chops aren't up to 
the challenge yet:

1.upto(100){|i|puts"FizzBuzz#{i}"[i%3==0?0: i%5==0?4: 8,i%15==0?8: 4]}

I know there's a way to compute the substring indices mathematically 
instead of logically, but I haven't found it yet.

> (dotimes (i 101)
>   (format t "~[~:;~&~[Fizz~[Buzz~]~:;~[Buzz~:;~A~]~]~]"
>           i (mod i 3) (mod i 5) i))
> 
> [If you remove all unnecessary whitespace, it's 90 bytes long]
> 
> Cheers,
> Paul.
From: Brian Adkins
Subject: Re: A style question
Date: 
Message-ID: <gBPFh.923$m7.850@bignews5.bellsouth.net>
Brian Adkins wrote:
> P.L.Hayes wrote:
>> I think it would be if if it wasn't for the loop. When I had a go at
>> this at http://golf.shinh.org/p.rb?FizzBuzz the only way I could find
>> to get it down to the 90 characters others had managed was this:
> 
> I'm extremely upset with you for posting that golf url! :)
> 
> I just wasted way too much time trying to squeeze my Ruby version down 
> and can't get below 71 bytes. I'd love to know how the top guy did it in 
> 56. Sorry for being off topic with Ruby, but my Lisp chops aren't up to 
> the challenge yet:
> 
> 1.upto(100){|i|puts"FizzBuzz#{i}"[i%3==0?0: i%5==0?4: 8,i%15==0?8: 4]}

Got it down to 65 bytes: http://golf.shinh.org/p.rb?FizzBuzz
Something is definitely wrong when you get a bit of a thrill realizing 
you can shave off a few bytes by transforming x==0 to x<1 in a few spots.

1.upto(100){|i|puts"FizzBuzz#{i}"[i%3<1?0:i%5<1?4:8,i%15<1?8:4]}

> I know there's a way to compute the substring indices mathematically 
> instead of logically, but I haven't found it yet.
> 
>> (dotimes (i 101)
>>   (format t "~[~:;~&~[Fizz~[Buzz~]~:;~[Buzz~:;~A~]~]~]"
>>           i (mod i 3) (mod i 5) i))
>>
>> [If you remove all unnecessary whitespace, it's 90 bytes long]
>>
>> Cheers,
>> Paul.
From: Rainer Joswig
Subject: Re: A style question
Date: 
Message-ID: <joswig-960166.11532228022007@news-europe.giganews.com>
In article <························@p10g2000cwp.googlegroups.com>,
 "Tim Bradshaw" <··········@tfeb.org> wrote:

> On Feb 28, 2:02 am, ·············@craigslist.org wrote:
> 
> >
> > 1) In "ANSI Common Lisp", Graham makes the following comments:
> >     "The loop macro was originally designed to help inexperienced Lisp
> > users write iterative code...Unfortunately, loop is more like English
> > than its designers ever intended...to understand it in the abstract is
> > almost impossible...For such reasons, the use of loop cannot be
> > recommended."
> 
> Reading Paul Graham is a bit like reading reviews of films by a good
> critic: he is almost always wrong about everything, but has
> interesting things to say and it's possible to reliably predict
> whether you'll like something from what he says about it (though often
> you will differ from him on whether you like it, due to the above-
> mentioned almost-always-being-wrong thing).  He's kind of the Barry
> Norman of Lisp, really.

I agree. ;-)

> 
> >
> >     Is this a minority view? One of the things that attracted me to Lisp
> > was the simplicity, consistency, etc. of the language, so when I read
> > the above, it seemed reasonable.
> 
> Simplicity? consistency?  I think you're thinking of some other
> language there.  CL is this vast industrial thing full of enormous
> machines, oil and rust.  Some compartments are full of water, and no
> one knows what some of the machines do, if anything.  Many parts of it
> use a mixture of Whitworth & BSF threads (some left-handed), though
> much has now been converted to BA or metric, sometimes by use of taps
> & dies, sometimes with a hammer.
> 
> CL's closest living relative is FORTRAN: always remember that.

Common Lisp is a bit of the alligator in the pond, eating all
the younger designs. ;-)

> Incidentally, I'm deeply disappointed in the quality of answers in
> this thread.  In the elder days there would have been at least a few
> followups showing how to do this in the proper "FORMAT string
> indistinguishable from line noise" way.  No true CL programmer ever
> uses any other construct when the problem can be solved with a
> combination of FORMAT, LOOP & GO (FORMAT being always preferable,
> obviously).  There may yet be those reading cll who know this, though
> I suspect they have all gone into the west now.

It is always a shock to me when I look at such code. I mean
many pages long functions full of GOs, two letter variables
and such (and zero comments). I cannot
believe that humans can write this code. I always
think the author was some ugly 'Terminator' from the future,
though lately the Terminators seem to be blond and good looking.

> 
> --tim (who has used the FORMAT string mentioned in
> http://www.tfeb.org/lisp/obscurities.html in anger)
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <C7fFh.6$M24.0@newsfe12.lga>
Rainer Joswig wrote:
> In article <························@p10g2000cwp.googlegroups.com>,
>  "Tim Bradshaw" <··········@tfeb.org> wrote:

>>Incidentally, I'm deeply disappointed in the quality of answers in
>>this thread.  In the elder days there would have been at least a few
>>followups showing how to do this in the proper "FORMAT string
>>indistinguishable from line noise" way.  No true CL programmer ever
>>uses any other construct when the problem can be solved with a
>>combination of FORMAT, LOOP & GO (FORMAT being always preferable,
>>obviously).  There may yet be those reading cll who know this, though
>>I suspect they have all gone into the west now.
> 
> 
> It is always a shock to me when I look at such code. I mean
> many pages long functions full of GOs, two letter variables
> and such (and zero comments). I cannot
> believe that humans can write this code.

You refer of course to the Cello code to create a 3-D oblong button of 
variable thickness with rounded corners of variable radius:

(defun ix-render-oblong (lbox thickness baser slices stacks)
   (unless slices (setq slices 0))
   (unless stacks (setq stacks (if (zerop thickness)
                                   0 (min 10
                                       (max 1  ;; force 3d if nonzero 
thickness
                                         (round (abs thickness) 2))))))
   (when (eql (abs thickness) (abs baser))
     (setf thickness (* .99 thickness)))
   (trc nil "oblong" baser thickness etages)

   (loop
     with theta = (/ pi 2 slices)
     with etages = stacks ;; french floors (etages) zero = ground floor
     with lw/2 = (/ (r-width lbox) 2)
     with lh/2 = (/ (r-height lbox) 2)
     with bx = (- lw/2 baser)
     with by = (- lh/2 baser)
     for etage upto etages
     for oe = 0 then ie
     for ie = (unless (= etage etages)
                (* (/ (1+ etage) etages)
                  (/ pi 2)))
     for ii = (if (not ie)
                  0 ;; throwaway value to avoid forever testing if nil
                (+ (* (abs thickness)
                     (- 1 (cos ie)))))

     for ox = lw/2 then ix
     for oy = lh/2 then iy
     for oz = 0 then iz
     for oc = (cornering baser slices) then ic
     for ic = (when ie
                (cornering (- baser ii) slices))
     for ix = (- lw/2 ii)
     for iy = (- lh/2 ii)
     for iz = (when ie
                (* thickness (sin ie)))

     do (trc nil "staging" etage ie)


     (gl-translatef (+ (r-left lbox) lw/2)(+ (r-bottom lbox) lh/2) 0)

     (with-gl-begun ((if ie
                         gl_quad_strip
                       gl_polygon))

       (loop for (dx dy no-turn-p)
           in '((1 1)(-1 1)(-1 -1)(1 -1)(1 1 t))
             ;;for dbg = (and (eql dx 1)(eql dy 1)(not no-turn-p))
             do (destructuring-bind (xyn0 ix0 iy0 ox0 oy0)
                    (cons (+ (if oc (/ theta 2) 0)
                            (ecase dx (1 (ecase dy (1 0)(-1 (/ pi -2))))
                              (-1 (ecase dy (1 (/ pi 2))(-1 pi)))))
                      (if oc
                          (case (* dx dy)
                            (1 (list (* dx ix)(* dy by)(* dx ox)(* dy by)))
                            (-1 (list (* dx bx)(* dy iy)(* dx bx)(* dy 
oy))))
                         (list (* dx ix)(* dy iy)(* dx ox)(* dy oy))))

                  ;; --- lay-down start/only -------------
                  (when ie
                    (ogl-vertex-normaling ie xyn0 ix0 iy0 iz))
                  (ogl-vertex-normaling  oe xyn0 ox0 oy0 oz)

                  (trc nil "cornering!!!!!!----------------" dx dy)
                  ;; --- corner if slices and not just finishing strip

                  (unless no-turn-p
                    (trc nil "------ start ------------------" (length 
oc)(length ic))
                    (loop for (oxn . oyn) in oc
                        for icrem = ic then (cdr icrem)
                        for (ixn . iyn) = (car icrem)
                        for xyn upfrom (+ xyn0 theta) by theta
                           do (macrolet
                                  ((vtx (elev gx sx gy sy gz)
                                     `(progn
                                        (when (minusp (* dx dy))
                                          (rotatef ,sx ,sy))
                                        (ogl-vertex-normaling ,elev xyn
                                          (incf ,gx (* dx ,sx))
                                          (incf ,gy (* dy ,sy))
                                          ,gz))))
                                (trc nil "ocn icn" oxn oyn (car icrem))
                                (when icrem
                                  (vtx ie ix0 ixn iy0 iyn iz))
                                (vtx oe ox0 oxn oy0 oyn oz)))))))
     (gl-translatef (- (+ (r-left lbox) lw/2))
       (- (+ (r-bottom lbox) lh/2)) 0)))

> I always
> think the author was some ugly 'Terminator' from the future,
> though lately the Terminators seem to be blond and good looking.

Actually I was doing a rare transcription from a paper solution (where 
short variables saved pencil lead).

kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Rainer Joswig
Subject: Re: A style question
Date: 
Message-ID: <joswig-B48649.14482728022007@news-europe.giganews.com>
In article <·············@newsfe12.lga>,
 Ken Tilton <·········@gmail.com> wrote:

> Rainer Joswig wrote:
> > In article <························@p10g2000cwp.googlegroups.com>,
> >  "Tim Bradshaw" <··········@tfeb.org> wrote:
> 
> >>Incidentally, I'm deeply disappointed in the quality of answers in
> >>this thread.  In the elder days there would have been at least a few
> >>followups showing how to do this in the proper "FORMAT string
> >>indistinguishable from line noise" way.  No true CL programmer ever
> >>uses any other construct when the problem can be solved with a
> >>combination of FORMAT, LOOP & GO (FORMAT being always preferable,
> >>obviously).  There may yet be those reading cll who know this, though
> >>I suspect they have all gone into the west now.
> > 
> > 
> > It is always a shock to me when I look at such code. I mean
> > many pages long functions full of GOs, two letter variables
> > and such (and zero comments). I cannot
> > believe that humans can write this code.
> 
> You refer of course to the Cello code to create a 3-D oblong button of 
> variable thickness with rounded corners of variable radius:

This code is harmless. It is not even UPPERCASE. Not enough global variables. Scroll down!

> 
> (defun ix-render-oblong (lbox thickness baser slices stacks)
>    (unless slices (setq slices 0))
>    (unless stacks (setq stacks (if (zerop thickness)
>                                    0 (min 10
>                                        (max 1  ;; force 3d if nonzero 
> thickness
>                                          (round (abs thickness) 2))))))
>    (when (eql (abs thickness) (abs baser))
>      (setf thickness (* .99 thickness)))
>    (trc nil "oblong" baser thickness etages)
> 
>    (loop
>      with theta = (/ pi 2 slices)
>      with etages = stacks ;; french floors (etages) zero = ground floor
>      with lw/2 = (/ (r-width lbox) 2)
>      with lh/2 = (/ (r-height lbox) 2)
>      with bx = (- lw/2 baser)
>      with by = (- lh/2 baser)
>      for etage upto etages
>      for oe = 0 then ie
>      for ie = (unless (= etage etages)
>                 (* (/ (1+ etage) etages)
>                   (/ pi 2)))
>      for ii = (if (not ie)
>                   0 ;; throwaway value to avoid forever testing if nil
>                 (+ (* (abs thickness)
>                      (- 1 (cos ie)))))
> 
>      for ox = lw/2 then ix
>      for oy = lh/2 then iy
>      for oz = 0 then iz
>      for oc = (cornering baser slices) then ic
>      for ic = (when ie
>                 (cornering (- baser ii) slices))
>      for ix = (- lw/2 ii)
>      for iy = (- lh/2 ii)
>      for iz = (when ie
>                 (* thickness (sin ie)))
> 
>      do (trc nil "staging" etage ie)
> 
> 
>      (gl-translatef (+ (r-left lbox) lw/2)(+ (r-bottom lbox) lh/2) 0)
> 
>      (with-gl-begun ((if ie
>                          gl_quad_strip
>                        gl_polygon))
> 
>        (loop for (dx dy no-turn-p)
>            in '((1 1)(-1 1)(-1 -1)(1 -1)(1 1 t))
>              ;;for dbg = (and (eql dx 1)(eql dy 1)(not no-turn-p))
>              do (destructuring-bind (xyn0 ix0 iy0 ox0 oy0)
>                     (cons (+ (if oc (/ theta 2) 0)
>                             (ecase dx (1 (ecase dy (1 0)(-1 (/ pi -2))))
>                               (-1 (ecase dy (1 (/ pi 2))(-1 pi)))))
>                       (if oc
>                           (case (* dx dy)
>                             (1 (list (* dx ix)(* dy by)(* dx ox)(* dy by)))
>                             (-1 (list (* dx bx)(* dy iy)(* dx bx)(* dy 
> oy))))
>                          (list (* dx ix)(* dy iy)(* dx ox)(* dy oy))))
> 
>                   ;; --- lay-down start/only -------------
>                   (when ie
>                     (ogl-vertex-normaling ie xyn0 ix0 iy0 iz))
>                   (ogl-vertex-normaling  oe xyn0 ox0 oy0 oz)
> 
>                   (trc nil "cornering!!!!!!----------------" dx dy)
>                   ;; --- corner if slices and not just finishing strip
> 
>                   (unless no-turn-p
>                     (trc nil "------ start ------------------" (length 
> oc)(length ic))
>                     (loop for (oxn . oyn) in oc
>                         for icrem = ic then (cdr icrem)
>                         for (ixn . iyn) = (car icrem)
>                         for xyn upfrom (+ xyn0 theta) by theta
>                            do (macrolet
>                                   ((vtx (elev gx sx gy sy gz)
>                                      `(progn
>                                         (when (minusp (* dx dy))
>                                           (rotatef ,sx ,sy))
>                                         (ogl-vertex-normaling ,elev xyn
>                                           (incf ,gx (* dx ,sx))
>                                           (incf ,gy (* dy ,sy))
>                                           ,gz))))
>                                 (trc nil "ocn icn" oxn oyn (car icrem))
>                                 (when icrem
>                                   (vtx ie ix0 ixn iy0 iyn iz))
>                                 (vtx oe ox0 oxn oy0 oyn oz)))))))
>      (gl-translatef (- (+ (r-left lbox) lw/2))
>        (- (+ (r-bottom lbox) lh/2)) 0)))
> 
> > I always
> > think the author was some ugly 'Terminator' from the future,
> > though lately the Terminators seem to be blond and good looking.
> 
> Actually I was doing a rare transcription from a paper solution (where 
> short variables saved pencil lead).
> 
> kt

Take this (not written by me). Well, actually there are too many comments.
Though I'm not sure if they actually would help to understand the code...


(DEFUN INCREMENTAL-SEARCH (REVERSE-P)
  (INITIALIZE-INCREMENTAL-SEARCH-GLOBALS)
  (SELECT-WINDOW *WINDOW*) ;Flush typeout before TYPEIN-LINE-ACTIVATE
  (TYPEIN-LINE "")      ;Necessary if in the mini-buffer
  (UNWIND-PROTECT
      (TYPEIN-LINE-ACTIVATE
   (SI:WITH-STACK-ARRAY
       ;; Allocate an skip-table on the stack to avoid consing too much.
       ;; We don't bother with the reoccurrence table because (1) it's size
       ;; changes for each pattern string, and (2) it's small anyway.
       (SKIP-RESOURCE (HIGHEST-LEGAL-CHAR-CODE) :TYPE 'ART-FIXNUM)
     (PROG (CHAR     ; The current command.
       REAL-CHAR  ; The one to :UNTYI if need be
       XCHAR      ; Upcase version of character
       MUST-REDIS ; T => The echo-area must be completely redisplayed.
       (P 0)      ; The stack pointer into *IS-BP*, etc. for input and rubout
       (P1 0)     ; The pointer for which search we are doing.
            ; Can never exceed P.
       SUPPRESSED-REDISPLAY ; T if the last input char was read before
                  ; redisplay had a chance to finish.
                  ;  A G read that way acts like a failing search quit.
       (BP (POINT))  ; The POINT.
       BP1     ; Aux BP used for actual searching.
       NEW-BP
       TIME-OUT   ; Set by SEARCH when it times out so we can check input.
       INPUT-DONE ; An altmode or control char has been seen.
            ; Do not look for input any more; just search, then exit.
       (ORIG-PT)  ; Original position of POINT.
       (SKIP-TABLE NIL)
       (OLD-SKIP-TABLE NIL)
       (REOCCURRENCE-TABLE NIL)
       (OLD-REOCCURRENCE-TABLE NIL)
       )
    
      (SETQ ORIG-PT (COPY-BP BP))
      (SETQ BP1 (COPY-BP BP))    ; This is reused to save consing.
      (STORE-ARRAY-LEADER 0 *IS-STRING* 0); Clear out the search string.
      (ASET T *IS-STATUS* 0)     ; Initialize the stacks.
      (ASET REVERSE-P *IS-REVERSE-P* 0)
      (ASET ':NORMAL *IS-OPERATION* 0)
      (ASET 0 *IS-POINTER* 0)
      (ASET (COPY-BP BP) *IS-BP* 0)
      (SETQ MUST-REDIS T)     ; Initially we must redisplay.
      (GO CHECK-FOR-INPUT)
      
      ;; Come here if there is input, or nothing to do until there is input.
        INPUT
      (SETQ SUPPRESSED-REDISPLAY NIL)
      (AND (WINDOW-READY-P *WINDOW*)   ;In case of minibuffer
           (REDISPLAY *WINDOW* ':POINT))  ; Redisplay point position while waiting.
      (OR (= (WINDOW-REDISPLAY-DEGREE *WINDOW*) DIS-NONE)
          (SETQ SUPPRESSED-REDISPLAY T))
      (MULTIPLE-VALUE (CHAR REAL-CHAR)
        (EDITOR-INPUT :SCROLL T :MOUSE :RETURN
            :ANY-TYI 'COMMAND))  ; allow the mouse to work!
      (UNLESS (CHARACTERP CHAR)     ; eliminate mouse clicks now
        (SETQ INPUT-DONE T)
        ;; This is admittedly a kludge, but it's the simplest way to
        ;; get EDITOR-INPUT to execute the mouse-clicked command
        (SETQ *YANKED-MINI-BUFFER-COMMAND* CHAR)
        (GO CHECK-FOR-INPUT))     
      (SETQ XCHAR (CHAR-UPCASE CHAR))
      (COND ((NOT (OR (NOT (ZEROP (CHAR-BITS CHAR)))
            (CHAR-EQUAL CHAR #\ALTMODE) (CHAR-EQUAL CHAR #\END)
            (CHAR-EQUAL CHAR #\RUBOUT) (CHAR-EQUAL CHAR #\CLEAR-INPUT)
            (CHAR-EQUAL CHAR #\HELP) (CHAR-EQUAL CHAR #\SCROLL)
            (MEM #'CHAR-EQUAL CHAR TV:KBD-INTERCEPTED-CHARACTERS)))
             (GO NORMAL))
            ((MEMQ XCHAR '(#\c-S #\c-R))
             (PUSH-ISEARCH-STATUS)
             (ASET ':REPEAT *IS-OPERATION* P)
             (LET ((NEW-REVERSE-P (CHAR= XCHAR #\c-R)))
          (COND   ;; In reverse mode, just go to forward.
            ((NEQ (AREF *IS-REVERSE-P* P) NEW-REVERSE-P)
             (ASET NEW-REVERSE-P *IS-REVERSE-P* P)
             (SETQ MUST-REDIS T)
             (ASET ':REVERSE *IS-OPERATION* P))
            ((ZEROP (AREF *IS-POINTER* P))
             (LET ((STRING (STRING (OR (CAAR *SEARCH-RING*) (BARF)))))
               (IF *RUBOUT-KILLS-LAST-SEARCH-STRING*
              (PROGN
                (COPY-ARRAY-CONTENTS STRING *IS-STRING*)
                (ASET (ARRAY-ACTIVE-LENGTH STRING) *IS-POINTER* P))
            (LOOP FOR MORE FIRST NIL THEN T
                  FOR CHAR BEING THE ARRAY-ELEMENTS OF STRING
                  WHEN MORE
               DO (PUSH-ISEARCH-STATUS)
                  DO (LET ((IDX (AREF *IS-POINTER* P)))
                  (AND ( IDX (ARRAY-LENGTH *IS-STRING*))
                  (ADJUST-ARRAY-SIZE *IS-STRING* (+ IDX 100)))
                  (ASET CHAR *IS-STRING* IDX)
                  (ASET (1+ IDX) *IS-POINTER* P))
                (ASET ':NORMAL *IS-OPERATION* P))))
             (SETQ MUST-REDIS T))))
             (GO CHECK-FOR-INPUT))
            ((CHAR= XCHAR #\c-Q)
             (SETQ CHAR (MAKE-CHAR (EDITOR-INPUT)))
             (GO NORMAL))
            ((CHAR= XCHAR #\c-G)
             (COND ((AND (OR SUPPRESSED-REDISPLAY (NEQ (AREF *IS-STATUS* P) T))
               (PLUSP P))
               ;; G in other than a successful search
               ;; rubs out until it becomes successful.
               (SETQ P (DO ((P (1- P) (1- P)))
                 ((EQ (AREF *IS-STATUS* P) T) P)))
               (SETQ P1 (MIN P P1) MUST-REDIS T)
               (GO CHECK-FOR-INPUT))
              (T
               (MOVE-POINT (AREF *IS-BP* 0))
               (FUNCALL *TYPEIN-WINDOW* ':MAKE-COMPLETE)
               (RETURN NIL))))
            ((MEMQ CHAR TV:KBD-INTERCEPTED-CHARACTERS)
             (ZWEI-KBD-INTERCEPT-CHARACTER CHAR *TYPEIN-WINDOW*)
             (GO CHECK-FOR-INPUT))
            ((OR (CHAR= CHAR #\ALTMODE) (CHAR= CHAR #\END))
             (AND (ZEROP P)
             (RETURN (LET ((*CURRENT-COMMAND* 'COM-STRING-SEARCH))
                  (COM-STRING-SEARCH-INTERNAL REVERSE-P NIL NIL NIL))))
             (SETQ INPUT-DONE T)
             (GO CHECK-FOR-INPUT))
            ((CHAR= CHAR #\RUBOUT)
             (COND (( P 0)    ; If he over-rubbed out,
               (BEEP)      ;   that is an error.
               (GO CHECK-FOR-INPUT))
              (T
               ;; Rubout pops all of these PDLs.
               (SETQ P (1- P))
               (SETQ P1 (MIN P P1))
               (SETQ MUST-REDIS T)
               (GO CHECK-FOR-INPUT))))
            ((CHAR= CHAR #\CLEAR-INPUT)
             (SETQ P 0 P1 0 MUST-REDIS T)
             (GO CHECK-FOR-INPUT))
            ((CHAR= CHAR #\HELP)
             (PRINT-DOC ':FULL *CURRENT-COMMAND*)
             (FORMAT T "~2&Type any character to flush:")
             (CHECK-FOR-TYPEOUT-WINDOW-TYPEOUT)
             (GO CHECK-FOR-INPUT))
            (T
             (FUNCALL STANDARD-INPUT ':UNTYI REAL-CHAR)
             (SETQ INPUT-DONE T)
             (GO CHECK-FOR-INPUT)))
      (FERROR NIL "A clause fell through.")
      
      ;; Normal chars to be searched for come here.
        NORMAL
      (OR MUST-REDIS (TYPEIN-LINE-MORE "~C" CHAR))
      (PUSH-ISEARCH-STATUS)
      (LET ((IDX (AREF *IS-POINTER* P)))
        (AND ( IDX (ARRAY-LENGTH *IS-STRING*))
             (ADJUST-ARRAY-SIZE *IS-STRING* (+ IDX 100)))
        (WHEN (CHAR-FAT-P CHAR)
          (UNLESS (STRING-FAT-P *IS-STRING*)
            (LET ((NEW-STRING (MAKE-ARRAY (ARRAY-LENGTH *IS-STRING*)
                      :FILL-POINTER (FILL-POINTER *IS-STRING*)
                      :TYPE 'ART-FAT-STRING)))
         (COPY-ARRAY-CONTENTS *IS-STRING* NEW-STRING)
         (STRUCTURE-FORWARD *IS-STRING* NEW-STRING 2 2)
         (SETQ *IS-STRING* NEW-STRING))))
        (ASET CHAR *IS-STRING* IDX)
        (ASET (1+ IDX) *IS-POINTER* P))
      (ASET ':NORMAL *IS-OPERATION* P)
      ;; Come here after possibly processing input to update the search tables
      ;; to search for a while.  First, if necessary and not suppressed
      ;; update the search string displayed in the echo area.
        CHECK-FOR-INPUT
      ;; If there is input available, go read it.
      ;; Otherwise, do work if there is work to be done.
      (AND (NOT INPUT-DONE)
           (FUNCALL STANDARD-INPUT ':LISTEN)
           (GO INPUT))
      ;; Now do some work for a while, then go back to CHECK-FOR-INPUT.
      (COND (MUST-REDIS
             (SETQ MUST-REDIS NIL)
             (TYPEIN-LINE "~:|")
             (OR (AREF *IS-STATUS* P1) (TYPEIN-LINE-MORE "Failing "))
             (AND (AREF *IS-REVERSE-P* P) (TYPEIN-LINE-MORE "Reverse "))
             (TYPEIN-LINE-MORE "I-Search: ")
             (STORE-ARRAY-LEADER (AREF *IS-POINTER* P) *IS-STRING* 0)
             (TYPEIN-LINE-MORE "~A" *IS-STRING*)))
      ;; Now see what sort of state the actual search is in, and
      ;; what work there is to do.  P1 points at the level of the
      ;; table on which we are actually working.
      (MOVE-BP BP1 (AREF *IS-BP* P1))
      ;; Display point at the end of the last search level which has succeeded.
      (DO ((P0 P1 (1- P0)))
          ((EQ (AREF *IS-STATUS* P0) T)
           (MOVE-POINT (AREF *IS-BP* P0))))
      (MUST-REDISPLAY *WINDOW* DIS-BPS)
      (COND ((EQ (AREF *IS-STATUS* P1) ':GO)
             
             ;; If we are about to repeat a search, generate the Boyer-Moore
             ;; tables for the pattern string and cache them.  Do not generate
             ;; the tables if they are already cached.
             (IF (OR TIME-OUT (CHAR= XCHAR #\c-S))
            (WHEN (AND (NULL OLD-SKIP-TABLE) (NULL OLD-REOCCURRENCE-TABLE))
              (SETQ OLD-SKIP-TABLE (GENERATE-BOYER-SKIP-TABLE
                      *IS-STRING* SKIP-RESOURCE)
               OLD-REOCCURRENCE-TABLE (GENERATE-BOYER-REOCCURRENCE-TABLE
                         *IS-STRING*)))
          (SETQ OLD-SKIP-TABLE NIL
                OLD-REOCCURRENCE-TABLE NIL))
             ;; We need an additional check here, because of the interaction between
             ;; additional c-S'es and typeahead.  If you type, say "FEPFS" c-S in a
             ;; long buffer with "FEP" at the beginning of the buffer and "FEPFS" at
             ;; the end of the buffer, then *IS-STRING* can get out of sync with the
             ;; reoccurrence table.  This code gets them back in sync.
             (WHEN (AND OLD-REOCCURRENCE-TABLE
              ( (ARRAY-LENGTH OLD-REOCCURRENCE-TABLE)
                 (STRING-LENGTH *IS-STRING*)))
          (SETQ OLD-SKIP-TABLE (GENERATE-BOYER-SKIP-TABLE
                  *IS-STRING* SKIP-RESOURCE)
                OLD-REOCCURRENCE-TABLE (GENERATE-BOYER-REOCCURRENCE-TABLE
                     *IS-STRING*)))
             (SETQ SKIP-TABLE OLD-SKIP-TABLE
              REOCCURRENCE-TABLE OLD-REOCCURRENCE-TABLE)
                   
             ;; If the level we were working on is still not finished,
             ;; search at most 100 more lines.  If we find it or the end of the buffer
             ;; before then, this level is determined and we can work on the next.
             ;; Otherwise, we remain in the :GO state and do 100 more lines next time.
             (MULTIPLE-VALUE (NEW-BP TIME-OUT)
          (SEARCH BP1 *IS-STRING*
             (AREF *IS-REVERSE-P* P1) NIL 100
             NIL *ALPHABETIC-CASE-AFFECTS-SEARCH*  ;---
             SKIP-TABLE REOCCURRENCE-TABLE))
             ;; What happened?
             (COND (TIME-OUT
               ;; Nothing determined.  NEW-BP has where we stopped.
               (MOVE-BP BP1 NEW-BP))
              ((NULL NEW-BP)
               ;; This search was determined to be a failure.
               (OR (AND (MEMQ ':MACRO-ERROR
                    (FUNCALL STANDARD-INPUT ':WHICH-OPERATIONS))
                   (FUNCALL STANDARD-INPUT ':MACRO-ERROR))
              (BEEP))
               (ASET NIL *IS-STATUS* P1)
               (MOVE-BP BP1 (AREF *IS-BP* (1- P1)))
               (MOVE-POINT BP1)
               (SETQ MUST-REDIS T))
              (T ;; This search level has succeeded.
               (ASET T *IS-STATUS* P1)
               (MOVE-POINT NEW-BP)
               (MOVE-BP BP1 NEW-BP))))
            (( P P1)
             ;; This level is finished, but there are more pending levels typed ahead.
             (SETQ P1 (1+ P1))
             (ASET (SETQ BP1 (COPY-BP BP1)) *IS-BP* P1)
             (STORE-ARRAY-LEADER (AREF *IS-POINTER* P1) *IS-STRING* 0)
             (COND ((NULL (AREF *IS-STATUS* (1- P1)))
               (COND ((NEQ (AREF *IS-OPERATION* P1) ':REVERSE)
                 ;; A failing search remains so unless we reverse direction.
                 (ASET NIL *IS-STATUS* P1))
                (T ;; If we reverse direction, change prompt line.
                 (SETQ MUST-REDIS T))))
              ((EQ (AREF *IS-OPERATION* P1) ':NORMAL)
               ;; Normal char to be searched for comes next.
               ;; We must adjust the bp at which we start to search
               ;; so as to allow the user to extend the string already found.
               (MOVE-BP
            BP1 (FORWARD-CHAR
                  BP1 (COND ((AREF *IS-REVERSE-P* P1)
                   (COND ((= (ARRAY-ACTIVE-LENGTH *IS-STRING*) 1)
                     0)
                         (T (ARRAY-ACTIVE-LENGTH *IS-STRING*))))
                  (T (- 1 (ARRAY-ACTIVE-LENGTH *IS-STRING*))))
                    T)))))
            ;; If there is nothing left to do, and terminator seen, exit.
            (INPUT-DONE
             (SEARCH-RING-PUSH
          ;; Entries on the search ring should have a leader
          (STRING-NCONC (MAKE-ARRAY (ARRAY-ACTIVE-LENGTH *IS-STRING*)
                     ':TYPE (ARRAY-TYPE *IS-STRING*)
                     ':FILL-POINTER 0)
                   *IS-STRING*)
          'SEARCH)
             (TYPEIN-LINE-MORE "~C" #\END)
             (MAYBE-PUSH-POINT ORIG-PT)
             (SELECT-WINDOW *WINDOW*)
             (RETURN NIL))
            ;; Nothing to do and no terminator, wait for input.
            (T (GO INPUT)))
      (GO CHECK-FOR-INPUT)
      
      )))
    (FUNCALL *MODE-LINE-WINDOW* ':DONE-WITH-MODE-LINE-WINDOW))
  DIS-BPS)



How about this? This is clearly from aliens.


(DEFMFUN MEVAL1 (FORM)
  (declare (special  nounl *break-points* *break-step*))
  (COND ((ATOM FORM)
    (PROG (VAL)
      (COND ((NOT (SYMBOLP FORM)) (RETURN FORM))
       ((AND $NUMER (SETQ VAL (SAFE-MGET FORM '$NUMER))
             (OR (NOT (EQ FORM '$%E)) $%ENUMER))
        (RETURN (MEVAL1 VAL)))
       ((NOT (BOUNDP FORM))
        (IF (SAFE-GET FORM 'BINDTEST)
            (MERROR "~:M unbound variable" FORM)
            (RETURN FORM)))
       ((MFILEP (SETQ VAL (SYMBOL-VALUE FORM)))
        (SETQ VAL
         (EVAL (DSKGET (CADR VAL) (CADDR VAL) 'VALUE NIL)))))
      (WHEN (AND $REFCHECK (MEMQ FORM (CDR $VALUES))
            (NOT (MEMQ FORM REFCHKL)))
       (SETQ REFCHKL (CONS FORM REFCHKL))
       (MTELL "~:M has value.~%" FORM))
      (RETURN VAL)))
   ((OR (AND (ATOM (CAR FORM))
        (SETQ FORM (CONS (NCONS (CAR FORM)) (CDR FORM))))
        (ATOM (CAAR FORM)))
    (LET ((BAKTRCL BAKTRCL) TRANSP) 
      (PROG (U ARYP)
       (declare (special aryp))
        ;;(COND ((EQ DEBUG '$ALL) (SETQ BAKTRCL (CONS FORM BAKTRCL))))
                (setq *last-meval1-form* form)
        (SETQ ARYP (MEMQ 'array (CDAR FORM))) 
        (COND ((AND (NOT OPEXPRP) (NOT ARYP) 
          (MEMQ (CAAR FORM) '(MPLUS MTIMES MEXPT MNCTIMES)))
          (GO C))
         ;; dont bother pushing mplus and friends on baktrcl
         ;; should maybe even go below aryp.
         ((AND debug
          (PROGN
           ;(SETQ BAKTRCL (CONS FORM BAKTRCL))
           ;; if wanting to step, the *break-points*
           ;; variable will be set to a vector (possibly empty).
           (when (and *break-points*
                 (or (null  *break-step*)
                (null (funcall *break-step* form))))
            (let ((ar *break-points*))
              (declare (type (vector t) ar))
            (sloop for i below (fill-pointer ar)
                   when (eq (car (aref ar i)) form)
                   do (*break-points* form)
                   (loop-finish))))
            NIL)))
         ((AND $SUBSCRMAP ARYP
          (DO ((X (MARGS FORM) (CDR X)))
              ((OR (NULL X) (MXORLISTP (CAR X))) X)))
          (SETQ NOEVALARGS NIL) (RETURN (SUBGEN FORM)))
         ((EQ (CAAR FORM) 'MQAPPLY) (RETURN (MQAPPLY1 FORM))))
        (BADFUNCHK (CAAR FORM) (CAAR FORM) NIL)
       A    (SETQ U (OR (SAFE-GETL (CAAR FORM) '(NOUN))
              (AND NOUNSFLAG (EQ (GETCHAR (CAAR FORM) 1) '%)
              (NOT (OR (GETL-FUN (CAAR FORM)
                       '(SUBR FSUBR LSUBR))
                  (SAFE-GETL (CAAR FORM)
                   '(MFEXPR* MFEXPR*S))))
              (PROG2 ($VERBIFY (CAAR FORM))
                (SAFE-GETL (CAAR FORM) '(NOUN))))
              (AND (NOT ARYP) $TRANSRUN
              (SETQ TRANSP
               (OR (SAFE-MGETL (CAAR FORM) '(T-MFEXPR))
                   (SAFE-GETL (CAAR FORM)
                    '(TRANSLATED-MMACRO)))))
              (AND (NOT ARYP)
              (SETQ U
               (OR (SAFE-MGET (CAAR FORM) 'TRACE)
                   (AND $TRANSRUN
                   (SAFE-GET (CAAR FORM) 'TRANSLATED)
                   (NOT (SAFE-MGET (CAAR FORM)
                         'LOCAL-FUN))
                   (SETQ TRANSP T) (CAAR FORM))))
              (GETL-FUN U '(EXPR SUBR LSUBR)))
              (COND (ARYP (SAFE-MGETL (CAAR FORM) '(HASHAR ARRAY)))
               ((SAFE-MGETL (CAAR FORM) '(MEXPR MMACRO)))
               ((SAFE-MGETL (CAAR FORM) '(T-MFEXPR)))
               (T (OR (SAFE-GETL (CAAR FORM)
                  '(MFEXPR* MFEXPR*S))
                 (GETL-FUN (CAAR FORM)
                      '(SUBR FSUBR EXPR FEXPR macro
                        LSUBR)))))))
        (COND ((NULL U) (GO B))
         ((AND (MEMQ (CAR U) '(MEXPR MMACRO)) (MFILEP (CADR U)))
          (SETQ U (LIST (CAR U)
              (DSKGET (CADADR U) (CAR (CDDADR U))
                 (CAR U) NIL))))
         ((AND (MEMQ (CAR U) '(ARRAY HASHAR)) (MFILEP (CADR U)))
          (I-$UNSTORE (NCONS (CAAR FORM)))
          (RETURN (MEVAL1 FORM))))
        (RETURN 
         (COND ((EQ (CAR U) 'HASHAR) 
           (HARRFIND (CONS (CAR FORM) (MEVALARGS (CDR FORM)))))
          ((MEMQ (CAR U) '(FEXPR FSUBR))
           (IF FEXPRERRP
          (MERROR "Attempt to call ~A ~A from MACSYMA level.~
             ~%Send a bug note."
             (CAR U) (CAAR FORM)))
           (SETQ NOEVALARGS NIL) (APPLY (CAAR FORM) (CDR FORM)))
          ((OR (AND (EQ (CAR U) 'SUBR)
               (PROG2 (MARGCHK (CAAR FORM) (CDR FORM)) T))
          (EQ (CAR U) 'LSUBR))
;            ((MEMQ (CAR U) '(SUBR LSUBR))
;        (MARGCHK (CAAR FORM) (CDR FORM)))
           (APPLY (CAAR FORM) (MEVALARGS (CDR FORM))))

          ((EQ (CAR U) 'NOUN)
;        (MARGCHK (CAAR FORM) (CDR FORM))
           (COND ((OR (MEMQ (CAAR FORM) NOUNL) NOUNSFLAG)
             (SETQ FORM (CONS (CONS (CADR U) (CDAR FORM))
                    (CDR FORM)))
             (GO A))
            (ARYP (GO B))
            ((MEMQ (CAAR FORM) '(%SUM %PRODUCT))
             (SETQ U (DO%SUM (CDR FORM) (CAAR FORM))
              NOEVALARGS NIL)
             (CONS (NCONS (CAAR FORM)) U))
            (T (MEVAL2 (MEVALARGS (CDR FORM)) FORM))))
          ((EQ (CAR U) 'array)
           (ARRFIND (CONS (CAR FORM) (MEVALARGS (CDR FORM)))))
          ((EQ (CAR U) 'MEXPR)
           (MLAMBDA (CADR U) (CDR FORM) (CAAR FORM) NOEVALARGS form))
          ((MEMQ (CAR U) '(MMACRO TRANSLATED-MMACRO))
           (SETQ NOEVALARGS NIL)
           (MEVAL (MMACRO-APPLY (CADR U) FORM)))
          ((EQ (CAR U) 'MFEXPR*)
           (SETQ NOEVALARGS NIL)  (APPLY (CADR U) (NCONS FORM)))
          #+cl
          ((eq (car u) 'macro)
           (setq noevalargs nil)
           (setq form (cons(caar form) (cdr form)))
;          (setf (car form) (caar form) )
            (eval form)
           )
          #+Maclisp
          ((EQ (CAR U) 'MFEXPR*S)
           (SETQ NOEVALARGS NIL)
           ;; use macsyma Trace if you want to trace this call.
           (SUBRCALL T (CADR U) FORM))
          ((EQ (CAR U) 'T-MFEXPR) (APPLY (CADR U) (CDR FORM)))
          (T (MARGCHK (CAAR FORM) (CDR FORM))
             (APPLY (CADR U) (MEVALARGS (CDR FORM))))))
       B   #+(OR PDP10 Multics Franz NIL cl)
        (IF (AND (NOT ARYP) (LOAD-FUNCTION (CAAR FORM) T)) (GO A))
        (BADFUNCHK (CAAR FORM) (CAAR FORM) NIL)
        (IF (SYMBOLP (CAAR FORM))
       (SETQ U (BOUNDP (CAAR FORM)))
       (RETURN (MEVAL1-EXTEND FORM)))
       C   (COND ((OR (NULL U)
            (AND (SAFE-GET (CAAR FORM) 'OPERATORS) (NOT ARYP))
            (EQ (CAAR FORM) (SETQ U (SYMBOL-VALUE (CAAR FORM)))))
             (SETQ FORM (MEVAL2 (MEVALARGS (CDR FORM)) FORM))
             (RETURN (OR (AND (SAFE-MGET (CAAR FORM) 'ATVALUES)
               (AT1 FORM)) FORM)))
            ((AND ARYP (SAFE-GET (CAAR FORM) 'NONARRAY))
             (RETURN (CONS (CONS (CAAR FORM) ARYP)
                 (MEVALARGS (CDR FORM)))))
            ((ATOM U)
             (BADFUNCHK (CAAR FORM) U NIL)
             (SETQ FORM (CONS (CONS (GETOPR U) ARYP) (CDR FORM)))
             (GO A))
            ((EQ (CAAR U) 'LAMBDA)
             (IF ARYP
            (MERROR "Improper array call")
            (RETURN (MLAMBDA U (CDR FORM)
                   (CAAR FORM) NOEVALARGS form))))
            (T (RETURN (MAPPLY1 U (MEVALARGS (CDR FORM))
                (CAAR FORM) form)))))))
   (T (MAPPLY1 (CAAR FORM) (MEVALARGS (CDR FORM)) (CAAR FORM) form))))
From: Vassil Nikolov
Subject: Re: A style question
Date: 
Message-ID: <yy8virdlegpk.fsf@eskimo.com>
On Wed, 28 Feb 2007 14:48:27 +0100, Rainer Joswig <······@lisp.de> said:
| ...
| Take this (not written by me).

  Zmacs?

| ...
| How about this? This is clearly from aliens.

  But was ported to Common Lisp at some point, wasn't it?

  ---Vassil.


-- 
mind mate, n.
  One of two persons mentally compatible with each other (cf. soul mate).
From: Rainer Joswig
Subject: Re: A style question
Date: 
Message-ID: <joswig-97DA21.09303501032007@news-europe.giganews.com>
In article <················@eskimo.com>,
 Vassil Nikolov <···············@pobox.com> wrote:

> On Wed, 28 Feb 2007 14:48:27 +0100, Rainer Joswig <······@lisp.de> said:
> | ...
> | Take this (not written by me).
> 
>   Zmacs?
> 
> | ...
> | How about this? This is clearly from aliens.
> 
>   But was ported to Common Lisp at some point, wasn't it?

Not sure. There are selected libraries that got ported.
But the system runs several Lisp dialects at the same time.

> 
>   ---Vassil.
From: Frank Buss
Subject: Re: A style question
Date: 
Message-ID: <3iflyo7w2xsl.4obp81wdw69q.dlg@40tude.net>
Ken Tilton wrote:

> You refer of course to the Cello code to create a 3-D oblong button of 
> variable thickness with rounded corners of variable radius:

Yes, that's really ugly :-) Did you thought about using your dataflow
paradigm to create graphics? Something similar would be to use higher order
functions and combinators. The code below creates buttons like this:

http://www.frank-buss.de/tmp/buttons.png

In LispWorks 4.3.7 it is not very fast, but SBCL needs not many seconds :-)

(defparameter *width* 200)
(defparameter *height* 70)
(defstruct color
	(r 0.0 :type single-float)
	(g 0.0 :type single-float)
	(b 0.0 :type single-float)
	(a 0.0 :type single-float))

(defun rgb-2-color (rgb)
    (declare (type fixnum rgb)
  (make-color :r (/ (ldb (byte 8 16) rgb) 255.0)
              :g (/ (ldb (byte 8 8) rgb) 255.0)
              :b (/ (ldb (byte 8 0) rgb) 255.0)))

(defun middle (a b)
  (/ (+ a b) 2.0))

(defconstant +transparent+ (make-color :r 1.0 :g 1.0 :b 1.0 :a 1.0))
(defconstant +white+ (make-color :r 1.0 :g 1.0 :b 1.0))

;(defconstant +color0+ (rgb-2-color #xeaeaa2))
;(defconstant +color1+ (rgb-2-color #xee4f23))

;(defconstant +color0+ (rgb-2-color #x999999))
;(defconstant +color1+ (rgb-2-color #x444444))

(defconstant +color0+ (rgb-2-color #xa2fafa))
(defconstant +color1+ (rgb-2-color #x23ee4f))

(defconstant +color-avg+
  (make-color :r (middle (color-r +color0+) (color-r +color1+))
              :g (middle (color-g +color0+) (color-g +color1+))
              :b (middle (color-b +color0+) (color-b +color1+))))

(defun transparentp (color)
  (= 1.0 (color-a color)))

(defun disc (&key x0 y0 radius)
  (let ((r2 (* radius radius)))
    (lambda (x y)
      (let ((xc (- x x0))
            (yc (- y y0)))
        (let ((r (+ (* xc xc) (* yc yc))))
          (<= r r2))))))

(defun rect (&key x0 y0 x1 y1)
  (lambda (x y)
    (and (>= x x0)
         (<= x x1)
         (>= y y0)
         (<= y y1))))

(defun rounded-rect (&key x0 y0 x1 y1 radius)
  (let ((x0-i (+ x0 radius))
        (y0-i (+ y0 radius))
        (x1-i (- x1 radius))
        (y1-i (- y1 radius)))
    (lambda (x y)
      (let ((rect (rect :x0 x0 :y0 y0 :x1 x1 :y1 y1))
            (top-left-disc (disc :x0 x0-i :y0 y0-i :radius radius))
            (top-right-disc (disc :x0 x1-i :y0 y0-i :radius radius))
            (bottom-left-disc (disc :x0 x0-i :y0 y1-i :radius radius))
            (bottom-right-disc (disc :x0 x1-i :y0 y1-i :radius radius)))
        (cond ((and (< x x0-i) (< y y0-i)) (funcall top-left-disc x y))
              ((and (> x x1-i) (< y y0-i)) (funcall top-right-disc x y))
              ((and (< x x0-i) (> y y1-i)) (funcall bottom-left-disc x y))
              ((and (> x x1-i) (> y y1-i)) (funcall bottom-right-disc x y))
              (t (funcall rect x y)))))))

(defun gradient (&key color0 color1 x0 x1)
  (let ((r0 (color-r color0))
        (g0 (color-g color0))
        (b0 (color-b color0))
        (r1 (color-r color1))
        (g1 (color-g color1))
        (b1 (color-b color1))
        (dx (- x1 x0)))
    (lambda (x)
      (cond ((< x x0) color0)
            ((>= x x1) color1)
            (t (setf x (/ (- x x0) dx))
               (make-color :r (+ (* (- r1 r0) x) r0)
                           :g (+ (* (- g1 g0) x) g0)
                           :b (+ (* (- b1 b0) x) b0)))))))

(defun blur (&key mask)
  (lambda (x y)
    (let ((sum 0.0))
      (loop for xo from -4 to 4 do
            (loop for yo from -4 to 4 do
                  (when (funcall mask (+ x xo) (+ y yo)) (incf sum (/ (+ (*
xo xo) (* yo yo) 2.0))))))
      (/ sum 2.0))))

(defun add (fun1 fun2)
  (lambda (x y)
    (let ((c1 (funcall fun1 x y))
          (c2 (funcall fun2 x y)))
      (cond ((transparentp c1) c2)
            ((transparentp c2) c1)
            (t (make-color :r (+ (color-r c1) (color-r c2))
                           :g (+ (color-g c1) (color-g c2))
                           :b (+ (color-b c1) (color-b c2))))))))
    
(defun neg-mul (color-fun channel-fun)
  (lambda (x y)
    (let ((color (funcall color-fun x y))
          (channel (funcall channel-fun x y)))
      (cond ((transparentp color) color)
            (t (when (> channel 1) (setf channel 1))
               (when (< channel 0) (setf channel 0))
               (let ((channel2 (- 1 channel)))
                 (make-color :r (+ (* channel (color-r +color0+)) (*
channel2 (color-r color)))
                             :g (+ (* channel (color-g +color0+)) (* channel2 (color-g color)))
                             :b (+ (* channel (color-b +color0+)) (* channel2 (color-b color))))))))))
    
(defun fill-gradient-vertical (&key gradient function)
  (lambda (x y)
    (if (funcall function x y)
        (funcall gradient y)
      +transparent+)))

(defun fill-solid (&key function color)
  (lambda (x y)
    (if (funcall function x y)
        color
      +transparent+)))

(defun overlay (&key background foreground)
  (lambda (x y)
    (let ((foreground-color (funcall foreground x y)))
      (if (transparentp foreground-color)
          (funcall background x Y)
        foreground-color))))

(defun xor (fun1 fun2)
  (lambda (x y)
    (not (eql (funcall fun1 x y) (funcall fun2 x y)))))

(defun channel-and (channel-fun binary-fun)
  (lambda (x y)
    (if (funcall binary-fun x y)
        (funcall channel-fun x y)
      0)))

(defun button (&key x0 y0 x1 y1)
  (let* ((radius 15.0)
         (stroke 1.0)
         (outer-rect (rounded-rect :x0 (- x0 stroke) :y0 (- y0 stroke)
                                   :x1 (+ x1 stroke) :y1 (+ y1 stroke)
                                   :radius (+ radius stroke)))
         (inner-rect (rounded-rect :x0 x0 :y0 y0
                                   :x1 x1 :y1 y1
                                   :radius radius))
         (ring (xor outer-rect inner-rect))
         (inner-glow (channel-and (blur :mask ring) inner-rect))
         (gradient (gradient :color0 +color0+ :color1 +color1+ :x0 y0 :x1
y1))
         (filled-outer-rect (fill-solid
                             :function outer-rect
                             :color +color-avg+))
         (filled-inner-rect (fill-gradient-vertical
                             :gradient gradient
                             :function inner-rect)))
    (overlay :background filled-outer-rect
             :foreground (neg-mul filled-inner-rect inner-glow))))

(defun anti-alias (function)
  (lambda (x y)
    (let ((c0 (funcall function x y))
          (c1 (funcall function (+ x 0.5) y))
          (c2 (funcall function x (+ y 0.5)))
          (c3 (funcall function (+ x 0.5) (+ y 0.5))))
      (make-color :r (/ (+ (color-r c0) (color-r c1) (color-r c2) (color-r
c3)) 4.0)
                  :g (/ (+ (color-g c0) (color-g c1) (color-g c2) (color-g c3)) 4.0)
                  :b (/ (+ (color-b c0) (color-b c1) (color-b c2) (color-b c3)) 4.0)
                  :a (/ (+ (color-a c0) (color-a c1) (color-a c2) (color-a c3)) 4.0)))))

(defun color-byte (color)
  (let ((result (floor (* 255.0 color))))
    (cond ((> result 255) 255)
          ((< result 0) 0)
          (t result))))

(defun red-byte (color)
  (color-byte (color-r color)))

(defun green-byte (color)
  (color-byte (color-g color)))

(defun blue-byte (color)
  (color-byte (color-b color)))

(defun paint (function &optional (filename "c:/tmp/test.tga"))
  (with-open-file 
      (tga filename 
           :direction :output 
           :if-exists :supersede 
           :element-type 'unsigned-byte) 
    (dolist (byte (list 0 0 2 0 0 0 0 0 0 0 0 0 
                        (mod *width* 256) (floor *width* 256) 
                        (mod *height* 256) (floor *height* 256) 24 0)) 
      (write-byte byte tga)) 
    (loop for y from (1- *height*) downto 0 do 
          (loop for x from 0 below *width* do 
                (let ((color (funcall function x y)))
                  (when (transparentp color) (setf color +white+))
                  (write-byte (blue-byte color) tga) 
                  (write-byte (green-byte color) tga)
                  (write-byte (red-byte color) tga)))))
  #+:lispworks (sys:call-system (format nil
"c:\\Programme\\Adobe\\Photoshop 7.0\\Photoshop.exe ~a" filename)))

(defun test ()
  (paint (anti-alias (button :x0 10.0 :y0 10.0 :x1 190.0 :y1 60.0))))

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <P6lFh.24$XI4.17@newsfe12.lga>
Frank Buss wrote:
> Ken Tilton wrote:
> 
> 
>>You refer of course to the Cello code to create a 3-D oblong button of 
>>variable thickness with rounded corners of variable radius:
> 
> 
> Yes, that's really ugly :-) Did you thought about using your dataflow
> paradigm to create graphics?

No. This will shock everyone and have Mastenbrook calling me a liar, but 
my use of Cells does not violate Tilton's Law, viz., "Never use anything 
for everything."

> Something similar would be to use higher order
> functions and combinators.

Look, I'm not smart like you guys, just a simple application programmer. 
That is how I ended up working on paper and drawing pictures.

> The code below creates buttons like this:
> 
> http://www.frank-buss.de/tmp/buttons.png

Wow, gorgeous. I let the graphicss card to the work, but your solution 
is way cool.

kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Luke J Crook
Subject: Re: A style question
Date: 
Message-ID: <8v6dnZxMY7FlOHrYnZ2dnUVZ_hKdnZ2d@giganews.com>
Frank Buss wrote:
> The code below creates buttons like this:
> 
> http://www.frank-buss.de/tmp/buttons.png
> 
> In LispWorks 4.3.7 it is not very fast, but SBCL needs not many seconds :-)
> 

You know there is this little-known package called lispbuilder-sdl that
can also be used for the back-end rendering. ;)

- Luke
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <XLPFh.985$zR6.101@newsfe12.lga>
Luke J Crook wrote:
> Frank Buss wrote:
> 
>>The code below creates buttons like this:
>>
>>http://www.frank-buss.de/tmp/buttons.png
>>
>>In LispWorks 4.3.7 it is not very fast, but SBCL needs not many seconds :-)
>>
> 
> 
> You know there is this little-known package called lispbuilder-sdl that
> can also be used for the back-end rendering. ;)

Maybe he suffers from IH syndrome.

lb-sdl is interesting. A kazillion libraries, not a few dead links, and 
no unifying GUI or app framework. Maybe the LB should stand for 
"lotsabindings"?

What's up with that?

kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Frank Buss
Subject: Re: A style question
Date: 
Message-ID: <1q2g9pcnmq6eh.1ugz9npzqkn8y.dlg@40tude.net>
Ken Tilton wrote:

> Luke J Crook wrote:
>> 
>> You know there is this little-known package called lispbuilder-sdl that
>> can also be used for the back-end rendering. ;)

Yes, and saving images would be a good idea for lispbuilder-sdl-images :-)

> lb-sdl is interesting. A kazillion libraries, not a few dead links, and 
> no unifying GUI or app framework. Maybe the LB should stand for 
> "lotsabindings"?
> 
> What's up with that?

My main idea was to create a Lisp distribution, with lots of useful
libraries, for Mac, Linux and Windows, with which you can create platform
independant end-user installable GUI applications, like it is possible with
LispWorks and CAPI:

http://wiki.alu.org/Application_Builder

Thanks to the volunteers, the library part is very advanced and
lispbuilder-sdl is even working for Mac. Now the distribution part needs
some work.

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <E3XFh.251$sT3.8@newsfe12.lga>
Frank Buss wrote:
> Ken Tilton wrote:
> 
> 
>>Luke J Crook wrote:
>>
>>>You know there is this little-known package called lispbuilder-sdl that
>>>can also be used for the back-end rendering. ;)
> 
> 
> Yes, and saving images would be a good idea for lispbuilder-sdl-images :-)
> 
> 
>>lb-sdl is interesting. A kazillion libraries, not a few dead links, and 
>>no unifying GUI or app framework. Maybe the LB should stand for 
>>"lotsabindings"?
>>
>>What's up with that?
> 
> 
> My main idea was to create a Lisp distribution, with lots of useful
> libraries, for Mac, Linux and Windows, with which you can create platform
> independant end-user installable GUI applications, like it is possible with
> LispWorks and CAPI:
> 
> http://wiki.alu.org/Application_Builder

Ah, there it is: wxCL or all-Lisp native GUI. Not Tcl/Tk?

Hmmm, also interesting, I thought I saw wxWindows was GPL last I looked, 
but now I see an exception saying binaries are cool ("under my own 
temrs"). Nice.

> 
> Thanks to the volunteers, the library part is very advanced and
> lispbuilder-sdl is even working for Mac.

Yes, very impressive libs list. OpenRM /and/ ODE. Is SDL still 
one-window only? Not that that is a big problem for games. And SDL and 
wxWindows work together?

kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Luke Crook
Subject: Re: A style question
Date: 
Message-ID: <1172859211.875345.267300@31g2000cwt.googlegroups.com>
On Mar 2, 7:06 am, Ken Tilton <·········@gmail.com> wrote:
> Yes, very impressive libs list. OpenRM /and/ ODE. Is SDL still
> one-window only? Not that that is a big problem for games. And SDL and wxWindows work together?

Support for multiple SDL windows is in SDL 1.3, I believe. But 1.3 is
still in development. The latest stable version 1.2.11 only supports
one window.

- Luke
From: Luke Crook
Subject: Re: A style question
Date: 
Message-ID: <1172859278.339429.167870@s48g2000cws.googlegroups.com>
On Mar 2, 7:06 am, Ken Tilton <·········@gmail.com> wrote:
> Yes, very impressive libs list. OpenRM /and/ ODE. Is SDL still
> one-window only? Not that that is a big problem for games. And SDL and wxWindows work together?

Support for multiple SDL windows is in SDL 1.3, I believe. But 1.3 is
still in development. The latest stable version 1.2.11 only supports
one window.

- Luke
From: Luke J Crook
Subject: Re: A style question
Date: 
Message-ID: <Aa2dnVdb69mdYnXYnZ2dnUVZ_obinZ2d@giganews.com>
Frank Buss wrote:
>> Luke J Crook wrote:
>>> You know there is this little-known package called lispbuilder-sdl that
>>> can also be used for the back-end rendering. ;)
> 
> Yes, and saving images would be a good idea for lispbuilder-sdl-images :-)
> 

If you don't mind saving a surface in BMP format then you can use this
function in lispbuilder-sdl

(sdl:save-image surface filename &optional (path #P""))

- Luke
From: Ken Tilton
Subject: Re: A style question
Date: 
Message-ID: <rm7Gh.2453$rM2.215@newsfe12.lga>
Luke J Crook wrote:
> Frank Buss wrote:
> 
>>>Luke J Crook wrote:
>>>
>>>>You know there is this little-known package called lispbuilder-sdl that
>>>>can also be used for the back-end rendering. ;)
>>
>>Yes, and saving images would be a good idea for lispbuilder-sdl-images :-)
>>
> 
> 
> If you don't mind saving a surface in BMP format then you can use this
> function in lispbuilder-sdl
> 
> (sdl:save-image surface filename &optional (path #P""))

Phooey! You need lispbuilder-graphicsmagick. :)

In Cello I load any image format, crop/resize, flip or flop or whatever, 
then write out any way I like. I even had a snapshot mechanism going for 
a while that wrote the current screen out as a JPG. GM rocks.

kt

-- 
Well, I've wrestled with reality for 35 years, Doctor, and
I'm happy to state I finally won out over it.
                                   -- Elwood P. Dowd

In this world, you must be oh so smart or oh so pleasant.
                                   -- Elwood's Mom
From: Luke Crook
Subject: Re: A style question
Date: 
Message-ID: <1172859729.464657.191600@s48g2000cws.googlegroups.com>
On Mar 1, 10:47 pm, Ken Tilton <·········@gmail.com> wrote:
> lb-sdl is interesting. A kazillion libraries, not a few
> dead links, and no unifying GUI or app framework.
> Maybe the LB should stand for "lotsabindings"?

Good point. I think a single lb-sdl package that contains lb-sdl-
image, lb-sdl-gfx, lb-sdl-mixer, lb-sdl-net and lb-sdl-ttf would be
more workable. The user should still have the ability to load each
package into his Lisp environment separately but at least these
packages won't be separate downloads. And making releases on
sourceforge will become a whole lot less tedious.

The dead links are a reminder for me to write the documentation.

- Luke
From: Thomas A. Russ
Subject: Re: A style question
Date: 
Message-ID: <ymiejo97vqk.fsf@sevak.isi.edu>
"Tim Bradshaw" <··········@tfeb.org> writes:
> 
> Incidentally, I'm deeply disappointed in the quality of answers in
> this thread.  In the elder days there would have been at least a few
> followups showing how to do this in the proper "FORMAT string
> indistinguishable from line noise" way.  No true CL programmer ever
> uses any other construct when the problem can be solved with a
> combination of FORMAT, LOOP & GO (FORMAT being always preferable,
> obviously).  There may yet be those reading cll who know this, though
> I suspect they have all gone into the west now.

Well, OK -- I have gone into the West, but I stopped just short of the
Pacific Ocean.  Obviously this requires some finesse since we don't want
to have to specify arguments more than once.  So we do need to obscurely
move back and forth along the argument list:

(dotimes (i 20)
  (format t "~[Fizz~:;~]~[Buzz~*~:;~2:*~[~2*~:;~*~D~]~]~%"
         (mod i 3) (mod i 5) i))

Now this is just way too obscure for me -- and it looks vaguely like
Perl code ;)

My real preference for doing it using format would be for a solution
more like:

(dotimes (i 20)
  (let ((divisible-by-3-p (zerop (mod i 3)))
        (divisible-by-5-p (zerop (mod i 5))))
    (format t ··@[Fizz~*~]·@[Buzz~*~]~:[~D~:;~*~]~%"
            divisible-by-3-p divisible-by-5-p
            (or divisible-by-3-p divisible-by-5-p)
            i)))



Although for production code I would take one of the cond-based
programming solutions over trying to do this with format




-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: lojic
Subject: Re: A style question
Date: 
Message-ID: <1172719148.689770.200300@8g2000cwh.googlegroups.com>
On Feb 28, 5:39 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> Well, OK -- I have gone into the West, but I stopped just short of the
> Pacific Ocean.  Obviously this requires some finesse since we don't want
> to have to specify arguments more than once.  So we do need to obscurely
> move back and forth along the argument list:
>
> (dotimes (i 20)
>   (format t "~[Fizz~:;~]~[Buzz~*~:;~2:*~[~2*~:;~*~D~]~]~%"
>          (mod i 3) (mod i 5) i))
>
> Now this is just way too obscure for me -- and it looks vaguely like
> Perl code ;)

Disturbing yet impressive. Anyone want to give a hand to the newbie in
understanding the above?

Brian
From: Tim Bradshaw
Subject: Re: A style question
Date: 
Message-ID: <1172749611.294912.88710@s48g2000cws.googlegroups.com>
On Mar 1, 3:19 am, "lojic" <···········@gmail.com> wrote:

> Disturbing yet impressive. Anyone want to give a hand to the newbie in
> understanding the above?

Surely it's self evident?  I mean it has hardly any parens, and
everyone knows the problem with Lisp is the parens.
From: John Thingstad
Subject: Re: A style question
Date: 
Message-ID: <op.tohsydolpqzri1@pandora.upc.no>
On Thu, 01 Mar 2007 04:19:08 +0100, lojic <···········@gmail.com> wrote:

> On Feb 28, 5:39 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
>> Well, OK -- I have gone into the West, but I stopped just short of the
>> Pacific Ocean.  Obviously this requires some finesse since we don't want
>> to have to specify arguments more than once.  So we do need to obscurely
>> move back and forth along the argument list:
>>
>> (dotimes (i 20)
>>   (format t "~[Fizz~:;~]~[Buzz~*~:;~2:*~[~2*~:;~*~D~]~]~%"
>>          (mod i 3) (mod i 5) i))
>>
>> Now this is just way too obscure for me -- and it looks vaguely like
>> Perl code ;)
>
> Disturbing yet impressive. Anyone want to give a hand to the newbie in
> understanding the above?
>
> Brian
>

Shouldn't be necessary. The key to this cypher is in
the ANSI document under format options.

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Thomas A. Russ
Subject: Re: A style question
Date: 
Message-ID: <ymiy7mf5zyy.fsf@sevak.isi.edu>
"John Thingstad" <··············@chello.no> writes:

> On Thu, 01 Mar 2007 04:19:08 +0100, lojic <···········@gmail.com> wrote:
> 
> > On Feb 28, 5:39 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> >> Well, OK -- I have gone into the West, but I stopped just short of the
> >> Pacific Ocean.  Obviously this requires some finesse since we don't want
> >> to have to specify arguments more than once.  So we do need to obscurely
> >> move back and forth along the argument list:
> >>
> >> (dotimes (i 20)
> >>   (format t "~[Fizz~:;~]~[Buzz~*~:;~2:*~[~2*~:;~*~D~]~]~%"
                  aaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
                                   cc   ddddeeeeeeeeeeeeee
                                              ffff  gggg

> >>          (mod i 3) (mod i 5) i))
               arg 0     arg 1   arg 2

a  uses arg 0 and chooses the first clause on a 0 value, otherwise the
   second (empty clause)
b  uses arg 1 and choose the first clause on a 0 value, otherwise the
   large second clause.
c  consumes arg 2 using the ~* directive.  Not strictly necessary in
   this format string, but it's good hygiene to not leave arguments
   unprocessed , especially if you ever want to add this to another,
   larger string.
d  backs up the argument pointer 2 places so that we will process arg 0
   again with the next format directive
e  uses arg 0 and chooses the first clause (f) on a 0 value, otherwise the
   second clause (g)
f  since we handled this case in directive (a), we just consume the next
   two arguments, arg 1 and arg 2 for hygiene.
g  We get here if both arg 0 and arg 1 are non-zero, but the testing
   was done in the reverse order.  So we consume arg 1 and then print
   arg 2

> >>
> >> Now this is just way too obscure for me -- and it looks vaguely like
> >> Perl code ;)
> >
> > Disturbing yet impressive. Anyone want to give a hand to the newbie in
> > understanding the above?
> >
> > Brian
> >
> 
> Shouldn't be necessary. The key to this cypher is in
> the ANSI document under format options.

Well, as the author, I fell somewhat obligated....

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Barry Fishman
Subject: Re: A style question
Date: 
Message-ID: <m3d53u9sjk.fsf@bfishman.alum.rpi.edu>
"Tim Bradshaw" <··········@tfeb.org> writes:
> Incidentally, I'm deeply disappointed in the quality of answers in
> this thread.  In the elder days there would have been at least a few
> followups showing how to do this in the proper "FORMAT string
> indistinguishable from line noise" way.  No true CL programmer ever
> uses any other construct when the problem can be solved with a
> combination of FORMAT, LOOP & GO (FORMAT being always preferable,
> obviously).  There may yet be those reading cll who know this, though
> I suspect they have all gone into the west now.

I'm not a good practitioner of FORMAT, but there needs to be at least
one FORMAT solution presented.

(defun fizz-buzz (n)
  (loop for i from 1 to n do
        (format t "~[~d~;Fizz~;Buzz~;FizzBuzz~]~%"
                (+ (if (zerop (mod i 3)) 1 0)
                   (if (zerop (mod i 5)) 2 0))
                i)))

-- 
Barry Fishman
From: lojic
Subject: Re: A style question
Date: 
Message-ID: <1172716708.957089.253850@h3g2000cwc.googlegroups.com>
On Feb 28, 5:33 am, "Tim Bradshaw" <··········@tfeb.org> wrote:
> On Feb 28, 2:02 am, ·············@craigslist.org wrote:
> >     Is this a minority view? One of the things that attracted me to Lisp
> > was the simplicity, consistency, etc. of the language, so when I read
> > the above, it seemed reasonable.
>
> Simplicity? consistency?  I think you're thinking of some other
> language there.  CL is this vast industrial thing full of enormous
> machines, oil and rust.

I was referring to the syntax in particular e.g. (foo a b) and the
fact that the syntax makes it easier to generate and manipulate Lisp
code.

> Some compartments are full of water, and no
> one knows what some of the machines do, if anything.  Many parts of it
> use a mixture of Whitworth & BSF threads (some left-handed), though
> much has now been converted to BA or metric, sometimes by use of taps
> & dies, sometimes with a hammer.
>
> CL's closest living relative is FORTRAN: always remember that.
>
> Incidentally, I'm deeply disappointed in the quality of answers in
> this thread.  In the elder days there would have been at least a few
> followups showing how to do this in the proper "FORMAT string
> indistinguishable from line noise" way.  No true CL programmer ever
> uses any other construct when the problem can be solved with a
> combination of FORMAT, LOOP & GO (FORMAT being always preferable,
> obviously).  There may yet be those reading cll who know this, though
> I suspect they have all gone into the west now.
>
> --tim (who has used the FORMAT string mentioned inhttp://www.tfeb.org/lisp/obscurities.htmlin anger)
From: John Thingstad
Subject: Re: A style question
Date: 
Message-ID: <op.togfxisxpqzri1@pandora.upc.no>
On Wed, 28 Feb 2007 03:02:46 +0100, <·············@craigslist.org> wrote:

> Frank Buss wrote:
>> ·············@craigslist.org wrote:
>>
>>> I cranked out a Lisp version. It seems a bit clunky, so I thought I'd  
>>> see if anyone had suggestions for improvements.
>>  looks ok, but I would use loop and organize the body of the loop a bit
>> different:
>>  (defun fizz-buzz (n)
>>   (loop for i from 1 to n
>>         for fizz = (zerop (mod i 3))
>>         for buzz = (zerop (mod i 5)) do
>>         (when fizz (princ "Fizz"))
>>         (when buzz (princ "Buzz"))
>>         (when (not (or fizz buzz)) (princ i))
>>         (terpri)))
>>
>
> Thanks. Some questions/comments:
>
> 1) In "ANSI Common Lisp", Graham makes the following comments:
>     "The loop macro was originally designed to help inexperienced Lisp  
> users write iterative code...Unfortunately, loop is more like English  
> than its designers ever intended...to understand it in the abstract is  
> almost impossible...For such reasons, the use of loop cannot be  
> recommended."
>

You will find the same recommendation from Peter Norwig in "Paradigms of  
AI programming".
Something along the line: 'loop has a syntax that looks like English,  
unfortunately
it is nothing like English.

This is true.
For many years most lispers avoided loop. (except simplified loop)

I think the description in the ANSI CL standard entry on 'loop is next to
unreadable. This is probably the real reason it wasn't used.
What you need to learn 'loop is tons of examples.

Then along came Peter Seibels book "Practical Common Lisp"
in particular the chapter "Loop for black belts".
I know it taught me 'loop as it probably did most of the people here.
Yes 'loop's syntax is not intuitive (though highly readable).
In my opinion it's power makes it worth while to learn.

Whether you use it or not is a matter of taste.
There are other alternatives.
There is always 'do or there is a iterator package.

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Frank Buss
Subject: Re: A style question
Date: 
Message-ID: <1tcg9rlvzoopb.1e825ofc3kuk4.dlg@40tude.net>
·············@craigslist.org wrote:

> 1) In "ANSI Common Lisp", Graham makes the following comments:
>     "The loop macro was originally designed to help inexperienced Lisp 
> users write iterative code...Unfortunately, loop is more like English 
> than its designers ever intended...to understand it in the abstract is 
> almost impossible...For such reasons, the use of loop cannot be 
> recommended."

I don't agree. You can learn the basics by reading loop examples. Once you
know how each loop word works, all you need is the BNF, if you forgot
something. The more you use it, the more you learn the grammar and the
easier it is to use it. Like all good DSLs, it helps a lot to write short
and easy to understand code for the task for which it is designed:
iterating.

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Thierry Pirot
Subject: Re: A style question
Date: 
Message-ID: <83mz2zuh1q.fsf@thierrypirot.net>
 job-271842874 writes:

> (defun fizz-buzz (n)
>    (do ((i 1 (+ i 1)))
>      ((> i n))
>      (let
>        ((fizz (= 0 (mod i 3)))
>         (buzz (= 0 (mod i 5))))
>        (if fizz (format t "Fizz"))
>        (if buzz (format t "Buzz"))
>        (format t "~A~%"
>                (if (or fizz buzz) "" i)))))
> 
> (fizz-buzz 100)
> 
In a more functional style, my 2 cents, 

CL-USER> (defun printing (i) 
	   (format t "~a~%"
	     (cond 
	       ((= 0 (mod i 3)) "Fizz")
	       ((= 0 (mod i 5)) "Buzz")
	       (t i))))

CL-USER> (defun fb (i n) 
	   (when (< i n)
	     (printing i)
	     (fb (1+ i) n)))

CL-USER> (fb 1 100)
-- 
   Take it Easy          Don't worry            Be Happy

                           Thierry

�������o�o��������o�o��������o�o��������o�o��������o�o�������
From: Thierry Pirot
Subject: Re: A style question
Date: 
Message-ID: <83irdnufqe.fsf@thierrypirot.net>
Thierry Pirot  writes:

>  job-271842874 writes:
> 
> > (defun fizz-buzz (n)
> >    (do ((i 1 (+ i 1)))
> >      ((> i n))
> >      (let
> >        ((fizz (= 0 (mod i 3)))
> >         (buzz (= 0 (mod i 5))))
> >        (if fizz (format t "Fizz"))
> >        (if buzz (format t "Buzz"))
> >        (format t "~A~%"
> >                (if (or fizz buzz) "" i)))))
> > 
> > (fizz-buzz 100)
> > 
> In a more functional style, my 2 cents, 
> 
Ups, it's late here...
> CL-USER> (defun printing (i) 
> 	   (format t "~a~%"
> 	     (cond 
                ((= 0 (mod i (* 3 5))) "FizzBuzz")
> 	       ((= 0 (mod i 3)) "Fizz")
> 	       ((= 0 (mod i 5)) "Buzz")
> 	       (t i))))
From: ·············@craigslist.org
Subject: Re: A style question
Date: 
Message-ID: <6a7Fh.42520$19.9544@bignews3.bellsouth.net>
Thierry Pirot wrote:
> Thierry Pirot  writes:
> 
>>  job-271842874 writes:
>>
>>> (defun fizz-buzz (n)
>>>    (do ((i 1 (+ i 1)))
>>>      ((> i n))
>>>      (let
>>>        ((fizz (= 0 (mod i 3)))
>>>         (buzz (= 0 (mod i 5))))
>>>        (if fizz (format t "Fizz"))
>>>        (if buzz (format t "Buzz"))
>>>        (format t "~A~%"
>>>                (if (or fizz buzz) "" i)))))
>>>
>>> (fizz-buzz 100)
>>>
>> In a more functional style, my 2 cents, 
>>
> Ups, it's late here...
>> CL-USER> (defun printing (i) 
>> 	   (format t "~a~%"
>> 	     (cond 
>                 ((= 0 (mod i (* 3 5))) "FizzBuzz")
>> 	       ((= 0 (mod i 3)) "Fizz")
>> 	       ((= 0 (mod i 5)) "Buzz")
>> 	       (t i))))
> 

Maybe I'm reading this incorrectly, but wouldn't that always print i? 
Printing i is mutually exclusive with printing "Fizz" and/or "Buzz".
From: justinhj
Subject: Re: A style question
Date: 
Message-ID: <1172635615.403918.94360@8g2000cwh.googlegroups.com>
(defun multiple(x n)
  (= 0 (mod x n)))

(defun output-multiple(x n str)
  (if (and (multiple x n) (princ str))
      1
    0))

(defun fizzbuzz(n)
  (loop for x from 1 to n do
        (if (> (+ (output-multiple x 3 "fizz") (output-multiple x 5
"buzz")) 0)
            (format t "~%"))))
From: ·············@craigslist.org
Subject: Re: A style question
Date: 
Message-ID: <7A7Fh.42528$19.27826@bignews3.bellsouth.net>
justinhj wrote:
> (defun multiple(x n)
>   (= 0 (mod x n)))
> 
> (defun output-multiple(x n str)
>   (if (and (multiple x n) (princ str))
>       1
>     0))
> 
> (defun fizzbuzz(n)
>   (loop for x from 1 to n do
>         (if (> (+ (output-multiple x 3 "fizz") (output-multiple x 5
> "buzz")) 0)
>             (format t "~%"))))
> 

Hmm.. this doesn't seem to work.

[1]> (defun multiple(x n)
   (= 0 (mod x n)))
MULTIPLE
[2]>
(defun output-multiple(x n str)
   (if (and (multiple x n) (princ str))
       1
     0))
OUTPUT-MULTIPLE
[3]>
(defun fizzbuzz(n)
   (loop for x from 1 to n do
         (if (> (+ (output-multiple x 3 "fizz") (output-multiple x 5
"buzz")) 0)
             (format t "~%"))))
FIZZBUZZ
[4]> (fizzbuzz 12)
fizz
buzz
fizz
fizz
buzz
fizz
NIL
[5]>
From: justinhj
Subject: Re: A style question
Date: 
Message-ID: <1172677864.947842.240470@h3g2000cwc.googlegroups.com>
On Feb 27, 11:31 pm, ·············@craigslist.org wrote:
> justinhj wrote:
> > (defun multiple(x n)
> >   (= 0 (mod x n)))
>
> > (defun output-multiple(x n str)
> >   (if (and (multiple x n) (princ str))
> >       1
> >     0))
>
> > (defun fizzbuzz(n)
> >   (loop for x from 1 to n do
> >         (if (> (+ (output-multiple x 3 "fizz") (output-multiple x 5
> > "buzz")) 0)
> >             (format t "~%"))))
>
> Hmm.. this doesn't seem to work.
>
> [1]> (defun multiple(x n)
>    (= 0 (mod x n)))
> MULTIPLE
> [2]>
> (defun output-multiple(x n str)
>    (if (and (multiple x n) (princ str))
>        1
>      0))
> OUTPUT-MULTIPLE
> [3]>
> (defun fizzbuzz(n)
>    (loop for x from 1 to n do
>          (if (> (+ (output-multiple x 3 "fizz") (output-multiple x 5
> "buzz")) 0)
>              (format t "~%"))))
> FIZZBUZZ
> [4]> (fizzbuzz 12)
> fizz
> buzz
> fizz
> fizz
> buzz
> fizz
> NIL
> [5]>

Unless I'm misunderstanding something what doesn't work? The output is
correct.

Justin
From: justinhj
Subject: Re: A style question
Date: 
Message-ID: <1172680317.390793.34360@h3g2000cwc.googlegroups.com>
On Feb 28, 10:51 am, "justinhj" <········@gmail.com> wrote:
> On Feb 27, 11:31 pm, ·············@craigslist.org wrote:
>
>
>
> > justinhj wrote:
> > > (defun multiple(x n)
> > >   (= 0 (mod x n)))
>
> > > (defun output-multiple(x n str)
> > >   (if (and (multiple x n) (princ str))
> > >       1
> > >     0))
>
> > > (defun fizzbuzz(n)
> > >   (loop for x from 1 to n do
> > >         (if (> (+ (output-multiple x 3 "fizz") (output-multiple x 5
> > > "buzz")) 0)
> > >             (format t "~%"))))
>
> > Hmm.. this doesn't seem to work.
>
> > [1]> (defun multiple(x n)
> >    (= 0 (mod x n)))
> > MULTIPLE
> > [2]>
> > (defun output-multiple(x n str)
> >    (if (and (multiple x n) (princ str))
> >        1
> >      0))
> > OUTPUT-MULTIPLE
> > [3]>
> > (defun fizzbuzz(n)
> >    (loop for x from 1 to n do
> >          (if (> (+ (output-multiple x 3 "fizz") (output-multiple x 5
> > "buzz")) 0)
> >              (format t "~%"))))
> > FIZZBUZZ
> > [4]> (fizzbuzz 12)
> > fizz
> > buzz
> > fizz
> > fizz
> > buzz
> > fizz
> > NIL
> > [5]>
>
> Unless I'm misunderstanding something what doesn't work? The output is
> correct.
>
> Justin

I'm not having much luck trying to make it elegant and concise but I
quite like this recursive version...

(defun fizzbuzz2(n)
  (labels ((fizzbuzz-rec (current last fizz buzz)
                         (let ((output nil))
                           (if (= 0 fizz)
                               (push "fizz" output))
                           (if (= 0 buzz)
                               (push "buzz" output))
                           (if output
                               (format t "~{~a~}~%" output))
                           (unless (= current last)
                             (fizzbuzz-rec (1+ current) last (mod (1-
fizz) 3) (mod (1- buzz) 5))))))
    (fizzbuzz-rec 1 n (1- 3) (1- 5))))

CL-USER> (fizzbuzz2 15)
fizz
buzz
fizz
fizz
buzz
fizz
buzzfizz


Justin
From: justinhj
Subject: Re: A style question
Date: 
Message-ID: <1172688944.450699.265520@v33g2000cwv.googlegroups.com>
On Feb 28, 11:31 am, "justinhj" <········@gmail.com> wrote:
> On Feb 28, 10:51 am, "justinhj" <········@gmail.com> wrote:
>
>
>
> > On Feb 27, 11:31 pm, ·············@craigslist.org wrote:
>
> > > justinhj wrote:
> > > > (defun multiple(x n)
> > > >   (= 0 (mod x n)))
>
> > > > (defun output-multiple(x n str)
> > > >   (if (and (multiple x n) (princ str))
> > > >       1
> > > >     0))
>
> > > > (defun fizzbuzz(n)
> > > >   (loop for x from 1 to n do
> > > >         (if (> (+ (output-multiple x 3 "fizz") (output-multiple x 5
> > > > "buzz")) 0)
> > > >             (format t "~%"))))
>
> > > Hmm.. this doesn't seem to work.
>
> > > [1]> (defun multiple(x n)
> > >    (= 0 (mod x n)))
> > > MULTIPLE
> > > [2]>
> > > (defun output-multiple(x n str)
> > >    (if (and (multiple x n) (princ str))
> > >        1
> > >      0))
> > > OUTPUT-MULTIPLE
> > > [3]>
> > > (defun fizzbuzz(n)
> > >    (loop for x from 1 to n do
> > >          (if (> (+ (output-multiple x 3 "fizz") (output-multiple x 5
> > > "buzz")) 0)
> > >              (format t "~%"))))
> > > FIZZBUZZ
> > > [4]> (fizzbuzz 12)
> > > fizz
> > > buzz
> > > fizz
> > > fizz
> > > buzz
> > > fizz
> > > NIL
> > > [5]>
>
> > Unless I'm misunderstanding something what doesn't work? The output is
> > correct.
>
> > Justin
>
> I'm not having much luck trying to make it elegant and concise but I
> quite like this recursive version...
>
> (defun fizzbuzz2(n)
>   (labels ((fizzbuzz-rec (current last fizz buzz)
>                          (let ((output nil))
>                            (if (= 0 fizz)
>                                (push "fizz" output))
>                            (if (= 0 buzz)
>                                (push "buzz" output))
>                            (if output
>                                (format t "~{~a~}~%" output))
>                            (unless (= current last)
>                              (fizzbuzz-rec (1+ current) last (mod (1-
> fizz) 3) (mod (1- buzz) 5))))))
>     (fizzbuzz-rec 1 n (1- 3) (1- 5))))
>
> CL-USER> (fizzbuzz2 15)
> fizz
> buzz
> fizz
> fizz
> buzz
> fizz
> buzzfizz
>
> Justin

Note: just realised you have to swap the order of the buzz print with
the fizz print to get the correct output ;)

Justin
From: lojic
Subject: Re: A style question
Date: 
Message-ID: <1172717564.222611.146910@8g2000cwh.googlegroups.com>
On Feb 28, 10:51 am, "justinhj" <········@gmail.com> wrote:
> On Feb 27, 11:31 pm, ·············@craigslist.org wrote:
>
>
>
> > justinhj wrote:
> > > (defun multiple(x n)
> > >   (= 0 (mod x n)))
>
> > > (defun output-multiple(x n str)
> > >   (if (and (multiple x n) (princ str))
> > >       1
> > >     0))
>
> > > (defun fizzbuzz(n)
> > >   (loop for x from 1 to n do
> > >         (if (> (+ (output-multiple x 3 "fizz") (output-multiple x 5
> > > "buzz")) 0)
> > >             (format t "~%"))))
>
> > Hmm.. this doesn't seem to work.
>
> > [1]> (defun multiple(x n)
> >    (= 0 (mod x n)))
> > MULTIPLE
> > [2]>
> > (defun output-multiple(x n str)
> >    (if (and (multiple x n) (princ str))
> >        1
> >      0))
> > OUTPUT-MULTIPLE
> > [3]>
> > (defun fizzbuzz(n)
> >    (loop for x from 1 to n do
> >          (if (> (+ (output-multiple x 3 "fizz") (output-multiple x 5
> > "buzz")) 0)
> >              (format t "~%"))))
> > FIZZBUZZ
> > [4]> (fizzbuzz 12)
> > fizz
> > buzz
> > fizz
> > fizz
> > buzz
> > fizz
> > NIL
> > [5]>
>
> Unless I'm misunderstanding something what doesn't work? The output is
> correct.
>
> Justin

The output should be:
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
...
From: Thierry Pirot
Subject: Re: A style question
Date: 
Message-ID: <83ejoav3py.fsf@thierrypirot.net>
 job-271842874writes:
> Thierry Pirot wrote:

> >> CL-USER> (defun printing (i) 	   
> >>            (format t "~a~%"
> >> 	         (cond
> >                 ((= 0 (mod i (* 3 5))) "FizzBuzz")
> >> 	           ((= 0 (mod i 3)) "Fizz")
> >> 	           ((= 0 (mod i 5)) "Buzz")
> >> 	           (t i))))

> Maybe I'm reading this incorrectly, but wouldn't that always print i?
>
Let's run 
CL-USER> (printing 3)
Fizz
NIL
CL-USER> (printing 4)
4
NIL
CL-USER> (printing 5)
Buzz
NIL
CL-USER> (printing 30)
FizzBuzz
NIL

Let's read 
http://www.lispworks.com/documentation/HyperSpec/Body/m_cond.htm
cond, a root of Lisp, is not a function, 
it sequentially evaluates its clauses' antecedent until one is true and then 
returns the evaluation of the consequent.  
t in the last clause can be thought of as an "otherwise".  
-- 
   Take it Easy          Don't worry            Be Happy

                           Thierry

�������o�o��������o�o��������o�o��������o�o��������o�o�������
From: Fred Gilham
Subject: Re: A style question
Date: 
Message-ID: <u7y7mfw521.fsf@snapdragon.csl.sri.com>
It's fun to see all the different techniques people have brought to
bear on this problem.  I can imagine someone writing a programming
book taking all these different programs and using them to illustrate
various programming paradigms and methodologies.

Here's an extensible version that uses a list of closures as filters.


(defvar *fizzers* nil)

(defun make-fizzer (n string)
  (lambda (i)
    (and (zerop (mod i n)) (princ string))))

;; Obviously order matters here....
(push (make-fizzer 5 "Buzz") *fizzers*)
(push (make-fizzer 3 "Fizz") *fizzers*)

(defun map-fizzers (n)
  (map 'list 
       (lambda (f)
	 (funcall f n))
       *fizzers*))

(defun fizz-buzz (n)
  (dotimes (i n)
    (or (notevery #'null (map-fizzers (1+ i)))
	(princ (1+ i)))
    (terpri)))

-- 
Fred Gilham                                  ······@csl.sri.com
And then [Clinton] turned to Hunter Thompson, of all people, and said
with wholehearted fervor, "We're going to put one hundred thousand new 
police officers on the street."
I was up all night persuading Hunter that this was not a personal
threat.                                              -- P. J. O'Rourke
From: ctnd
Subject: Re: A style question
Date: 
Message-ID: <1173023064.063658.93150@64g2000cwx.googlegroups.com>
Someone had to come up with the horrible solution:

(defun fb (start finish tests otherwise)
  (loop for n from start to finish
        for tested-t = nil do
        (loop for test in tests
              while (if (funcall (first test) n)
                        (progn
                          (funcall (second test) n)
                          (setf tested-t t)
                          nil)
                        t))
        (if (not tested-t) (funcall otherwise n)))))

(defun fizz-buzz-example ()
    (fb 1 100 (list
               (list
                #'(lambda (n) (and (zerop (mod n 3)) (zerop (mod n
5))))
                #'(lambda (n) (print "FizzBuzz")))
               (list
                #'(lambda (n) (zerop (mod n 3)))
                #'(lambda (n) (print "Fizz")))
               (list
                #'(lambda (n) (zerop (mod n 5)))
                #'(lambda (n) (print "Buzz"))))
     #'print))
From: Wade Humeniuk
Subject: Re: A style question
Date: 
Message-ID: <kRCGh.10911$lY6.3692@edtnps90>
ctnd wrote:
> Someone had to come up with the horrible solution:

There is nothing wrong with that solution.  Its legit.

Here is another generalized solution using the approach
I previously used.  I removed MOD as it is not needed.

(defun fbv (i map)
   (or (remove nil (mapcar (lambda (mod)
                             (and (integerp (/ i (car mod))) (cadr mod)))
                           map))
       (list i)))


(defun fizzbuzz (n map)
   (loop for i from 1 to n do (format t "~{~A~}~%" (fbv i map))))


CL-USER 21 > (fizzbuzz 15 '((3 "Fizz") (5 "Buzz") (8 "Gack")))
1
2
Fizz
4
Buzz
Fizz
7
Gack
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
NIL

CL-USER 23 > (fbv 40 '((3 "Fizz") (5 "Buzz") (8 "Gack")))
("Buzz" "Gack")

CL-USER 24 > (fbv 120 '((3 "Fizz") (5 "Buzz") (8 "Gack")))
("Fizz" "Buzz" "Gack")

CL-USER 25 > (fbv 49 '((3 "Fizz") (5 "Buzz") (8 "Gack")))
(49)

CL-USER 26 >