[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

simple loops and recursion

ishamid

11/27/2006 4:34:00 AM

Hi,

I'm a total newbie, and this is my very first message. I'm going
through Chris Pine's Learn to Program; almost half done.

Problem: Consider the following working code:

===============
def repeat type
number_of_bottles = '99'
while number_of_bottles != '0'
puts number_of_bottles.to_s + ' bottles:' + ' If one falls, ' +
(number_of_bottles.to_i - 1).to_s + ' bottles.'
type + (number_of_bottles.to_i - 1).to_s + ':'
number_of_bottles = gets.chomp
end
end

repeat 'Type '
===============

I want to add a recursion conditional: If there are 98 bottles left,
one should type '98'; if there are 97, one should type '97' etc. At 0
bottles the programs ends. What I want is an additional conditional
recursion, so that e.g. if, at 98 bottles, I type anything other than
'98', the program recursively tells me to type '98' until I type '98'.

Every way I've tried this gives me a " undefined local variable or
method `number_of_bottles' " type of error, or else the program keeps
going back to 99.

Thanks in advance
Idris

9 Answers

Edwin Fine

11/27/2006 6:07:00 AM

0

> def repeat type
> number_of_bottles = '99'
> while number_of_bottles != '0'
> puts number_of_bottles.to_s + ' bottles:' + ' If one falls, ' +
> (number_of_bottles.to_i - 1).to_s + ' bottles.'
> type + (number_of_bottles.to_i - 1).to_s + ':'
> number_of_bottles = gets.chomp
> end
> end
>
> repeat 'Type '
> ===============
>
> I want to add a recursion conditional: If there are 98 bottles left,

First of all, use of the term "recursion" is not correct here. Recursion
occurs when a function calls itself. The code above is iterative, not
recursive.

For example (this can be written more tersely but I am trying to
illustrate something clearly):

def factorial(n)
return 1 if n <= 1 # Termination condition
return n * factorial(n - 1) # Recursive call
end

factorial(6) => 720

The same thing iteratively is

def factorial(n)
fact = 1
n.downto(1) { |i| fact *= i }
fact
end

Second of all, your code uses strings where it should use integers.
Writing

while number_of_bottles != '0'

is doing a string comparison. '0' is a 1-character string consisting of
the character '0'. You really want an integer.

So, rewriting your code to be more Rubyish,

def repeat(type)
number_of_bottles = 99
while number_of_bottles != 0
puts "#{number_of_bottles} bottles: If one falls,
#{number_of_bottles - 1} bottles."
puts "#{type}#{number_of_bottles - 1}:"
number_of_bottles = gets.chomp.to_i
end
end

Now, to ensure that someone types in what you want, you should create a
simple function to get what you are looking for, e.g.

def expect(msg, expected_value)
puts "#{msg}#{expected_value}:"
loop do
actual_value = gets.chomp.to_i
return actual_value if actual_value == expected_value
puts "Sorry, expected #{expected_value} but got #{actual_value}"
end
end

Note that this function is not perfect; it does not check to see if an
actual integer was entered, so if people enter non-digits they will be
seen as 0 values. I leave this as a exercise for the reader...

Anyway, we now change the original function to the following:

def repeat(msg)
number_of_bottles = 99
while number_of_bottles != 0 do
puts "#{number_of_bottles} bottles: If one falls,
#{number_of_bottles - 1} bottles."
number_of_bottles = expect(msg, number_of_bottles - 1)
end
end

Hope this helps. I recommend buying and reading Pragmatic Programming in
Ruby. It will answer a lot of your Ruby questions.

--
Posted via http://www.ruby-....

dblack

11/27/2006 1:47:00 PM

0

ishamid

11/27/2006 9:16:00 PM

0

Thank you very much, Edwin, for your comments.

1. The recursive factorial was easy to follow; the iterative example
less so (still have a lot to learn). I will study both examples
carefully and I really appreciate the lesson!

2. (Keep in my mind my only previous experience programming is in TeX,
and not at a low level). For your second point, what makes code
"Rubyish". What benchmarks are there?

3. I will study your solution carefully. About books, etc.: My plan was
to get through Chris Pine (Learn to Program), then go through Mark
Slagell (Ruby in 21 Days), then plow through the PickAxe. Any
suggestions in this regard?

Thanks again for your help.

Idris

ishamid

11/27/2006 9:29:00 PM

0

An ambiguity:

I find it interesting that, in its output, Ruby (and I guess other
programming languages as well) have no convention for the use-mention
distinction. For example:

===================
def expect(msg, expected_value)
puts "#{msg}#{expected_value}:"
loop do
actual_value = gets.chomp.to_i
return actual_value if actual_value == expected_value
puts "Sorry, expected #{expected_value} but got #{actual_value}"
end
end

expect('We want ', '98')
===================

gives me

===================
Sorry, expected 98 but got 98
===================

Of course, the problem is that I entered a string not an integer.

The output does not distinguish number from numeral. Is this standard
or is there something else going on?

Best
Idris

ishamid

11/27/2006 9:42:00 PM

0

> def expect(msg, expected_value)
> puts "#{msg}#{expected_value}:"
> loop do
> actual_value = gets.chomp.to_i
> return actual_value if actual_value == expected_value
> puts "Sorry, expected #{expected_value} but got #{actual_value}"
> end
> end
>
> Note that this function is not perfect; it does not check to see if an
> actual integer was entered, so if people enter non-digits they will be
> seen as 0 values. I leave this as a exercise for the reader...

Is this too naive/non-Rubyish for what you had in mind? I just moved
the .to_i; it seems to work...

===========
def expect(msg, expected_value)
puts "#{msg}#{expected_value}:"
loop do
actual_value = gets.chomp
return actual_value if actual_value.to_i == expected_value
puts "Sorry, expected #{expected_value} but got #{actual_value}"
end
end

expect('We want ', 98)
===========

Thank you again

Idris

ishamid

11/27/2006 9:44:00 PM

0

> def expect(msg, expected_value)
> puts "#{msg}#{expected_value}:"
> loop do
> actual_value = gets.chomp.to_i
> return actual_value if actual_value == expected_value
> puts "Sorry, expected #{expected_value} but got #{actual_value}"
> end
> end
>
> Note that this function is not perfect; it does not check to see if an
> actual integer was entered, so if people enter non-digits they will be
> seen as 0 values. I leave this as a exercise for the reader...

Is this too naive/non-Rubyish for what you had in mind? I just moved
the .to_i; it seems to work...

===========
def expect(msg, expected_value)
puts "#{msg}#{expected_value}:"
loop do
actual_value = gets.chomp
return actual_value if actual_value.to_i == expected_value
puts "Sorry, expected #{expected_value} but got #{actual_value}"
end
end

expect('We want ', 98)
===========

Thank you again

Idris

Martin DeMello

11/27/2006 9:56:00 PM

0

On 11/28/06, ishamid <ishamid@colostate.edu> wrote:
> puts "Sorry, expected #{expected_value} but got #{actual_value}"
[...]

> gives me
>
> ===================
> Sorry, expected 98 but got 98
> ===================
>
> Of course, the problem is that I entered a string not an integer.
>
> The output does not distinguish number from numeral. Is this standard
> or is there something else going on?

When you interpolate an expression in a string, ruby first evaluates
it, then calls to_s on the result. 98.to_s = "98"

Here's an illustrative example - I'll define a class and give it a
to_s method, then create an object of that class and embed it inside a
string:

irb(main):001:0> class MyClass
irb(main):002:1> def to_s
irb(main):003:2> "hello world"
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> a = MyClass.new
=> hello world
irb(main):007:0> puts "the language that cannot print '#{a}' is not
the true language"
the language that cannot print 'hello world' is not the true language
=> nil

martin

ishamid

11/27/2006 9:59:00 PM

0


I leave this as a exercise for the reader...

Ok, here is the solution to the exercise :-)

==============
def expect(msg, expected_value)
puts "#{msg}#{expected_value}:"
loop do
actual_value = gets.chomp
return actual_value.to_i if actual_value.to_i == expected_value
puts "Sorry, expected #{expected_value} but got #{actual_value}"
end
end

# expect('We want ', 98) # test

def repeat(msg)
number_of_bottles = 99
while number_of_bottles != 0 do
puts "#{number_of_bottles} bottles: If one falls,
#{number_of_bottles - 1} bottles."
number_of_bottles = expect(msg, number_of_bottles - 1)
end
end

repeat('We want ')
==============

If I input a string, it comes back as a string, and everything else
works too. Thank you again for this lesson!

Now I will study David's approach...

Thnx again and
Best
Idris

doog

11/27/2006 10:25:00 PM

0

Try learning ruby in your browser with a live Ruby interpreter:
http://tryruby....

Start by typing "help" on the Ruby command line.
It's a lotta fun.

Don't let it sit idle for more than 10 minutes between chapters
or you'll need to start the chapter over from scratch.

If you stop, to move to chapter 2, type "help 2", to chapter 3,
type "help 3" and so on.

Took me a little over a half hour to go through the lessons.

-Doug

ishamid wrote:
> 3. I will study your solution carefully. About books, etc.: My plan was
> to get through Chris Pine (Learn to Program), then go through Mark
> Slagell (Ruby in 21 Days), then plow through the PickAxe. Any
> suggestions in this regard?
>
> Idris