I'm looking for a clean way to write a function that allows me to choose which parameter to solve for assuming all others are known. Is it good design to do something like this: ? class Foo def initialize(x, y, z) @x, @y, @z = x, y, z end def function(var) if @x.nil? @x = var elsif @y.nil? @y = var else @z = var end @x + @y + @z end end z = Foo.new(1, 2, nil) z.function(3) => 6 ??

on 2009-02-03 08:10

on 2009-02-03 08:22

> if @x.nil? > @x = var This could be rewritten as @x ||= var > elsif @y.nil? What if @x and @y are nil? You might want to use @y ||= var @z ||= var instead -- depending on what you want of course.

on 2009-02-03 08:52

What do you mean? Blog: http://random8.zenunit.com/ Learn rails: http://sensei.zenunit.com/ On 03/02/2009, at 5:10 PM, Jason L.

on 2009-02-03 13:29

Jason L. wrote: > I'm looking for a clean way to write a function that allows me to choose > which parameter to solve for assuming all others are known. Is it good > design to do something like this: ? > > class Foo > def initialize(x, y, z) > @x, @y, @z = x, y, z > end > > def function(var) > if @x.nil? > @x = var > elsif @y.nil? > @y = var > else > @z = var > end > @x + @y + @z > end > > end > > z = Foo.new(1, 2, nil) > z.function(3) > => 6 Hmm, is this some sort of currying? adder = lambda { |x,y,z| x+y+z } z = lambda { |z| adder[1,2,z] } z[3] You could perhaps factor this out into some sort of fix_args method. Ruby 1.9 has Proc#curry, but I think this only fixes from the left.

on 2009-02-03 13:52

> This could be rewritten as > > @x ||= var I totally misread the code. Sorry. Brian seems to be on the right track.

on 2009-02-03 15:05

Jason L. wrote: > class Foo > def initialize(x, y, z) > @x, @y, @z = x, y, z > end > > def function(var) > if @x.nil? > @x = var > elsif @y.nil? > @y = var > else > @z = var > end > @x + @y + @z > end > > end > > z = Foo.new(1, 2, nil) > z.function(3) > => 6 Also, if this is really the pattern you want (an object holding default values for each of the args), then you probably don't want to modify the instance variables between invocations. So here is a more general version: class Foo def initialize(*args) @args = args end def function(*more) # for each nil argument, pick one from 'more' calculate(*@args.collect { |x| x || more.shift }) end def calculate(x,y,z) x + y + z end end z = Foo.new(1,2,nil) z.function(3) q = Foo.new(nil,nil,6) q.function(4,5) But I still think some flavour of currying is what you want. Is it important that arbitrary parameters are fixed, rather than just the left-most ones?

on 2009-02-03 15:46

adder = lambda { |x,y,z| x+y+z } z = lambda { |z| adder[1,2,z] } z[3] This is what I want: write my equation one time then use that equation in many different ways - solve for any one variable of my choice without re-writing the equation. Thank you so much! > > But I still think some flavour of currying is what you want. Is it > important that arbitrary parameters are fixed, rather than just the > left-most ones? It is important that arbitrary parameters are fixed as long as only one parameter is unknown. Thank you.

on 2009-02-03 16:09

Jason L. wrote: > adder = lambda { |x,y,z| x+y+z } > z = lambda { |z| adder[1,2,z] } > z[3] > This is what I want: write my equation one time then use that equation > in many different ways - solve for any one variable of my choice without > re-writing the equation. Thank you so much! > >> >> But I still think some flavour of currying is what you want. Is it >> important that arbitrary parameters are fixed, rather than just the >> left-most ones? > > It is important that arbitrary parameters are fixed as long as only one > parameter is unknown. If the logic is to be hard-coded then maybe f2 = lambda { |y| adder[1,y,3] } is good enough for you. Otherwise, writing a currying function which fixes arbitrary parameters is left as an exercise :-)