99 bottles of beer: Difference between revisions

→‎{{header|TXR}}: Shortened thanks to new lazy primitives.
(→‎{{header|Perl}}: Fix excessive line length.)
(→‎{{header|TXR}}: Shortened thanks to new lazy primitives.)
Line 4,471:
=={{header|TXR}}==
 
The <code>(range 99 -1 -1)</code> expression produces a lazy list of integers from 99 down to -1. The <code>mapcar*</code> function lazily maps these numbers to strings, and the rest of the code treats this lazy list as text stream to process, extracting the numbers with some pattern matching cases and interpolating them into the song's text. Functional programming with lazy semantics meets text processing, pattern matching and here documents.
Previously, this used an external command to generate a text stream of numbers from 99 to -1, one per line. For fun, this is now replaced by a lazy list, keeping the rest of the program intact: processes a stream of numbers and transforms then into the song. Lazy lists are based on lazy conses. A lazy cons is a special object which contains a function. When the object is accessed using the usual cons accessors, the function is called to fill in the car and cdr slots of the object. To terminate the list, the function writes a nil into the cdr. If the list is to be continued, the function can put a continuation tail into cdr, which can be a concrete list, or another lazy cons (which can re-use the same lazy cons function, using the trick shown in this example).
 
<lang txr>@(donext :list @(defunmapcar* lazy-textual-number-list(fun tostring) (minrange max99 -1 -1)))
(let ((counter min)
(delta (if (<= min max) 1 -1)))
(make-lazy-cons (lambda (lcons)
(rplaca lcons (format nil "~a" counter))
(cond
((eql counter max)
(rplacd lcons nil) t)
(t
(inc counter delta)
(rplacd lcons (make-lazy-cons
(lcons-fun lcons))))))))))
@(next :list @(lazy-textual-number-list 99 -1))
@(collect)
@number
Anonymous user