Mutually-Recursive Functions

  • Thread starter Revence Kalibwani
  • Start date
R

Revence Kalibwani

Ruby doesn't seem to do mutually-recursive functions. Or is it some
particular idiom I know not about? I am using an array to implement
them, and it stinks a bit. Any way to do it?

Thanks.

Revence
 
D

Dan Zwell

Revence said:
Ruby doesn't seem to do mutually-recursive functions. Or is it some
particular idiom I know not about? I am using an array to implement
them, and it stinks a bit. Any way to do it?

Thanks.

Revence

Could you show us what you mean? I for one do not know what a mutually
recursive function is.

Dan
 
R

Revence Kalibwani

--------------080502090604050007040806
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Dan said:
Could you show us what you mean? I for one do not know what a mutually
recursive function is.
I have written it all out. Now, since I'm fresh to this list, I dunno if
attachments show. Indulge me, please. I'll paste all the code (it's a
bit literate') and also attach it (as mutrec.rb). :)
By the way, ruby -v is: 1.8.5

#! /usr/bin/ruby
# Two examples of a mutually-recursive function.

# These are functions that depend on each other - recursively.

# even and odd:
# If a number is zero, then it is even. Otherwise, it is even if the one before it is odd.
# A number is odd if it is not zero. Otherwise, it is odd if it the one before it is even. :eek:)
# This is the canonical example.
def my_even(x)
x == 0 or odd(x - 1)
end

def my_odd(x)
x != 0 and even(x - 1)
end

# That is, of course, a silly way to implemet even and odd. So, let me give you the problem
# I was trying to solve.
#
# To generate the lettering similar to that above the spreadsheet columns, where the first
# column has 'A', the second 'B' ... the twenty-sixth 'Z'. Then, the twenty-seventh has
# 'AA', the twenty-eight has 'AB', and so on. This is recursive by nature. Here is what
# should work:


Letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z']

def alphabetise(pos)
pile_letters(0, pos) # LABEL: 1
end
def pile_chars(thus_far, pos)
len = Letters.length
if pos < len then
Letters[pos]
else
alphabeticise(thus_far) + pile_chars(thus_far + 1, pos - len)
end

end

# Labels:
# 1. That's where it fails. I guess 'tis because the scope is searched backwards
# from that point.
# OCaml, for example, requires me to put the `and' keyword between mutually-recursive
# functions. I'd not mind doing that in Ruby, but I don't know how. n00b. ;-)
# Also, it works in That Other Language.
#

# Now, the (dirty) solution I found. I think you will help me with how to get it done
# without all this voodoo:

Funcs = [lambda do |pos|
Funcs[1].call(0, pos)
end,
lambda do |thus_far, pos|
len = Letters.length
if pos < len then
Letters[pos]
else
Funcs[0].call(thus_far) + Funcs[1].call(thus_far + 1, pos - len)
end
end]

def main(args)
puts Funcs[0].call((26 * 26) - 1) # Prints A to Z. But see how un-Rubyistic it is!
# puts alphabetise(675) # This fails.
# if my_even 4 and my_odd 5 then 0 else 1 end # This also fails
0
end

exit(main(ARGV))



--------------080502090604050007040806
Content-Type: text/plain;
name="mutrec.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="mutrec.rb"

#! /usr/bin/ruby
# Two examples of a mutually-recursive function.

# These are functions that depend on each other - recursively.

# even and odd:
# If a number is zero, then it is even. Otherwise, it is even if the one before it is odd.
# A number is odd if it is not zero. Otherwise, it is odd if it the one before it is even. :eek:)
# This is the canonical example.
def my_even(x)
x == 0 or odd(x - 1)
end

def my_odd(x)
x != 0 and even(x - 1)
end

# That is, of course, a silly way to implemet even and odd. So, let me give you the problem
# I was trying to solve.
#
# To generate the lettering similar to that above the spreadsheet columns, where the first
# column has 'A', the second 'B' ... the twenty-sixth 'Z'. Then, the twenty-seventh has
# 'AA', the twenty-eight has 'AB', and so on. This is recursive by nature. Here is what
# should work:


Letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z']

def alphabetise(pos)
pile_letters(0, pos) # LABEL: 1
end
def pile_chars(thus_far, pos)
len = Letters.length
if pos < len then
Letters[pos]
else
alphabeticise(thus_far) + pile_chars(thus_far + 1, pos - len)
end

end

# Labels:
# 1. That's where it fails. I guess 'tis because the scope is searched backwards
# from that point.
# OCaml, for example, requires me to put the `and' keyword between mutually-recursive
# functions. I'd not mind doing that in Ruby, but I don't know how. n00b. ;-)
# Also, it works in That Other Language.
#

