Как я могу оптимизировать это?

В настоящее время я учусь кодировать Erlang. У меня есть веб-приложение поверх Chicago Boss. У меня есть модель под названием Todo, и я хотел бы предложить операции CRUD над ней в качестве REST API.

В моем методе PUT у меня есть этот код:

index('PUT', [Id]) ->
    Todo = boss_db:find(Id),
    Body = element(2, mochijson:decode(Req:request_body())),
    %% Set the new values
    NewTodo = Todo:attributes([
            {subject, proplists:get_value("subject", Body)},
            {done, proplists:get_value("done", Body)}
        ])
,
    {json, [{todo, element(2, NewTodo:save())}]}.

Как я могу оптимизировать этот фрагмент кода? Или это уже лучшее из возможных?

Есть ли какой-нибудь "умный" способ изменить ключи проплиста на ключи атома? Как это:

[{"subject", "Foo"}] -> [{subject, "Foo"}].

Я также нахожу утомительным присваивать переменную Todo и затем иметь NewTodo. К сожалению, я не могу найти хороший пример приложений Erlang Chicago Boss на github, которые я могу проверить.

3 ответа

Вы всегда можете сделать что-то вроде этого:

t([{"subject", V}|T]) -> [{subject, V}|t(T)];
t([{"done"   , V}|T]) -> [{done,    V}|t(T)];
t([_             |T]) ->               t(T) ; % optional garbage ignoring clause
t([])                 -> [].

Но я сомневаюсь, это будет значительное улучшение скорости в вашем случае.

Может быть, вы сможете выжать последний бит из этого:

-compile({inline, [t/1]}).
t(L) -> t(L, []).

t([{"subject", V}|T], A) -> t(T, [{subject, V}|A]);
t([{"done"   , V}|T], A) -> t(T, [{done,    V}|A]);
t([_             |T], A) -> t(T, A); % optional garbage ignoring clause
t([], A)                 -> A.

Который стоит только для бенчмарков;-) (заметки нет lists:reverse/1 позвоните в последнем пункте. Было бы испортить улучшение от предыдущей версии.)

PS: Если вы думаете, что я фанат микро-оптимизации, вы правы, поэтому я бы заменил lists:reverse/1 позвонить с lists:reverse/2 использовать BIF напрямую и сэкономить немного времени;-)

К сожалению, я не могу комментировать ответ Хайнека, но, как новичок Эрланга, мое первое предположение было бы пойти на что-то вроде:

lists:map(fun({A, B}) -> {list_to_atom(A), B} end, [X || {Y, Z}=X <- List, is_list(Y)]).

Вы не можете действительно избежать назначения NewTodo

Как насчет

index('PUT', [Id]) ->
    Body = element(2, mochijson:decode(Req:request_body())),
    OldTodo = boss_db:find(Id),
    NewTodo = OldTodo:attributes([ {list_to_atom(A),B} || {A,B}<-Body ]),
    {json, [{todo, element(2, NewTodo:save())}]}.
Другие вопросы по тегам