Ответ 1
Идея состоит в том, что каждый раз, когда вы запрашиваете свой тяжелый расчет, вы сразу же проверяете кеш, если вы уже его оценили. Если да, вы просто возвращаете сохраненное значение. Если нет, вы должны оценить новое значение и сохранить его, прежде чем возвращать его конечному пользователю.
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.
Очевидно, что даже если это помогает для больших чисел, вы должны учитывать дополнительные затраты на добавление записи в таблицу поиска для каждого шага. Учитывая причины, по которым было введено кэширование (мы предполагаем, что вычисление очень тяжелое, поэтому время вставки поиска незначительно), это должно быть совершенно нормально.