Методы запоминания членов в Groovy


У меня есть метод, который является чистой функцией и требует времени для запуска. Я хотел бы запомнить этот метод, чтобы последующие вызовы были намного быстрее. Я вижу в документации Groovy, что вы можете запоминать замыкания через:

foo = {…}.memoize()

Однако я не могу найти способ запомнить метод члена. Есть ли способ сделать это?
2 4

2 ответа:

Правка:

В Groovy 2.2.X появится новое преобразование AST под названием @Memoized, которое сделает это за вас.

import groovy.transform.Memoized

class Woo {
  @Memoized
  def sum( int a, int b ) {
    Thread.sleep( 1000 )
    a + b
  }
}

new Woo().with {
  println new Date()
  println sum( 1, 2 )
  println new Date()
  println sum( 1, 2 )
  println new Date()
}

Оригинальный ответ

Другой вариант-написать своего рода преобразование AST, чтобы вы могли аннотировать метод с помощью @Memoize и сделать мемуаризацию за вас.

Я могу найти пару примеров, один здесь для добавления Redis в качестве кэша мемоизация в файл Grails, а другой Здесь, которые, кажется, позволяют мемоизация методы с одним аргументом , в основном манипулируя АСТ, чтобы выглядеть как вторая часть ответа эпидемиана.

Поскольку вы, вероятно, хотите несколько параметров, я бы выбрал второй метод epidemian. Однако написание преобразования AST может быть интересным экспериментом / сайд-проектом?

Это то, что, если сделать все правильно, я мог бы увидеть возвращение в исходный код Groovy core (для славы и славы): -)

Я не знаю никакого прямого способа запоминания методов, точно так же, как вы можете запомнить закрытие.

Если метод не получает никаких параметров (и, следовательно, возвращаемое значение всегда одно и то же, поскольку оно чисто), вы можете сделать memoization, просто сохранив возвращаемое значение в атрибуте члена. Эта техника очень распространена в Ruby и обычно принимает форму def some_method; @value ||= compute_value; end. Переведя это на Groovy, вы можете сделать что-то вроде:

class Computer {
    private answer
    def getAnswer() {
        answer = answer ?: computeAnswer()
    }
    private computeAnswer() {
        println "Computing the Answer to the Ultimate Question of Life, the Universe, and Everything"
        42
    }
}

def c = new Computer()
println c.answer
println c.answer

Вывод:

Computing the Answer to the Ultimate Question of Life, the Universe, and Everything
42
42

Так что мемуаризация сработала:)

Если вы не хотите определять дополнительный метод, вы также можете написать метод getAnswer следующим образом:

def getAnswer() {
    if (answer != null) return answer
    println "Computing the Answer to the Ultimate Question of Life, the Universe, and Everything"
    answer = 42        
}

Теперь, если метод действительно получает какие-либо параметры, было бы довольно громоздко реализовать memoization таким образом. Вместо этого вы можете вызвать memoized closure из merhod, который вы хотите запомнить:
class Calculator {
    def sum(a, b) {
        memoizedSum(a, b)
    }
    private memoizedSum = { a, b ->
        println "Computing the sum of $a and $b"
        a + b
    }.memoize()
}

def c = new Calculator()
println c.sum(4, 7)
println c.sum(4, 7)
println c.sum(4, 2)

Вывод:

Computing the sum of 4 and 7
11
11
Computing the sum of 4 and 2
6