Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: A function returning another function

Tags:

function

ruby

In order to understand the functional programming part of ruby I want to write a function that takes 2 functions f(x,y),g(x) as arguments and returns a new function h(x,y)=f(g(x),g(y)).

def foo(x, y)
    return x+y
end

def bar(x)
    return 2*x
end

def comp(f,g)

end

f=comp(f,g)
f(1,2) #=> 6

I tried things like

def comp(f,g)
    mylambda = lambda {|x,y| return f(g(x),g(y))}
    return mylambda
end
f=comp(foo, bar)
f.call(1,2)

I thought f would be a Proc now, and I could just call it. But apparently "in `foo': wrong number of arguments (0 for 2) (ArgumentError)"

What syntax would I have to use? And is it possible to return a "real" function instead of a Proc, so that instead of f.call(1,2) I could just writhe f(1,2) like if I had just defined f myself normaly?

like image 460
Rene Recktenwald Avatar asked Nov 05 '13 22:11

Rene Recktenwald


2 Answers

This type of functional pattern doesn't work as smoothly as on more functional languages, as javascript or python. Since ruby has optional parentheses, writing foo is the same as calling the foo method without passing any arguments.

To get a reference to a method, you need to use the Object#method method:

def foo(x, y)
  x + y
end

def bar(x)
  x * 2
end

def comp(f, g)
  lambda { |x, y| f.call(g.call(x), g.call(y)) }
end

h = comp(method(:foo), method(:bar))
h.call(1, 2) # => 6
like image 122
Renato Zannon Avatar answered Oct 11 '22 02:10

Renato Zannon


Ruby doesn't have first class functions like Python. Ruby has lambdas, and method objects that can be constructed specially from a method, but methods themselves are not objects. The closest you'll get to this is this:

def foo(x, y)
    return x+y
end

def bar(x)
    return 2*x
end

def comp(f,g)
  return lambda {|x, y| f.call(g.call(x), g.call(y))}
end

f=comp(method(:f),method(:g))
f.call(1,2) #=> 6

Also, for the calling syntax point, you can call a lambda with square brackets, so you could do this:

f[1,2]
like image 31
Linuxios Avatar answered Oct 11 '22 03:10

Linuxios