воскресенье, 29 ноября 2009 г.

Хвостовая рекурсия в Erlang'e

Хвостовая рекурсия - это рекурсия только с одним рекурсивным вызовом, когда функция вызывает саму себя только в конце своего выполнения (хвостовой вызов). Все остальные рекурсивные вызовы преобразуются в итерации - оптимизация хвостовой рекурсии. Так экономятся ресурсы на использовании стека вызовов - при увеличении глубины рекурсии, память не растет линейно, а остается постоянной. Это очень важно для Erlang'а, где циклы реализуются только через рекурсию. Но не смотря на важность, оптимизация хвостовой рекурсии выполняется только если рекурсивный вызов является последней операцией в функции, поэтому для следующей функции оптимизация не будет выполнена:


%% Сумма элементов списка
sum([]) -> 0;
sum([H|T]) ->
%% последняя операция - "+"
H + sum(T).

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

sum(X) ->
sum(X, 0).
%% Результат каждой итерации
%% складывается в Acc
sum([], Acc) ->
Acc;
sum([H|T], Acc) ->
%% хвостовой вызов
sum(T, H + Acc).

sum/1 и sum/2 - это разные функции, поэтому определение sum/1 отделяется точкой, в противном случае при компиляции вылезет ошибка "head mismatch".

Существует мнение, что хвостовая рекурсия выполняется значительно быстрее, чем "обычная", но исходя из мифов об Эрланге, it depends.

Дополнительно о хвостовой рекурсии можно почитать:
- Recursion;
- A Deeper Look at Tail Recursion in Erlang;
- Erlang, Tail Recursion, and Living the Dream;
- Adventures in F#--Tail Recursion in Three Languages.

Read More...

суббота, 28 ноября 2009 г.

STRICT-функции в Postgres

STRICT, он же RETURNS NULL ON NULL INPUT, параметр, указываемый при создании функций в Postgres, означает, что функция возвращает NULL, если ей передается хотя бы один NULL. Благодаря этому можно экономить на вызовах функций - сразу использовать NULL вместо вызова функции с нулевыми аргументами.


create or replace function test_strict(str text)
returns text as
$$
begin
if str is NULL then
raise info 'str is NULL';
else
raise info 'str is %', str;
end if;
return str;
end;
$$
-- По умолчанию функция CALLED ON NULL INPUT
language 'plpgsql'

При вызове этой функции со значением str равным NULL увидим сообщение "INFO: str is NULL". Если в последнюю строку функции добавить STRICT, то сообщение выведено не будет - функция не вызывается:
language 'plpgsql' strict

Такое поведение strict-функций сразу наводит на мысль, что в некоторых случаях можно получить не совсем очевидные результаты. Например, если фукнция возвращает тип boolean, то вместо двух ожидаемых true и false, можно получить еще и NULL:

create or replace function is_equal(v text, t text)
returns boolean as
$$
begin
if v = t then
return true;
end if;
return false;
end;
$$
language 'plpgsql' strict;

select is_equal('test', 'test'), -- true
is_equal('test', 'test2'), -- false
is_equal(null, 'test'); -- NULL

Про полезность такой оптимизации пока ничего сказать не могу. Теоретически, в сложных запросах это может влиять на результат работы планировщика, но такие ситуации мне еще не встречались.

Read More...

вторник, 17 ноября 2009 г.

Запуск Python-скрипта из Vim

Ничего IDE'шное Vim'у не чуждо. Для исполнения редактируемого питоновского скрипта достаточно написать в командной строке:


:!python file_name.py

Так как Vim позволяет создавать хоткеи для любой последовательности команд (:help mapping), то можно замапить запуск на нажатие какой-нибудь кнопки. Для этого в .vimrc нужно добавить две строки:

map <F5> :w\|!python %<cr>
imap <F5> <Esc><F5>

В первой строке по F5 файл сначала сохраняется, потом запускается. map - создает хоткей в нормальном режиме. Вторая строка - для режима редактирования (imap). Из режима редактирования Vim переходит в нормальный (как по нажатию Esc), потом в нормальном режиме эмулируется нажатие F5.

Перед запуском скрипта полезно знать, есть ли в нем ошибки. Для этого можно использовать PyLint, PyChecker или Pyflakes. Мне удобнее всего пользоваться последним - работает быстро и не перегружает консоль ворнингами.

После установки Pyflakes (sudo aptitude install Pyflakes) нужно создать в .vimrc команду для проверки файла:

command Pyflakes :call Pyflakes()
function! Pyflakes()
let tmpfile = tempname()
execute "w" tmpfile
execute "set makeprg=(pyflakes\\ " . tmpfile .
"\\\\\\|sed\\ s@" . tmpfile ."@%@)"
silent make
cw
endfunction

И добавить ее вызов перед запуском скрипта:

map <F5> :w\|call Pyflakes()\|!python %<cr>
imap <F5> <Esc><F5>

Вуаля! Теперь по нажатию F5 редактируемый скрипт сохраняется не зависимо от режима, выполняется проверка синтаксиса и, если все ок, выполняется. Хотя это удобно только для одного файла, для целого проекта этого будет маловато.

Read More...