# Now, the (dirty) solution I found. I think you will help me with how to get it done
# without all this voodoo:

Funcs = [lambda do |pos|
Funcs[1].call(0, pos)
end,
lambda do |thus_far, pos|
len = Letters.length
if pos < len then
Letters[pos]
else
Funcs[0].call(thus_far) + Funcs[1].call(thus_far + 1, pos - len)
end
end]

def main(args)
puts Funcs[0].call((26 * 26) - 1) # Prints A to Z. But see how un-Rubyistic it is!
# puts alphabetise(675) # This fails.
# if my_even 4 and my_odd 5 then 0 else 1 end # This also fails
0
end

exit(main(ARGV))

--------------080502090604050007040806--
 
B

Bruno Michel

For the even and odd example, it works if you remplace odd by my_odd in
the my_even function, and even by my_even in the my_odd function. Like this:

def my_even(x)
x == 0 or my_odd(x - 1)
end

def my_odd(x)
x != 0 and my_even(x - 1)
end

my_even(10) #=> true


Hope this helps.
 
R

Revence Kalibwani

Bruno said:
For the even and odd example, it works if you remplace odd by my_odd
in the my_even function, and even by my_even in the my_odd function.
Like this:

def my_even(x)
x == 0 or my_odd(x - 1)
end

def my_odd(x)
x != 0 and my_even(x - 1)
end

my_even(10) #=> true


Hope this helps.
Yeah. Solved it. Lots of typos. That happens under stress. Thanks a lot,
everyone. :)
 
J

Jano Svitok

Yeah. Solved it. Lots of typos. That happens under stress. Thanks a lot,
everyone. :)

For this very case, String#succ and String.succ! might be helpful
('A'.succ -> 'B', 'Z'.succ -> 'AA').
 
H

Harry Kakueki

# That is, of course, a silly way to implemet even and odd. So, let me give you the problem
# I was trying to solve.
#
# To generate the lettering similar to that above the spreadsheet columns, where the first
# column has 'A', the second 'B' ... the twenty-sixth 'Z'. Then, the twenty-seventh has
# 'AA', the twenty-eight has 'AB', and so on. This is recursive by nature. Here is what
# should work:

I may be missing something, but..

If you just want to do that then try something like this.

arr = []
("a".."ff").each {|x| arr << x}
p arr

Harry
 
D

dblack

Hi --

# That is, of course, a silly way to implemet even and odd. So, let
me give you the problem
# I was trying to solve.
#
# To generate the lettering similar to that above the spreadsheet
columns, where the first
# column has 'A', the second 'B' ... the twenty-sixth 'Z'. Then, the
twenty-seventh has
# 'AA', the twenty-eight has 'AB', and so on. This is recursive by
nature. Here is what
# should work:

I may be missing something, but..

If you just want to do that then try something like this.

arr = []
("a".."ff").each {|x| arr << x}
p arr

Work-saving tip for the day:

p [*"a".."ff"]

:)


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
H

Harry Kakueki

Hi --

I may be missing something, but..

If you just want to do that then try something like this.

arr = []
("a".."ff").each {|x| arr << x}
p arr

Work-saving tip for the day:

p [*"a".."ff"]

:)


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
I was going to do this.

p ("a".."ff").each {|x| p x}

But I didn't want it to run off the screen.
But you did the same thing in a better way.
Thanks for the tip.

Harry
 
H

Harry Kakueki

Work-saving tip for the day:

p [*"a".."ff"]

:)


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
I was going to do this.

p ("a".."ff").each {|x| p x}

Harry
Oops.
Don't need 2 p's.

("a".."ff").each {|x| p x}

Harry
 
A

ara.t.howard

Hi --

# That is, of course, a silly way to implemet even and odd.
So, let me give you the problem
# I was trying to solve.
#
# To generate the lettering similar to that above the
spreadsheet columns, where the first
# column has 'A', the second 'B' ... the twenty-sixth 'Z'.
Then, the twenty-seventh has
# 'AA', the twenty-eight has 'AB', and so on. This is
recursive by nature. Here is what
# should work:

I may be missing something, but..

If you just want to do that then try something like this.

arr = []
("a".."ff").each {|x| arr << x}
p arr

Work-saving tip for the day:

p [*"a".."ff"]

:)

seems a bit perlish no?

cfp:~ > cat a.rb
p ('a' .. 'ff').to_a


