Ваш пример на ruby 2.1.2 заработал после небольшой доработки
1. Почему внутри метода memoize lambda получает массив?
Непонятно что вы имели ввиду? В memoize происходит следующее:
- создается переменная cache
- создается объект-функция, которая является оберткой для того объекта-функции на котором вызван метод memoize. При этом внутри обертки доступна переменная cache (замыкание)
- возвращается созданная обертка
2. В строке cache[args] = self[*args] self - это lambda {|x| return 1 if x==0; x*factorial[x-1]}?
Да, self это то над чем делается обертка, причем [] примененные к объекту-функции это аналог call. То есть вызов обертки с параметрами *args
3. Зачем в self[*args] стоит оператор-звездочка (распаковка массива)?
Для распаковки массива (как это ни странно). То есть args это массив содержащий переданные параметры, а оборачиваемая лямбда принимает число. Соответственно массив нужно распаковать.
Рабочий код, можете повтыкать принты и поглядеть что чему равно
class Proc #!!!!!!
def memoize
cache = {} # Пустой кэш. lambda захватывает его в свое замкнутое
# пространство
lambda { |*args| #!!!!!
# Заметьте, что ключ хэша - это сплошной массив аргументов!
unless cache.has_key?(args) # если результата для этих аргументов в кэше нет,
cache[args] = self[*args]
end
cache[args]
}
end
end
# далее демонстрируется его использование
factorial = lambda {|x| return 1 if x==0; x*factorial[x-1]}.memoize
puts factorial.call(5)