I am trying to mess around a little bit with Ruby. Therefor I try to implement the algorithms (given in Python) from the book "Programming Collective Intelligence" Ruby.
In chapter 8 the author passes a method a as parameter. This seems to work in Python but not in Ruby.
I have here the method
def gaussian(dist, sigma=10.0)
foo
end
and want to call this with another method
def weightedknn(data, vec1, k = 5, weightf = gaussian)
foo
weight = weightf(dist)
foo
end
All I got is an error
ArgumentError: wrong number of arguments (0 for 1)
-
You have to call the method "call" of the function object:
weight = weightf.call(dist)EDIT: as explained in the comments, this approach is wrong. It would work if you're using Procs instead of normal functions.
Squeegy : When he does `weightf = gaussian` in the arg list it's actually trying to execute `gaussian` and assign the result as the default value of weightf. The call doesn't have required args and crashes. So weightf is not even a proc object with a call method just yet.Tiago : Oh, I got it. Thanks for correcting me =) -
You want a proc object:
gaussian = Proc.new do |dist, *args| sigma = args.first || 10.0 ... end def weightedknn(data, vec1, k = 5, weightf = gaussian) ... weight = weightf.call(dist) ... endJust note that you can't set a default argument in a block declaration like that. So you need to use a splat and setup the default in the proc code itself.
Or, depending on your scope of all this, it may be easier to pass in a method name instead.
def weightedknn(data, vec1, k = 5, weightf = :gaussian) ... weight = self.send(weightf) ... endIn this case you are just calling a method that is defined on an object rather than passing in a complete chunk of code. Depending on how you structure this you may need replace
self.sendwithobject_that_has_the_these_math_methods.send
Last but not least, you can hang a block off the method.
def weightedknn(data, vec1, k = 5) ... weight = if block_given? yield(dist) else gaussian.call(dist) end end ... end wegihtedknn(foo, bar) do |dist| # square the dist dist * dist endBut it sounds like you would like more reusable chunks of code here.
Jimmy Stenke : I think that second option is the best option (that is, using Object.send()), the drawback is that you need to use a class for all of it (which is how you should do in OO anyway :)). It is more DRY than passing a block (Proc) all the time, and you could even pass arguments trough the wrapper method. -
The normal Ruby way to do this is to use a block.
So it would be something like:
def weightedknn(data, vec1, k = 5) foo weight = yield(dist) foo endAnd used like:
weightenknn(data, vec1) {|dist| gaussian(dist)}This pattern is used extensively in Ruby.
-
The comments referring to blocks and Procs are correct in that they are more usual in Ruby. But you can pass a method if you want. You call
methodto get the method and.callto call it:def weightedknn(data, vec1, k = 5, weightf = method(:gaussian)) ... weight = weightf.call(dist) ... end
0 comments:
Post a Comment