cfp:~ > ruby a.rb
["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"aa", "ab", "ac", "ad", "ae", "af", "ag", "ah", "ai", "aj", "ak",
"al", "am", "an", "ao", "ap", "aq", "ar", "as", "at", "au", "av",
"aw", "ax", "ay", "az", "ba", "bb", "bc", "bd", "be", "bf", "bg",
"bh", "bi", "bj", "bk", "bl", "bm", "bn", "bo", "bp", "bq", "br",
"bs", "bt", "bu", "bv", "bw", "bx", "by", "bz", "ca", "cb", "cc",
"cd", "ce", "cf", "cg", "ch", "ci", "cj", "ck", "cl", "cm", "cn",
"co", "cp", "cq", "cr", "cs", "ct", "cu", "cv", "cw", "cx", "cy",
"cz", "da", "db", "dc", "dd", "de", "df", "dg", "dh", "di", "dj",
"dk", "dl", "dm", "dn", "do", "dp", "dq", "dr", "ds", "dt", "du",
"dv", "dw", "dx", "dy", "dz", "ea", "eb", "ec", "ed", "ee", "ef",
"eg", "eh", "ei", "ej", "ek", "el", "em", "en", "eo", "ep", "eq",
"er", "es", "et", "eu", "ev", "ew", "ex", "ey", "ez", "fa", "fb",
"fc", "fd", "fe", "ff"]

;-)


-a
 
D

dblack

Hi --

Hi --

# That is, of course, a silly way to implemet even and odd. So, let
me give you the problem
# I was trying to solve.
#
# To generate the lettering similar to that above the spreadsheet
columns, where the first
# column has 'A', the second 'B' ... the twenty-sixth 'Z'. Then,
the twenty-seventh has
# 'AA', the twenty-eight has 'AB', and so on. This is recursive by
nature. Here is what
# should work:

I may be missing something, but..

If you just want to do that then try something like this.

arr = []
("a".."ff").each {|x| arr << x}
p arr

Work-saving tip for the day:

p [*"a".."ff"]

:)

seems a bit perlish no?

No, since you asked :) It looks like that thing in Ruby where you
use the unar[r]ay operator to unarray a range :)


David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
 
V

vasudevram

p [*"a".."ff"]

David Black's solution above looks like the best for Ruby (hey, he
wrote the Ruby for Rails book :)

If Ruby didn't have that ability to enumerate from "a" to "ff" (I know
it does), this one would also work (in Ruby as well as in other
languages like Python, with suitable changes for their different
syntax):

labels = []
["a".."z"].each { |c| labels << c }
["a".."z"].each do |c|
["a".."z"].each { |c2| labels << (c + c2) }
end
# Now do whatever you want with the array 'labels'.]

( I'm not at my PC right now, so can't check if its quite right. )

Vasudev Ram
Dancing Bison Enterprises
http://www.dancingbison.com
 
B

bbiker

Work-saving tip for the day:
p [*"a".."ff"]
:)
David
--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
(See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)
I was going to do this.
p ("a".."ff").each {|x| p x}

Oops.
Don't need 2 p's.

("a".."ff").each {|x| p x}

Harry

--

A Look into Japanese Ruby List in Englishhttp://www.kakueki.com/- Hide quoted text -

- Show quoted text -

I am not exactly sure what the OP was trying to do .. except that it
has to do with Columns in Excel. It does seems to me to be fairly
complicated. If this off topic, please excuse.

In Excel, columns may either have a numeric format or an alpha
format. Columns range for 1 .. 255 (A .. IV). Since I do quite a bit
of work using Excel from Ruby via WIN32OLE, I have written a couple of
helper functions to convert a numeric column value to an alpha column
value and vice versa. Note that alpha columns in Excel are all caps.

Here they are, I hope that someone might find them useful.

# method to convert from numeric column to alpha col
# accepts numeric column 1 through 256
# returns alpha column A through IV
# returns empty string on invalid input
def n2a_col(num_col)

# verify that it in the range of 1 to 255
return nil if num_col < 1 || num_col > 256

mostSD = num_col / 26 # SD = Significant Digit
leastSD = num_col % 26

if leastSD == 0
mostSD -= 1
leastSD = 26
end

leastSA = ('A'[0] + leastSD - 1 ).chr
mostSA = mostSD > 0 ? ('A'[0] + mostSD - 1).chr : ''

mostSA + leastSA
end

# method to convert from alpha column to numeric col
# accepts alpha column A through IV
# returns numeric column 1 through 255
# returns 0 on invalid input
def a2n_col(alpha_col)
# to uppercase
alpha_col.upcase

col_size = alpha_col.size

case col_size
when 1
return 0 if alpha_col < 'A' || alpha_col > 'Z'
return alpha_col[0] - 'A'[0] + 1
when 2
return 0 if alpha_col < 'AA' || alpha_col > 'IV'
return (alpha_col[0] - 'A'[0] + 1) * 26 + alpha_col[1] - 'A'[0] + 1
else
return 0
end
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top