• Как работает этот пример из учебника?

    @vsuhachev
    Ваш пример на 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)
    Ответ написан
    1 комментарий