Thanks for the summary, Yanyan!
> 3. PAPL's design recipe teaches recursion at the very beginning, instead of
> focusing on iteration. So another way to tackle the problem is to think in
> terms of input-output and designing reusable recursive functions. (Shriram
> explained this idea better in his reply above)
It's worth saying that there are two separate ideas here:
1. Thinking in terms of input-output, which helps us design reusable,
testable functions
2. Designing specifically _recursive_ functions
The first urges you to write this program as a function rather than a
toplevel printing statement, whether the function is recursive or
iterative or whatever. This gives us a function that's testable,
parameterizable, etc.
It turns out that there's a whole bunch of good pedagogic reasons to
do the latter (learning to write recursive functions) in order to get
to the former (implementations of input-output specifications).
But it's obviously not true that all good reusable functions are
recursively implemented. So it's worth asking how we can write
iterative(-looking) programs to do the former.
In this case, something like "for find(...): ... end" would work well,
if we had a good way to get the cross-product of two lists and iterate
over it. Here's a solution that uses tuples (upcoming feature! more
on that soon) to do that, in a nicely iterative-looking solution that
stops at the right answer:
https://pyret-horizon.herokuapp.com/editor#share=0B32bNEogmncOWEVpdFhxTVdnVXM
(The weakness of this solution is that is creates the whole one
million-length list first to traverse. It would be nice to not do
that work somehow, which the recursive solution accomplished. In the
for loop, we'd need a better lazy version of cross() to avoid creating
the big list first.)