Я прокомментировал ответ rkj выше относительно лямбды. Этот код демонстрирует пример, который вы просили;
def abs(n); (n < 0) ? -n : n; end
def square(n); n * n; end
def average(x, y); (x + y) / 2; end
def fixed_point(x, point, process, test)
return point if test.call(x, point)
fixed_point(x, process.call(x, point), process, test)
end
def sqrt(n)
process = lambda {|n,g| average g, (n/g) }
test = lambda {|n,g| abs(square(g) - n) < 0.001}
fixed_point(n, 1.0, process, test)
end
Первое, на что следует обратить внимание: метод fixed_point
обрабатывает общую идею постепенного применения процесса к некоторым данным, пока он не пройдет определенный тест. Функция sqrt
определяет процесс поиска квадратного корня и тест для определения того, когда мы должны быть удовлетворены. Затем эти «процедуры» передаются, как и любая другая форма данных, так что fixed_point
может работать как по волшебству.
Вместо временного хранения процесса и проверки все это может быть анонимным. Мы могли бы переписать sqrt
как;
def sqrt(n)
fixed_point( n, 1.0,
lambda {|n,g| average g, (n/g)},
lambda {|n,g| abs(square(g) - n) < 0.001} )
end
Без этой возможности мне пришлось бы определять и процесс, и тест как отдельные функции, и создавать специальную функцию sqrt_fixed_point
для их вызова. Насколько я знаю, Java может делать нечто подобное с помощью Functors, но я не знаю достаточно, чтобы комментировать. Консенсус, который я видел в блогах или аналогичных программах, заключается в том, что Java делает это настолько ужасно сложным, что вы просто получите кровотечение из носа, просто попробовав это.
Конечно, еще одна опция, которую предоставляет Ruby, - это метапрограммирование. Я мог бы переписать sqrt
так, чтобы он переписывал (на лету) fixed_point
, используя правильный процесс и тестирование, но это, вероятно, злоупотребление функцией: -)
пс. Ссылка JoelOnSoftware размещена заслуживает повторения; http://www.joelonsoftware.com/items/2006/08/01.html