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
·············@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
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
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
>
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).
·············@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
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
>
·············@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
>>
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/
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
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
·············@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
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
<·············@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
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
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
<·············@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
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.
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"))))
<········@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
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
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
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
>
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).
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
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
····@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)))))
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
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
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
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
<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
···············@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)
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
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
·············@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
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
>
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
> >
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
·············@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�
--
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/
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
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/
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/
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
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
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
·············@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
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
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
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
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
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).
·············@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
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
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
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)
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
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
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).
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).
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
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
"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
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
"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
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/
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
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
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).
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
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
+ 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
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
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
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)))
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.
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.
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.
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)
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
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))))
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).
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.
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
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
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
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
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
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
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
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
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
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
"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
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
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.
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/
"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
"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
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)
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/
·············@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
(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 "~%"))))
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�������
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
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))
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 >