Идея состоит в том, что каждый раз, когда вы запрашиваете тяжелый расчет, вы сразу же проверяете в кеше, если уже оценивали его.Если да, вы просто возвращаете сохраненное значение.Если нет, вам нужно оценить новое значение и сохранить его, прежде чем вернуть его конечному пользователю.
A dict , а не таблица dets, также может работать.
(следующее решение не проверено)
-module(cache_fact).
-export([init/0, fact/1]).
init() ->
{ok, _} = dets:open_file(values, []).
fact(N) ->
case dets:lookup(values, N) of
[] ->
Result = do_fact(N),
dets:insert_new(values, {N, Result}),
Result;
[{N, Cached}] ->
Cached
end.
do_fact(0) ->
1;
do_fact(N) ->
N * do_fact(N-1).
Возможно, вы захотите инкапсулировать все это в универсальный сервер Erlang .В функции init вы должны создать таблицу DETS, функция fact / 1 должна представлять ваш API, и вы должны реализовать логику в функциях handle_call.
Более хорошим примером может быть написание более короткого сервиса для URL, кэшированного.
Как предполагает @Zed, было бы целесообразно также сохранить частичные результаты, чтобы избежать дальнейших перерасчетов.Если это так:
-module(cache_fact).
-export([init/0, fact/1]).
init() ->
{ok, _} = dets:open_file(values, []).
fact(0) ->
1;
fact(N) ->
case dets:lookup(values, N) of
[] ->
Result = N * fact(N-1),
dets:insert_new(values, {N, Result}),
Result;
[{N, Cached}] ->
Cached
end.
Очевидно, что даже если это помогает для больших чисел, необходимо учитывать дополнительные затраты на добавление записи в таблицу поиска для каждого шага.Учитывая причины, по которым было введено кэширование (мы предполагаем, что вычисления очень тяжелые, поэтому время вставки поиска незначительное), это должно быть совершенно нормально.