Andrew Welch wrote:
Nice! However a couple of small problems:
2 bottles of beer on the wall.
2 bottles of beer.
Take one down, pass it around
1 bottles of beer on the wall.
^^^^^^^
1 bottle of beer on the wall.
1 bottle of beer.
Take one down, pass it around
0 bottle of beer on the wall.
^^^^^^^^
You just need to modify it slightly:
Thanks for the correction. But now we have duplicated logic (the cast +
ends-with), which some consider bad programming practice. Here's an
update that does not duplicate the logic, removes the nested for
(better: it shows a way of shortcutting nested loops with the comma
operator), corrects my error and is much less readable (which was not on
purpose, btw).
for $i in reverse(1 to 99),
$j in (1 to 3)
return concat
($i - xs:integer($j mod 3 = 0),
' bottle',
('s')[not($i * 3 - $j = (1 to 3))],
' of beer',
(' on the wall.',
'. Take one down, pass it around',
' on the wall. ' )[$j]
(I like the idea of using the predicate instead of if...then...else)
As a tutorial it suits well for explaining why:
('s')[$i * 3 - $j != (1 to 3)]
yields exactly the same result as:
('s')[$i * 3 - $j = (1 to 3)]
which is quite counter-intuitive (IIRC, for a '!=' to return false, none
from the left must be the same as any from the right; to be true, only
one item needs to be unequal. This is not backed up by the example
above, but I am sure I am overlooking something. Moreover, I found that
(1 to 2) != 10 returns false, and (1,2) != 10 returns true.... I am
really missing something here, this must be a faq somewhere :S ).
Cheers,
-- Abel Braaksma
http://www.nuntia.nl