Several people in this thread have mentioned repeat-until loops, and much of 
the discussion here seems to be about how to approximate them in Python. In 
readability dreamland:

tries_left = 5 # Must be > 0

repeat:
    guess = int(input("Guess? "))
    tries -= 1
until guess == secret or tries_left == 0

if guess == secret:
    print("You guessed it!")
else:
    print("You maxed out.")

A Racket friend of mine likes to point out the many times in our intro course 
where we state a problem by saying "do something until X", and then spend time 
figuring out how to shoehorn the problem into a while loop.

(Aside: Mark, I find your while-function approach to be thought provoking.)

-Paul Gries

On 2012-04-22, at 4:44 PM, Mark Engelberg wrote:

> John Zelle wrote:
> guess = int(input("Guess? "))
> while(guess != secret):  // as long as the user didn't get it, get another 
> guess
>    print("Nope, try again")
>    guess = int(input("Guess? "))
> // Here we know the condition is false
> print("You guessed it")
> 
> 
> I mostly find John Zelle's version to be more elegant, but I dislike that the 
> line:
> guess = int(input("Guess? "))
> occurs in two places.
> 
> In general, we should be discouraging writing the same line twice.  What if 
> you want to change the prompt?  What if you want to create more complex error 
> checking for the input.  Are you going to remember to change it in both 
> places?
> 
> One reasonable option is to break this out into a separate getGuess() 
> function.  You'd still end up with two calls to the getGuess() function, but 
> at least the logic of getting the guess could easily be changed in one place.
> 
> This begs the question, though, as to whether it is possible to rework the 
> code to only have one line which gets the guess, without involving continue, 
> break, or while(True).  
> 
> I don't believe there is a way.  If Python had tail recursion, one way to 
> rewrite this that satisfies all those constraints would be:
> 
> def repeatUntilSecretIsGuessed():
>   guess = int(input("Guess? "))
>   if (guess == secret):
>     print("You guessed it")
>   else:
>     print("Nope, try again")
>     repeatUntilSecretIsGuessed()
> 
> This would be bad form for Python, though.
> 
> One other thought about while/continue/break.  I am always thinking about the 
> fact that we're training kids for the languages and programming styles that 
> will emerge over the next 10+ years.  To better understand the future we're 
> preparing them for, I spend a lot of time studying emerging languages, 
> looking for clues about what styles will best "future-proof" my students.
> 
> In the case of while loops, I think it's instructive to look at Scala, a 
> language that is currently being hailed as the most plausible successor to 
> Java.  Scala doesn't have break or continue at all.  The idea is that if you 
> have a loop that requires a break, it is far clearer to make that loop into a 
> separate helper function, and use return instead of break.  So for example, 
> looking at Kirby's code:
> 
> while True:  # no ifs ands or buts
>    guess = int(input("Guess?: ")
>    if guess == secret:
>        print("You guessed it!")
>        break
>    else:
>        print("Nope, try again...")
> 
> you'd instead write it as:
> 
> def repeatUntilSecretIsGuessed():
>   while True:  
>     guess = int(input("Guess?: ")
>     if guess == secret:
>         print("You guessed it!")
>         return            
> # It's a bit easier to understand this code because we see it completely 
> exits the function here, not  just the while loop
>     else:
>         print("Nope, try again...")
> 
> In this example, the distinction seems a little silly, but I would argue that 
> the vast majority of while loops are, semantically speaking, "returning a 
> value".  They do this by setting up some accumulator variable before the 
> while loop, and then pounding on the variable, changing it each time through 
> the while loop.  It can take a bit of analysis to determine which is the 
> variable(s) you care about, and what it contains at the time you break out of 
> a loop.  By breaking the loop into a separate function, and actually 
> returning the value you care about with a return statement, the code becomes 
> much easier to understand.
> 
> So for example, let's say you want to keep looping until you get a guess from 
> 1 to 10.
> 
> Standard way (using while True and break) would be something like this:
> 
> while True:
>   guess = int(input("Guess a number from 1 to 10? "))
>   if (guess < 1 or guess > 10):
>      print ("Try again")
>   else:
>      break
> # at this point we continue our code, and we know guess contains a number 
> from 1 to 10
> 
> Better way:
> 
> def getNumberFrom1To10():
>   while True:
>     guess = int(input("Guess a number from 1 to 10? "))
>     if (guess < 1 or guess > 10):
>        print ("Try again")
>     else:
>        return guess
> # Now, it's really obvious what is the value that is being "set" by the while 
> loop.
> 
> In any case, whether you prefer Kirby's while True version or John's version 
> which requires asking for a guess both before the loop and inside the loop, 
> the main idea here is to get kids thinking each time they have a loop, 
> especially a loop that involves break, whether maybe the code would be better 
> if they factored out the loop into a separate function.
> 
> --Mark
> _______________________________________________
> Edu-sig mailing list
> Edu-sig@python.org
> http://mail.python.org/mailman/listinfo/edu-sig

_______________________________________________
Edu-sig mailing list
Edu-sig@python.org
http://mail.python.org/mailman/listinfo/edu-sig

Reply via email to