B
Brian Candler
Not a question or anything... I just wanted to share this snippet with
any non-computer-scientist who thinks this is cool
I come from very much an imperative programming background - originally
machine code. Computer science books tend to use LISP, and I find anything
other than the simplest example to be impenetrable. However, translating
them to Ruby makes it much clearer to me what's going on.
---------------------------------------------------------------------------
# Simple start: implement the 'times' iterator recursively, applied
# to an explicit proc argument rather than an implicit block.
def my_times(n, f)
if n >= 1
f.call()
my_times(n-1, f)
end
end
my_times(3, proc { puts "testing" } )
# OK, now implement the 'times' iterator as an anonymous function (proc)
times = proc { |n, f|
if n >= 1
f.call()
times.call(n-1, f)
end
}
times.call(3, proc { puts "hello world" } )
# However, I cheated The proc isn't really anonymous because I assigned
# it to 'times', and this was essential because I referred to the name
# inside the function in order to call itself recursively.
#
# But in fact it's possible to write fully anonymous functions which are
# recursive.
#
# The following example is translated from "Structure and Interpretation
# of Computer Programs" (Abelson, Sussman and Sussman), second edition p393
# - it's an anonymous function which calculates factorial recursively
puts proc { |n|
proc { |fact| fact.call(fact, n) }.call(
proc { |ft, k|
k <= 1 ? 1 : k * ft.call(ft, k-1)
}
)
}.call(10)
# Using this pattern we can recast our iterator as follows, without using
# its name internally:
proc { |*a|
proc { |iter| iter.call(iter, *a) }.call(
proc { |me, n, f|
if n >= 1
f.call()
me.call(me, n-1, f)
end
}
)
}.call(3, proc { puts "hello again" } )
any non-computer-scientist who thinks this is cool
I come from very much an imperative programming background - originally
machine code. Computer science books tend to use LISP, and I find anything
other than the simplest example to be impenetrable. However, translating
them to Ruby makes it much clearer to me what's going on.
---------------------------------------------------------------------------
# Simple start: implement the 'times' iterator recursively, applied
# to an explicit proc argument rather than an implicit block.
def my_times(n, f)
if n >= 1
f.call()
my_times(n-1, f)
end
end
my_times(3, proc { puts "testing" } )
# OK, now implement the 'times' iterator as an anonymous function (proc)
times = proc { |n, f|
if n >= 1
f.call()
times.call(n-1, f)
end
}
times.call(3, proc { puts "hello world" } )
# However, I cheated The proc isn't really anonymous because I assigned
# it to 'times', and this was essential because I referred to the name
# inside the function in order to call itself recursively.
#
# But in fact it's possible to write fully anonymous functions which are
# recursive.
#
# The following example is translated from "Structure and Interpretation
# of Computer Programs" (Abelson, Sussman and Sussman), second edition p393
# - it's an anonymous function which calculates factorial recursively
puts proc { |n|
proc { |fact| fact.call(fact, n) }.call(
proc { |ft, k|
k <= 1 ? 1 : k * ft.call(ft, k-1)
}
)
}.call(10)
# Using this pattern we can recast our iterator as follows, without using
# its name internally:
proc { |*a|
proc { |iter| iter.call(iter, *a) }.call(
proc { |me, n, f|
if n >= 1
f.call()
me.call(me, n-1, f)
end
}
)
}.call(3, proc { puts "hello again" } )