<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7498141530276954327</id><updated>2011-11-17T22:20:57.518+02:00</updated><category term='MPS'/><category term='J'/><category term='philosophy'/><category term='vcs'/><category term='php'/><category term='web'/><category term='redis'/><category term='haskell'/><category term='OZ'/><category term='parrot'/><category term='db'/><category term='perl'/><title type='text'>Laziness, Impatience and Hubris</title><subtitle type='html'>Заметки программиста, в основном, о perl.
Название блога происходит от трех главных добродетелей программиста: Лень, Нетерпение и Высокомерие.
К некоторым статьям следует относиться с определенной долей юмора.
&lt;a href="http://laziness-impatience-hubris.blogspot.com/2008/10/blog-post.html"&gt;Содержание&lt;/a&gt;.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>63</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-4919664214180356812</id><published>2011-06-23T10:30:00.001+03:00</published><updated>2011-06-23T10:32:59.829+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='OZ'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Закорючки, продолжение</title><content type='html'>Предположим, что вам необходимо множества раз писать данные в сокет, при этом задача не позволяет объединить все операции записи в одну.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; Perl:&lt;br /&gt; send $sock, $msg1;&lt;br /&gt; send $sock, $msgN;&lt;br /&gt;&lt;br /&gt; OZ:&lt;br /&gt; {send Sock Msg1}&lt;br /&gt; {send Sock MsgN}&lt;br /&gt;&lt;br /&gt; Haskell:&lt;br /&gt; send sock msg1&lt;br /&gt; send sock msgN&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Много раз повторяется "send sock" - попробуем избавиться от дублирования.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; Perl:&lt;br /&gt; my $snd = sub { send $sock, @_ };&lt;br /&gt; $snd-&gt;($msg1);&lt;br /&gt; $snd-&gt;($msgN);&lt;br /&gt; # или &amp;$send($msgN);&lt;br /&gt; &lt;br /&gt; OZ:&lt;br /&gt; local Snd = fun {$ M} send Sock M end&lt;br /&gt; {Snd Msg1}&lt;br /&gt; {Snd MsgN}&lt;br /&gt; &lt;br /&gt; Haskell:&lt;br /&gt; let snd = send sock&lt;br /&gt; snd msg1&lt;br /&gt; snd msgN&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Как видим, Perl закорючки (@#$%&amp;) путаются под ногами.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-4919664214180356812?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/4919664214180356812/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=4919664214180356812' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4919664214180356812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4919664214180356812'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2011/06/blog-post_23.html' title='Закорючки, продолжение'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-4662402544847666195</id><published>2011-06-02T11:30:00.001+03:00</published><updated>2011-06-02T11:33:04.155+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Закорючки</title><content type='html'>В Perl 5.14 можно передавать функциям, ожидающим в качестве аргументов хеши и массивы, не только их, а и ссылки на  них.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   1. |----------------------------+---------------------------|&lt;br /&gt;   2. | Traditional syntax         | Terse syntax              |&lt;br /&gt;   3. |----------------------------+---------------------------|&lt;br /&gt;   4. | push @$arrayref, @stuff    | push $arrayref, @stuff    |&lt;br /&gt;   5. | unshift @$arrayref, @stuff | unshift $arrayref, @stuff |&lt;br /&gt;   6. | pop @$arrayref             | pop $arrayref             |&lt;br /&gt;   7. | shift @$arrayref           | shift $arrayref           |&lt;br /&gt;   8. | splice @$arrayref, 0, 2    | splice $arrayref, 0, 2    |&lt;br /&gt;   9. | keys %$hashref             | keys $hashref             |&lt;br /&gt;  10. | keys @$arrayref            | keys $arrayref            |&lt;br /&gt;  11. | values %$hashref           | values $hashref           |&lt;br /&gt;  12. | values @$arrayref          | values $arrayref          |&lt;br /&gt;  13. | ($k,$v) = each %$hashref   | ($k,$v) = each $hashref   |&lt;br /&gt;  14. | ($k,$v) = each @$arrayref  | ($k,$v) = each $arrayref  |&lt;br /&gt;  15. |----------------------------+---------------------------|&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;То есть, все идет к тому, что скоро закорючки (@#$%&amp;) станут не нужны.&lt;br /&gt;Если честно, раньше думал, что их наличии упрощает код. Меньше надо выдумывать имен и идентификаторов.&lt;br /&gt;Однако, пописав на еще более высоком уровне (OZ, Haskell), понял, что иногда без них проще.&lt;br /&gt;&lt;br /&gt;P.S.&lt;br /&gt;А может просто руки болят?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-4662402544847666195?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/4662402544847666195/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=4662402544847666195' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4662402544847666195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4662402544847666195'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2011/06/blog-post.html' title='Закорючки'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-3418854694960020686</id><published>2011-03-23T08:53:00.002+02:00</published><updated>2011-03-23T09:08:20.962+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>не-Perl</title><content type='html'>На прошлой неделе мне сразу два человека сказало (кажется даже в один день), что я пишу на Perl как не на Perl.&lt;br /&gt;Забавно, но я использую обычно очень маленькое подмножество многоликого языка Perl.&lt;br /&gt;&lt;br /&gt;P.S.&lt;br /&gt;&lt;a href="http://github.com/kni/redis-sharding/tree/v0.2"&gt;http://github.com/kni/redis-sharding/tree/v0.2&lt;/a&gt;&lt;br /&gt;&lt;a href="http://search.cpan.org/perldoc?IPC::MPS"&gt;http://search.cpan.org/perldoc?IPC::MPS&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-3418854694960020686?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/3418854694960020686/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=3418854694960020686' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3418854694960020686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3418854694960020686'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2011/03/perl.html' title='не-Perl'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-5046381034198591375</id><published>2011-03-14T10:16:00.006+02:00</published><updated>2011-03-14T10:21:47.766+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='redis'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Redis Sharding</title><content type='html'>&lt;a href="http://github.com/kni/redis-sharding/tree/v0.2"&gt;http://github.com/kni/redis-sharding/tree/v0.2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Redis Sharding is a multiplexed proxy-server, designed to work with the database divided to several servers.&lt;br /&gt;It's a temporary substitution of Redis Cluster (http://redis.io) that is under development.&lt;br /&gt;&lt;br /&gt;Redis Sharding is used for horizontal Redis database scaling (with connecting of additional servers) as long as load distribution between the cores on the multiprocessor servers (as Redis server is single-threaded, several copies of the server can be run, one for each free core).&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;                              /- Redis (node 1)&lt;br /&gt; Client 1 ---                /-- Redis (node 2)&lt;br /&gt;              Redis Sharding --- Redis (node 3)&lt;br /&gt; Client 2 ---                \-- Redis (node 4)&lt;br /&gt;                              \- Redis (node 5)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Sharding is done based on the CRC32 checksum of a key or key tag ("key{key_tag}").&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-5046381034198591375?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/5046381034198591375/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=5046381034198591375' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5046381034198591375'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5046381034198591375'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2011/03/redis-sharding.html' title='Redis Sharding'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-8233817294291577166</id><published>2010-12-02T14:57:00.005+02:00</published><updated>2010-12-02T15:04:15.038+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='OZ'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Стиль передачи продолжений и связывание</title><content type='html'>&lt;b&gt;Оператор связывания как синтаксический сахар&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;По мотивам цикла заметок "Сегодня без...", а именно заметки &lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/05/return_20.html"&gt;"Сегодня без return"&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Возьмем пример кода из вышеупомянутой заметки и сразу лишим его магии Perl прототипов: все равно в последующем коде они работать не будут:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub mul {&lt;br /&gt;     my ($sub, $x, $y) = @_;&lt;br /&gt;     my @r = map { $$x[$_] * $$y[$_] } 0 .. $#$x;&lt;br /&gt;     $sub-&gt;(@r);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub minus {&lt;br /&gt;     my ($sub, $x, $y) = @_;&lt;br /&gt;     my @r = map { $$x[$_] - $$y[$_] } 0 .. $#$x;&lt;br /&gt;     $sub-&gt;(@r);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; sub say {&lt;br /&gt;     my $sub = shift;&lt;br /&gt;     print join(" ", @_), "\n";&lt;br /&gt;     $sub-&gt;();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; my @i = (1, 2, 3);&lt;br /&gt; my @j = (2, 3, 4);&lt;br /&gt; my @k = (3, 4, 5);&lt;br /&gt;&lt;br /&gt; mul sub {&lt;br /&gt;     minus sub {&lt;br /&gt;         say sub {}, @_&lt;br /&gt;     }, \@_, \@k&lt;br /&gt; }, \@i, \@j;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Результат работы это программы - вывод на печать строки "-1 2 7".&lt;br /&gt;&lt;br /&gt;А теперь представим, что подпрограмма minus не вызывает продолжение, а возвращает результат:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub minus {&lt;br /&gt;     my ($x, $y) = @_;&lt;br /&gt;     map { $$x[$_] - $$y[$_] } 0 .. $#$x;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Поэтому напишем для обертку:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub bind_minus {&lt;br /&gt;     my ($sub, $x, $y) = @_;&lt;br /&gt;     my @r = minus($x, $y);&lt;br /&gt;     $sub-&gt;(@r);&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Которую и будем использовать:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; mul sub {&lt;br /&gt;     bind_minus sub {&lt;br /&gt;         say sub {}, @_&lt;br /&gt;     }, \@_, \@k&lt;br /&gt; }, \@i, \@j;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Затем сделаем подпрограмму bind_minus ленивой, чтобы только связывала, но ничего не вычисляла сразу (это пригодиться потом):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub bind_minus {&lt;br /&gt;     my ($sub) = @_;&lt;br /&gt;     sub {&lt;br /&gt;         my ($x, $y) = @_;&lt;br /&gt;         my @r = minus($x, $y);&lt;br /&gt;         $sub-&gt;(@r);&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; # ...&lt;br /&gt;&lt;br /&gt; mul sub {&lt;br /&gt;     bind_minus(sub {&lt;br /&gt;         say sub {}, @_&lt;br /&gt;     })-&gt;(\@_, \@k)&lt;br /&gt; }, \@i, \@j;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ленивость bind_minus позволяет по ее образу сделать универсальную подпрограмму Bind для связывания функции и продолжения:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub Bind {&lt;br /&gt;     my ($sub, $cont) = @_;&lt;br /&gt;     sub {&lt;br /&gt;         my @r = $sub-&gt;(@_);&lt;br /&gt;         $cont-&gt;(@r);&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; # ...&lt;br /&gt;&lt;br /&gt; mul sub {&lt;br /&gt;     Bind(\&amp;minus, sub {&lt;br /&gt;         say sub {}, @_&lt;br /&gt;     })-&gt;(\@_, \@k)&lt;br /&gt; }, \@i, \@j&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В результате, имея подпрограмму Bind, можно вместо специализированных под стиль передачи продолжений подпрограмм использовать обычные функции:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub mul {&lt;br /&gt;     my ($x, $y) = @_;&lt;br /&gt;     map { $$x[$_] * $$y[$_] } 0 .. $#$x;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub minus {&lt;br /&gt;     my ($x, $y) = @_;&lt;br /&gt;     map { $$x[$_] - $$y[$_] } 0 .. $#$x;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; sub say {&lt;br /&gt;     print join(" ", @_), "\n";&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; my @i = (1, 2, 3);&lt;br /&gt; my @j = (2, 3, 4);&lt;br /&gt; my @k = (3, 4, 5);&lt;br /&gt;&lt;br /&gt; sub Bind {&lt;br /&gt;     my ($sub, $cont) = @_;&lt;br /&gt;     sub {&lt;br /&gt;         my @r = $sub-&gt;(@_);&lt;br /&gt;         $cont-&gt;(@r);&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; Bind(\&amp;mul, sub {&lt;br /&gt;     Bind(\&amp;minus, sub {&lt;br /&gt;         Bind(\&amp;say, sub {})-&gt;(@_)&lt;br /&gt;     })-&gt;(\@_, \@k)&lt;br /&gt; })-&gt;(\@i, \@j)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Кстати, можно даже сделать маленькую &lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/07/tailcall-perl5.html"&gt;tailcall оптимизацию&lt;/a&gt;:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub Bind {&lt;br /&gt;     my ($sub, $cont) = @_;&lt;br /&gt;     sub {&lt;br /&gt;         @_ = $sub-&gt;(@_);&lt;br /&gt;         goto &amp;$cont;&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;А если превратить подпрограмму Bind в оператор, то это становиться на что-то очень-очень похоже... Неужели на Haskell?&lt;br /&gt;&lt;br /&gt;Стиль передачи продолжений позволяет симулировать состояния, то есть писать код без изменяемых переменных: лишь абсолютная чистота.&lt;br /&gt;Уж не являются операторы связывания и, соответственно, монады Haskell своеобразными обертками для более простого использования стиля передачи продолжений?&lt;br /&gt;&lt;br /&gt;Если да, то bind и монады в Haskell - это не кусочек императивного мира, а его иллюзия.&lt;br /&gt;То есть Haskell един, а не состоит из двух частей: чистой и грязной. Он чист, абсолютно чист, также как и Clean!&lt;br /&gt;&lt;br /&gt;А как же быть с ленивость? Ведь Haskell не только чист, но и ленив. Что-ж рассуждаем дальше.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Порядок для ленивых&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Оператор связывания&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Представим, что нам надо получить из вне две числа и разделить второе на первое:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my @numbers = (3, 6);&lt;br /&gt; sub get_number() {&lt;br /&gt;     shift @numbers;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; my $x1 = get_number();&lt;br /&gt; my $x2 = get_number();&lt;br /&gt; &lt;br /&gt; sub div($$) {&lt;br /&gt;     my ($x2, $x1) = @_;&lt;br /&gt;     $x2 / $x1;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; print div($x2, $x1);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Результат работы вышеприведенного кода - деление 6 (второе число) на 3 (первое число).&lt;br /&gt;Подпрограмма get_number имитирует получение чисел из внешнего источника.&lt;br /&gt;&lt;br /&gt;А теперь добавим ленивость:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my @numbers = (3, 6);&lt;br /&gt; sub get_number() {&lt;br /&gt;     sub { shift @numbers };&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; my $x1 = get_number();     # метка 1&lt;br /&gt; my $x2 = get_number();     # метка 2&lt;br /&gt; &lt;br /&gt; sub div($$) {&lt;br /&gt;     my ($x2, $x1) = @_;&lt;br /&gt;     $x2-&gt;() / $x1-&gt;();     # метка 4&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; print div($x2, $x1);       # метка 3&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В результате получим не 2, а 0.5, то есть числа перепутаны местами.&lt;br /&gt;Это произошло потому, что в ленивом языке порядок вычисления определен не потоком программы,&lt;br /&gt;а необходимостью в результате конкретного вычисления, или если быть точнее - редукцией графов.&lt;br /&gt;&lt;br /&gt;В нашем примере, добавив ленивость, мы сделали, что при выполнении программы в метке 1 почти ничего не происходит, и в метка 2 также. А вот в метке 3 требуется все таки вывести результат - программа осознает, что хватит лениться и вызывает функцию div, передав ей ленивые x2 и x1. В функции div (метка 4), уже нужны реальные результаты x2 и x1 - происходит получение данных из внешнего источника. Но поскольку нужен сначала x2, а лишь потом x1, то первое число попадает в x2, а не в x1.&lt;br /&gt;&lt;br /&gt;Чтобы задать порядок вычисления можно воспользоваться Стилем передачи продолжений -&lt;br /&gt;для простоты сразу возьмем вышеупомянутую функцию Bind:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my @numbers = (3, 6);&lt;br /&gt; sub get_number() {&lt;br /&gt;     sub { shift @numbers };&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub div($$) {&lt;br /&gt;     my ($x2, $x1) = @_;&lt;br /&gt;     $x2-&gt;() / $x1-&gt;();&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub Bind {&lt;br /&gt;     my ($sub, $cont) = @_;&lt;br /&gt;     sub {&lt;br /&gt;         @_ = $sub-&gt;(@_);&lt;br /&gt;         goto &amp;$cont;&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; Bind(get_number(), sub {&lt;br /&gt;     my $x1 = shift;&lt;br /&gt;     Bind(get_number(), sub {&lt;br /&gt;         my $x2 = shift;&lt;br /&gt;         Bind(\&amp;div, sub {&lt;br /&gt;             print @_;&lt;br /&gt;    # print "$x2/$x1=$_[0]\n"&lt;br /&gt;         })-&gt;(sub {$x2}, sub {$x1})&lt;br /&gt;     })-&gt;();&lt;br /&gt; })-&gt;();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Конечно выглядит ужасно!&lt;br /&gt;&lt;br /&gt;Но если подпрограммы Bind сделать оператором и упростить запись для анонимных подпрограмм, то все намного лучше:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; get_number &gt;&gt;= \x1 -&gt; (get_number &gt;&gt;= \x2 -&gt; (div x2 x1 &gt;&gt;= print))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;А при использовании do нотации - все просто замечательно:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; do x1 &lt;- get_number&lt;br /&gt;    x2 &lt;- get_number&lt;br /&gt;    r  &lt;- div x2 x1&lt;br /&gt;    print r&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Примечание: Haskell не знаю - так что эти две записи наверняка с ошибками.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Dataflow переменные&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Альтернативный способ задания порядка - это использование unborned dataflow переменных.&lt;br /&gt;&lt;br /&gt;Они используется для управления порядком в Mozart-OZ потоках.&lt;br /&gt;&lt;br /&gt;Им подобны "Уникальные типы" в Clean.&lt;br /&gt;&lt;br /&gt;В Haskell они просматриваются в руководствах посвещенных монадам:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; getChar :: RealWorld -&gt; (Char, RealWorld)&lt;br /&gt;  &lt;br /&gt; main :: RealWorld -&gt; ((), RealWorld)&lt;br /&gt; main world0 = let (a, world1) = getChar world0&lt;br /&gt;                   (b, world2) = getChar world1&lt;br /&gt;               in ((), world2)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Хотя мне не понятно зачем они тут, ведь все красиво делается при помощи связывания?&lt;br /&gt;Конечно, можно предположит, что getChar и прочии IO функции настолько ленивы, что им надо передавать всегда новый RealWorld,&lt;br /&gt;но ведь это можно делать за кулисами.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Выводы&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Время от времени читал о Haskell, о монадах - никак не мог понять их. Казалось, что одни руководства противоречат другим.&lt;br /&gt;И только, недавно, когда плюнул на все эти монады, а просто представил чистый и ленивый язык, сразу стало все на свои места.&lt;br /&gt;Нашлось там место и оператору bind, и самим монадам, но не как ключевым фигурам...&lt;br /&gt;Остался один вопрос: зачем так все путанном объясняется в Haskell? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;P.S.&lt;br /&gt;После того как была написана эта заметка решил посмотреть подробней на Clean и нашел там подтвержение вышесказаному.&lt;br /&gt;Может тем, кто хочет понять Haskell монады, следует рекомендовать сначала почитать как в Clean обходятся без них.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-8233817294291577166?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/8233817294291577166/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=8233817294291577166' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8233817294291577166'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8233817294291577166'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2010/12/blog-post.html' title='Стиль передачи продолжений и связывание'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-4523509664379528355</id><published>2010-12-01T11:04:00.009+02:00</published><updated>2010-12-01T11:30:13.505+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MPS'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>IPS::MPS, AnyEvent::HTTPD, AnyEvent::HTTP and DBI</title><content type='html'>Игрался на perl связкой &lt;a href="http://search.cpan.org/perldoc?IPC::MPS"&gt;IPS::MPS&lt;/a&gt;, AnyEvent::HTTPD, AnyEvent::HTTP и DBI.&lt;br /&gt;Сделал четыре процесса: главный (управляющий), HTTP сервер, HTTP клиент, DBI клиент.&lt;br /&gt;Хотя блокируемый процесс тут один: DBI, но этого поиграться с &lt;a href="/2010/11/ipcmps-message-passing-style-of-inter.html"&gt;межпроцессным взаимодействием в стиле передачи сообщений&lt;/a&gt; хватит:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;use IPC::MPS::Event;&lt;br /&gt;use AnyEvent::HTTPD;&lt;br /&gt;use AnyEvent::HTTP;&lt;br /&gt;use DBI;&lt;br /&gt;&lt;br /&gt;my $port = 9090;&lt;br /&gt;&lt;br /&gt;print "Please contact me at: http://127.0.0.1:$port/?q=foo\n";&lt;br /&gt;&lt;br /&gt;my $vpid_server = spawn {&lt;br /&gt;&lt;br /&gt;  my %url2req; # $url =&gt; [$req, ...]&lt;br /&gt;&lt;br /&gt;  my $httpd = AnyEvent::HTTPD-&gt;new(port =&gt; $port);&lt;br /&gt;&lt;br /&gt;  $httpd-&gt;reg_cb (&lt;br /&gt;    '' =&gt; sub {&lt;br /&gt;      my ($httpd, $req) = @_;&lt;br /&gt;      my $q = $req-&gt;parm('q');&lt;br /&gt;      if ($q) {&lt;br /&gt;        my $url = "http://www.google.com/search?q=$q";&lt;br /&gt;        snd(0, "req", $url);&lt;br /&gt;        push @{$url2req{$url}}, $req;&lt;br /&gt;      } else {&lt;br /&gt;        $req-&gt;respond([404, 'NOT FOUND']);&lt;br /&gt;      }&lt;br /&gt;    },&lt;br /&gt;  );&lt;br /&gt;&lt;br /&gt;  receive {&lt;br /&gt;    msg res =&gt; sub {&lt;br /&gt;      my ($from, $url, $data, $headers) = @_;&lt;br /&gt;      for my $req (@{$url2req{$url}}) {&lt;br /&gt;        $req-&gt;respond([200, 'OK', {'Content-Type' =&gt; 'text/html'}, $data]);&lt;br /&gt;      }&lt;br /&gt;      delete $url2req{$url};&lt;br /&gt;    };&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;my $vpid_client = spawn {&lt;br /&gt;  receive {&lt;br /&gt;    msg req =&gt; sub {&lt;br /&gt;      my ($from, $url) = @_;&lt;br /&gt;      http_get $url, sub {&lt;br /&gt;        my ($data, $headers) = @_;&lt;br /&gt;        snd($from, "res", $url, $data, $headers);&lt;br /&gt;      };&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;my $vpid_dbi = spawn {&lt;br /&gt;&lt;br /&gt;  # CREATE DATABASE nick OWNER nick ENCODING 'UTF8';&lt;br /&gt;  # CREATE TABLE urls (id_url SERIAL, datetime TIMESTAMP DEFAULT now(), url text, PRIMARY KEY (id_url));&lt;br /&gt;  # DROP TABLE urls;&lt;br /&gt;  my $data_sourse = "DBI:Pg:dbname=nick;host=localhost";&lt;br /&gt;  my $dbh = DBI-&gt;connect($data_sourse, "nick", "") or die $DBI::errstr;&lt;br /&gt;  my $sth = $dbh-&gt;prepare("INSERT INTO urls (url) VALUES (?)") or die $dbh-&gt;errstr();&lt;br /&gt;&lt;br /&gt;  receive {&lt;br /&gt;    msg res =&gt; sub {&lt;br /&gt;      my ($from, $url) = @_;&lt;br /&gt;      $sth-&gt;execute($url) or die $dbh-&gt;errstr();&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;receive {&lt;br /&gt;  msg req =&gt; sub {&lt;br /&gt;    my ($from, $url) = @_;&lt;br /&gt;    snd($vpid_client, "req", $url);&lt;br /&gt;    warn "Q; $url";&lt;br /&gt;  };&lt;br /&gt;  msg res =&gt; sub {&lt;br /&gt;    my ($from, $url, $data, $headers) = @_;&lt;br /&gt;    snd($vpid_server, "res", $url, $data, $headers);&lt;br /&gt;    snd($vpid_dbi, "res", $url);&lt;br /&gt;    warn "R; $url";&lt;br /&gt;  };&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Забавно получается.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-4523509664379528355?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/4523509664379528355/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=4523509664379528355' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4523509664379528355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4523509664379528355'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2010/12/ipsmps-anyeventhttpd-anyeventhttp-and.html' title='IPS::MPS, AnyEvent::HTTPD, AnyEvent::HTTP and DBI'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-3300539363996805949</id><published>2010-11-24T14:21:00.000+02:00</published><updated>2010-11-24T14:34:39.182+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>IPC::MPS - Message Passing Style of Inter-process communication</title><content type='html'>Немного на русском о межпроцессном взаимодействии в стиле передачи сообщений.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://search.cpan.org/perldoc?IPC::MPS"&gt;IPC::MPS&lt;/a&gt;, - система обмена сообщениями между родительскими и дочерними процессами, а также между дочерними, имеющими общего родителя.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use IPC::MPS;&lt;br /&gt; &lt;br /&gt; my $vpid = spawn { &lt;br /&gt;  receive {&lt;br /&gt;   msg ping =&gt; sub {&lt;br /&gt;    my ($from, $i) = @_;&lt;br /&gt;    print "Ping ", $i, " from $from\n";&lt;br /&gt;    snd($from, "pong", $i);&lt;br /&gt;   };&lt;br /&gt;  };&lt;br /&gt; };&lt;br /&gt; &lt;br /&gt; snd($vpid, "ping", 1);&lt;br /&gt; receive { &lt;br /&gt;  msg pong =&gt; sub {&lt;br /&gt;   my ($from, $i) = @_;&lt;br /&gt;   print "Pong $i from $from\n";&lt;br /&gt;   if ($i &lt; 3) {&lt;br /&gt;    snd($from, "ping", $i + 1);&lt;br /&gt;   } else {&lt;br /&gt;    exit;&lt;br /&gt;   }&lt;br /&gt;  };&lt;br /&gt; };&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Concurrency programming&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Особенностью системы является то, что передача сообщений между дочерними процессами осуществляется родительскими. Поэтому рекомендуется использовать родительские процессы лишь для координации рабочих, а также для хранения общей информации.&lt;br /&gt;&lt;br /&gt;Сообщения передаются посредством UNIX сокетов.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; $vpid = spawn {&lt;br /&gt;   ...&lt;br /&gt;   receive {&lt;br /&gt;    msg "name 1" =&gt; sub {&lt;br /&gt;     my ($from, @args) = @_;&lt;br /&gt;     ...&lt;br /&gt;    };&lt;br /&gt;    msg "name 2" =&gt; sub { ... };&lt;br /&gt;    msg "name 3" =&gt; sub { ... };&lt;br /&gt;    ...&lt;br /&gt;   };&lt;br /&gt;  };&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Создание дочерних процессов происходит не при вызове spawn, а потом, при receive, непосредственно перед вызовом цикла отправки-приема сообщений. Это необходимо чтобы все vpid были определены до вызовов fork. vpid - адрес ссылки на сокет с главного процесса в дочерний.&lt;br /&gt;&lt;br /&gt;Внутри spawn можно делать другие spawn. Если spawn делается внутри receive, то надо вызвать и receive, чтобы запустить дочерние процессы. При этом новый receive добавит свою информацию к старой и передаст управление циклу передачи сообщений старого receive.&lt;br /&gt;&lt;br /&gt;Отправка сообщений.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; snd($vpid, "msg name", @args);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Если vpid равен 0, то это сообщение родительскому процессу.&lt;br /&gt;&lt;br /&gt;Если дочерний процесс видит, что родительский завершился, то он также завершается.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dataflow programming&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Иногда при обработке сообщения может возникнуть ситуация, когда необходимо получить дополнительную информацию от других процессов, и лишь затем продолжить обработку сообщения. Для этого можно послать сообщения с запросом информации, а затем в нужном месте дождаться получения информации при помощи подпрограммы wt (сокращение от wait), не прерывая обработку текущего сообщения.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; snd("vpid_1", "msg_1", @args_1);&lt;br /&gt; snd("vpid_2", "msg_2", @args_2);&lt;br /&gt; &lt;br /&gt; my $r = wt("vpid_1", "msg_1");&lt;br /&gt; ...&lt;br /&gt; my @r = wt("vpid_2", "msg_2");&lt;br /&gt; ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Подпрограмма wt запускает новый цикл ожидания, продожается отправка еще не отправленных и прием новых сообщений, но новые сообщения не обрабатываются, а накапливаются в буфере. Когда получен ответ на необходимое сообщение, этот цикл ожидания завершается и wt возвращает ответ - обработка текущего сообщения продолжается.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my $r = snd_wt($vpid, $msg, @args);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;является сокращением для:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; snd($vpid, $msg, @args);&lt;br /&gt; my $r = wt($vpid, $msg);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The main differences from Erlang&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Внимание, это не Erlang, это Perl IPC::MPS. Основные отличия, вытекающие одно из другого:&lt;br /&gt;&lt;br /&gt;1. Полноценные процессы операционной системы.&lt;br /&gt;2. Подпрограмма spawn непосредственно не создает процессы, а лишь осуществляет подготовительные операции. Процессы создаются при вызове receive.&lt;br /&gt;3. "receive" - "многоразовый", а не "одноразовый", как в Erlang.&lt;br /&gt;4. "receive" внутри "receive" не заменяет временно собой предыдущий, а добавляет новые обработчики сообщений и запускает новые процессы.&lt;br /&gt;5. Чтобы дождаться внутри обработчика сообщения ответ на конкретное сообщение следует использовать подпрограмму wt. В Erlang это делается все тем-же "receive".&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Распределенное программирование&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Чтобы сделать текущий процесс узлом необходимо вызвать подпрограмму listener:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; listener($host, $port);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Подключение к уделенному узлу осуществляется при помощи подпрограммы open_node:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my $vpid = open_node($host, $port);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Чтобы обнаружить закрытие соединения следует определить обработчик сообщения NODE_CLOSED:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; msg NODE_CLOSED =&gt; sub { &lt;br /&gt;  my ($vpid) = @_;&lt;br /&gt;  ...&lt;br /&gt; };&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Это утверждение справедливо как для клиента, так и для сервера.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Совместимость с модулями, основанными на Event, EV и AnyEvent&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;IPC::MPS::Event, IPC::MPS::EV позволяют использовать сторонние модули на основе модулей Event и EV соответственно (напрямую или через AnyEvent).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;P.S.&lt;/b&gt;&lt;br /&gt;Примеры смотрите в каталоге demo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-3300539363996805949?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/3300539363996805949/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=3300539363996805949' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3300539363996805949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3300539363996805949'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2010/11/ipcmps-message-passing-style-of-inter.html' title='IPC::MPS - Message Passing Style of Inter-process communication'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-1676781983176286018</id><published>2010-10-18T11:13:00.002+03:00</published><updated>2010-10-19T09:18:03.495+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Почему Perl</title><content type='html'>Фрагмент из "Распределенное программирование на Perl для домохозяек".&lt;br /&gt;&lt;br /&gt;Если ваш муж программирует на Java, C#, Python или другом подобном языке, то он обязательно с недоумением спросит: "зачем Perl"? Более того, он скажет, что Perl слишком путанный язык со сложным синтаксисом и перегружен излишними возможностями. В ответ можно попытаться объяснить преимущества многогранности и многообразия, но не стоит. Лучше продемонстрируйте на практике. А для наглядности - на его собственном примере.&lt;br /&gt;&lt;br /&gt;Поведите мужа в Макдоналдс! Пусть с недельку поест там, а не дома. Да, это жестоко, ведь еда из Макдоналдса, как и любой фастфуд, вредна для здоровья. А разве Макдоналдс-языки программирования менее вредны? Только фастфуд наносит вред телу, а эти языки - разуму, так как человек погрязает в тесных рамках тех же ООП (объектно-ориентированных предрассудков) и не видит многообразие мира за ними.&lt;br /&gt;&lt;br /&gt;Макдоналдс-языки хороши для массового использования и стандартных ситуаций, а вот если нужно что-то оригинальное... Попросите в Макдоналдсе приготовить вам что-то праздничное ко дню рождения. Наверняка вам из гамбургеров выложат высокую пирамиду, зальют все сверху кетчупом и назовут праздничным тортом. Разве это может сравниться с работой шеф-повара, который даже с простого блюда может сделать шедевр?!&lt;br /&gt;&lt;br /&gt;Колоссальная гибкость и богатые возможности языка Perl являются его визитной карточкой, его изюминкой. Как шеф-повар делает изысканные блюда из простых ингредиентов, добавив лишь маленькую толику нужных пряностей, так при помощи Perl любую сложную задачу можно решить простым способом. Но тут главное не переборщить - специями можно не только украсить трапезу, но и испортить любой продукт, так и используя мощь Perl, можно решение самой простой задачи сделать чрезвычайно сложным и запутанным.&lt;br /&gt;&lt;br /&gt;Аналогия со специями абсолютна. Когда специи попали в Европу, они совершили настоящий переворот в кулинарии. Но потом дошло до абсурда - их стали использовать в таком количестве, что невозможно было определить, что за блюдо подано к столу. Затем произошел полный отказ от специй. И лишь сейчас они занимают место, по праву принадлежащее им: ведь никто не отрицает, что чуточка кардамона сделает дрожжевое тесто вкуснее. А волшебное сочетание корицы и печеных яблок! А мускатный орех - да это же король соусов!&lt;br /&gt;&lt;br /&gt;Конечно, чтобы овладеть мастерством и стать шеф-поваром, необходимо время. Чтобы по настоящему изучить Perl, нужно больше времени, чем потребуется для изучения чего-то попроще. Но оно того стоит.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-1676781983176286018?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/1676781983176286018/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=1676781983176286018' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1676781983176286018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1676781983176286018'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2010/10/perl.html' title='Почему Perl'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-9049254266324196332</id><published>2010-02-03T11:15:00.000+02:00</published><updated>2010-02-03T11:16:11.894+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Всякая всячина и книги</title><content type='html'>Пора заканчивать заниматься ерундой и писать всякую фигню o Perl - блог закрыт. Сажусь за написание двух книг.&lt;br /&gt;&lt;br /&gt;Первая книга будет называется "Событийное программирование на Perl для домохозяек или как успеть приготовить тысячу блюд к приходу гостей".&lt;br /&gt;&lt;br /&gt;Вторая - "Распределенное программирование на Perl для домохозяек".&lt;br /&gt;Эта книга предназначена для тех, кто любому кухонному комбайну предпочитает набор хороших кухонных ножей.&lt;br /&gt;&lt;br /&gt;Логичней было начать с первой, но вторая сейчас интересней, поэтому есть большая вероятность, что первая будет лишь брошюркой.&lt;br /&gt;&lt;br /&gt;Здесь будет опубликованы анонсы. До встречи.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-9049254266324196332?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/9049254266324196332/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=9049254266324196332' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/9049254266324196332'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/9049254266324196332'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2010/02/blog-post.html' title='Всякая всячина и книги'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-5581417009493401364</id><published>2010-01-04T11:26:00.004+02:00</published><updated>2010-01-04T11:26:00.189+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Если бы в Perl не было бы списков :-)</title><content type='html'>Новогодние каникулы продолжаются...&lt;br /&gt;Иногда в праздничном веселье, как нечто далекое, мелькают мысли: кто я, что я делал, perl какой-то...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Создание списка&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sub list($;$) {&lt;br /&gt; my ($h, $t) = @_;&lt;br /&gt; return sub {&lt;br /&gt;  return $h, $t;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;my $x1 = list(1);&lt;br /&gt;my $x2 = list(2, $x1);&lt;br /&gt;my $x3 = list(3, $x2);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Печать списка&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sub print_list($);&lt;br /&gt;sub print_list($) {&lt;br /&gt; my ($list) = @_;&lt;br /&gt; my ($h, $t) = $list-&gt;();&lt;br /&gt; print_list($t) if $t;&lt;br /&gt; print "$h ";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;print_list $x3;&lt;br /&gt;print "\n";&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;map&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sub _Map {&lt;br /&gt; my ($sub, $list) = @_;&lt;br /&gt; my ($h, $t) = $list-&gt;();&lt;br /&gt; my $r = $t ? _Map($sub, $t) : undef;&lt;br /&gt; list($sub-&gt;($h), $r);&lt;br /&gt;}&lt;br /&gt;sub Map(&amp;;$) { &amp;_Map }&lt;br /&gt;&lt;br /&gt;print_list Map { $_[0]**$_[0] } $x3;&lt;br /&gt;print "\n";&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-5581417009493401364?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/5581417009493401364/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=5581417009493401364' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5581417009493401364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5581417009493401364'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2010/01/perl.html' title='Если бы в Perl не было бы списков :-)'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-4694339789403474127</id><published>2009-12-28T09:26:00.000+02:00</published><updated>2009-12-28T09:26:00.215+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Open, каналы и ожидание завершения потомка</title><content type='html'>Трудно искать черную кошку в темной комнате, особенно, если ее там нет.&lt;br /&gt;Но как оказалось, еще трудней не замечать черную кошку, сидящую на видном месте в ярко освещенной комнате!&lt;br /&gt;&lt;br /&gt;Так вот и я потратил приличную часть времени, заметив, что в коде, упрошенном до нижеследующего, родительский процесс ожидает завершения потомка:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my $child_sub = sub { sleep };&lt;br /&gt;&lt;br /&gt; my $child_pid = open my $fh, "-|";&lt;br /&gt; defined $child_pid or die "Can't fork: $!";&lt;br /&gt; &lt;br /&gt; if ($child_pid) {&lt;br /&gt;  # Родитель.&lt;br /&gt; } else {&lt;br /&gt;  # Ребенок.&lt;br /&gt;  $child_sub-&gt;();&lt;br /&gt;  exit;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Впредь, если для дочернего процесса может истечь тайм-аут, буду использовать вызов pipe:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my $child_sub = sub { sleep };&lt;br /&gt;&lt;br /&gt; pipe my $from_child_fh, my $to_parent_fh or die "pipe: $!";&lt;br /&gt; &lt;br /&gt; my $child_pid = fork;&lt;br /&gt; defined $child_pid or die "Can't fork: $!";&lt;br /&gt; &lt;br /&gt; if ($child_pid) {&lt;br /&gt;  # Родитель.&lt;br /&gt;  close $to_parent_fh;&lt;br /&gt; } else {&lt;br /&gt;  # Ребенок.&lt;br /&gt;  close $from_child_fh;&lt;br /&gt;  $child_sub-&gt;();&lt;br /&gt;  exit;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Или буду использовать socketpair.&lt;br /&gt;&lt;br /&gt;С другой стороны, вред от первого варианта на практике всегда отсутствует, наверно поэтому и не замечал этого явления на протяжении многих лет.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-4694339789403474127?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/4694339789403474127/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=4694339789403474127' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4694339789403474127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4694339789403474127'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/12/open.html' title='Open, каналы и ожидание завершения потомка'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-3756879262158014731</id><published>2009-12-21T10:36:00.003+02:00</published><updated>2010-01-14T12:15:53.965+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Настоящие джедаи не используют threads</title><content type='html'>Поскольку термин потоки (threads) очень многогранный, сразу скажу, что под этим термином в этой заметке подразумевается лишь пользовательские потоки операционной системы и Perl потоки, и никаким образом не ядерные потоки, имеющие другую суть.&lt;br /&gt;&lt;br /&gt;Еще на заре истории старые мастера предупреждали, что потоки, разделяемые данные, блокировки и семафоры - это не хорошо, излишне и путано. Достаточно процессов и мультиплексирования. Но не послушали их, и были созданы пользовательские потоки, внеся в этот мир сумятицу и сложность. Да и как создали? Эх...&lt;br /&gt;&lt;br /&gt;В Linux пошли по самому легкому пути: по сути потоки являются немного облегченными процессами. Горячие головы пытались исправить это, но увидели мытарства разработчиков Solaris остудили свой пыл. И только в Windows-NT один из старых мастеров-ренегатов создал нормальные потоки. Но это была медвежья услуга - мир захотел потоков еще больше.&lt;br /&gt;&lt;br /&gt;Даже в лагере BSD начались волнения. Потоки во FreeBSD были, но о них ядро ничего не знало со всеми вытекающими последствиями. Поэтому в основном использовали реализацию Linux потоков. Но лучшая реализация Windows потоков не давала покоя и разработчики решили, что смогут сделать то, что не удалось сделать в Solaris. Так появилась FreeBSD 5 с KSE. Потом выпустили FreeBSD 6, затем 7 и вот недавно - 8, в которой от KSE не осталось ни следа, а потоки во FreeBSD стали иметь модель как у Windows и Solaris: 1 к 1.&lt;br /&gt;&lt;br /&gt;Но не все так мрачно. Еще по времена FreeBSD 4, один из джедаев, помня советы старых мастеров, сделал форк FreeBSD и назвал его DragonFlyBSD. Одной из целей этого проекта стала очистка от блокировок и всего, что мешает масштабированию системы. Вместо блокировок - сообщения.&lt;br /&gt;&lt;br /&gt;И в мире повыше, чем системное программирование, есть островки надежды. Например Erlang, с концепцией легковесных процессов, общающихся посредством сообщений. Также интересен Mozart-OZ. Да и функциональные языки хорошо распараллеливаются. Эти подходы позволяют скрыть от простого программиста "сложность" мультиплексирования и межпроцессорного взаимодействия не внося при этом недостатки, свойственные потокам. А настоящие джедаи понимают, что эта сложность лишь иллюзия.&lt;br /&gt;&lt;br /&gt;Что касается Perl, то он у меня до сих пор собран без поддержки потоков.&lt;br /&gt;Ой, как в этой заметки оказался Perl? Просто эта заметка является исповедью: мне пришлось написать многопоточное приложение на Perl.&lt;br /&gt;Но перед советом джедаев у меня есть два оправдания: мультиплексирующая и многопроцессная версии этого приложения!&lt;br /&gt;&lt;br /&gt;В многопроцессной версии взаимодействие между процессами реализовано посредством сообщений. Такая архитектура позволила многопроцессной версии быть более производительной, чем многопоточная, использующей разделяемые переменные и блокировки. Многопроцессная версия также оказалась чуть проще - не приходилось заботиться о минимизации времени блокировок. Не было нужды также держать перед глазами лист бумаги с порядком блокировок в каждом из потоков, чтобы ненароком не создать патовую ситуацию.&lt;br /&gt;&lt;br /&gt;Все таки был прав батюшка из фильма "Королева бензоколонки", сказав: "к полумерам не привык", либо процессы, либо мультиплексирование (ситуацию с Windows не рассматриваем).&lt;br /&gt;&lt;br /&gt;P.S.&lt;br /&gt;Перечитал - сплошной вихрь эмоций, а не заметка.&lt;br /&gt;&lt;br /&gt;P.P.S.&lt;br /&gt;Радует то, что разработчика Perl уже давно трезво смотрят на потоки. Для эмуляции системного вызова fork под Windows и для использования mod_perl2 с Apache2 в многопоточном режиме они реализовали многопоточность на основе копий интерпретатора Perl, а предыдущей модели Perl потоков забыли как о страшном сне.&lt;br /&gt;&lt;br /&gt;Разработчики же других динамических языков все еще находятся в эйфории от потоков, благо их языки намного проще. Например, вчера случайно попал на совещание питоноводов, на котором обсуждались вопрос частого падения их проекта при высокой нагрузке, а также вопрос, почему часто вместо ожидаемых данных возвращается другая информация, как будто от другого запроса. Услышав это, зная как реализованы потоки в питоне, порекомендовал использовать Apache2 в многопроцессном режиме работы. Система стала работать стабильно и корректно.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-3756879262158014731?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/3756879262158014731/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=3756879262158014731' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3756879262158014731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3756879262158014731'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/12/threads.html' title='Настоящие джедаи не используют threads'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-5872165898555064167</id><published>2009-12-14T09:20:00.000+02:00</published><updated>2009-12-14T09:20:00.302+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='db'/><title type='text'>Почему я не использую ORM</title><content type='html'>Для Perl на CPAN существует большое количество различным ORM, да и очень часто на конференциях делают доклады о них.&lt;br /&gt;Поэтому меня время от времени возникала мысль написать cтатью "Почему я не использую ORM".&lt;br /&gt;&lt;br /&gt;Но потом я увидел одну фразу, и смыл в данной статье отпал, так как в этой одной простой фразе содержался исчерпывающий ответ.&lt;br /&gt;Вот эта фраза, сказанная &lt;a href="http://plumqqz.livejournal.com"&gt;http://plumqqz.livejournal.com&lt;/a&gt;:&lt;br /&gt;"Высокоуровневый декларативный язык (SQL) в случае ORM заменяется низкоуровневым процедурным..."&lt;br /&gt;&lt;br /&gt;От себя вкратце добавлю, что не использую в основном потому что:&lt;br /&gt;1. Движки баз слишком разные. И от базы зависит не только как выбрать информацию с таблиц, но сама структура таблиц и индексов.&lt;br /&gt;2. ORM - это лишний промежуточный слой...&lt;br /&gt;&lt;br /&gt;Но, я не всегда пишу чистый SQL. Иногда генерирую его с более высокоуровневого MetaSQL, который учитывает специфику конкретного проекта. Да и MetaSQL иногда бывает частью некого декларативного описания более высокого уровня и генерируется на его основе, совместно с генерацией части Perl кода.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-5872165898555064167?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/5872165898555064167/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=5872165898555064167' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5872165898555064167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5872165898555064167'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/12/orm.html' title='Почему я не использую ORM'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-8987612538010624749</id><published>2009-12-07T12:03:00.000+02:00</published><updated>2009-12-07T12:05:09.519+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Обновил модуль BGS</title><content type='html'>Обновил модуль &lt;a href="http://search.cpan.org/~kni/BGS-0.02/BGS.pm"&gt;BGS - Background execution of subroutines in child processes&lt;/a&gt;.&lt;br /&gt;Вместо open используется pipe - теперь дочерний процесс может печатать на STDOUT.&lt;br /&gt;Также сделал, что bgs_call возвращает PID дочернего процесса. Зачем это сделал - не знаю,&lt;br /&gt;наверно, надо было бы лучше добавить проверку на допустимость возвращаемого значения блока bgs_call.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-8987612538010624749?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/8987612538010624749/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=8987612538010624749' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8987612538010624749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8987612538010624749'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/12/bgs.html' title='Обновил модуль BGS'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-5979499965689911614</id><published>2009-11-30T11:21:00.001+02:00</published><updated>2009-11-30T11:23:01.675+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>do, eval и return</title><content type='html'>Написал&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;my (@foo) = do {&lt;br /&gt; ...&lt;br /&gt; return ...&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;держа в голове &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;my (@foo) = eval {&lt;br /&gt; ...&lt;br /&gt; return ...&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;А не надо было в варианте с do использовать return, так как это выход не из do, а из подпрограммы, содержащей do.&lt;br /&gt;&lt;br /&gt;:-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-5979499965689911614?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/5979499965689911614/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=5979499965689911614' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5979499965689911614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5979499965689911614'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/11/do-eval-return.html' title='do, eval и return'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-4647822971506491056</id><published>2009-11-24T15:31:00.001+02:00</published><updated>2009-11-24T15:31:49.937+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='parrot'/><title type='text'>Parrot и Rakudo - перезагрузка</title><content type='html'>Как говорилось в &lt;a href="/2009/07/parrot-pir-pasm-l1.html"&gt;"Parrot: PIR, PASM и L1"&lt;/a&gt;, разработчики Parrot вынуждены переписать всю низкоуровневую часть проекта, неизменным останется лишь PIR и PGE.&lt;br /&gt;&lt;br /&gt;Но, как показали разработчики Rakudo в &lt;a href="http://use.perl.org/~pmichaud/journal/39779"&gt;Hague grant work: the new regex engine and NQP&lt;/a&gt;, PGE не слишком удобен на практике. Они собираются отказаться от него в пользу NQP-rx. Соответственно, PIR ждет та же учесть, которая постигла PASM с появлением первого.&lt;br /&gt;&lt;br /&gt;Таким образом, по моему вменению, приобретя колоссальный опыт, разработчики Parrot и Rakudo вернулись почти к той же точке, с которой начинали.&lt;br /&gt;Но не все так печально. Главное есть люди, есть идеи, есть решимость.&lt;br /&gt;&lt;br /&gt;Да наступить "Рождество" в Perl мире!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-4647822971506491056?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/4647822971506491056/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=4647822971506491056' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4647822971506491056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4647822971506491056'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/11/parrot-rakudo.html' title='Parrot и Rakudo - перезагрузка'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-928083750113130525</id><published>2009-11-16T10:30:00.000+02:00</published><updated>2009-11-16T10:30:00.195+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Weighted Random</title><content type='html'>На протяжении многих лет время от времени приходилось использовать код, выбирающий из списка случайные элементы. При этом в большинстве случаев желательно было учитывать веса. Но поскольку требование о взвешивании было желательно, а не обязательно, то лень побеждала, тем более, что эти требования были моими. :-)&lt;br /&gt;&lt;br /&gt;Но вот настал момент, когда я наконец-то победил лень и написал подпрограмму, которая создает замыкание, возвращающие случайный элемент из списка с учетом весов элементов:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub wrand($) {&lt;br /&gt;  my $data = shift;&lt;br /&gt; &lt;br /&gt;  my $total = 0;&lt;br /&gt;  $total += $_ foreach values %$data;&lt;br /&gt; &lt;br /&gt;  my @dist = ();&lt;br /&gt;  while (my ($value, $weight) = each %$data) {&lt;br /&gt;   push @dist, [$value, $weight / $total];&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  return sub {&lt;br /&gt;   my $rand = rand;&lt;br /&gt;   foreach (@dist) {&lt;br /&gt;    return $$_[0] if ($rand -= $$_[1]) &lt; 0;&lt;br /&gt;   }&lt;br /&gt;   return $dist[-1][0];&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Пример использования:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my %foo = (&lt;br /&gt;  # value =&gt; weight &lt;br /&gt;  "one"   =&gt; 3,&lt;br /&gt;  "two"   =&gt; 2,&lt;br /&gt;  "three" =&gt; 1,&lt;br /&gt; );&lt;br /&gt; &lt;br /&gt; my $wrand = wrand(\%foo);&lt;br /&gt; print $wrand-&gt;(), "\n" for 1 .. 10;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Если веса являются целыми числами, то можно использовать более быструю версию:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub iwrand($) {&lt;br /&gt;  my $data = shift;&lt;br /&gt;  my %dist = ();&lt;br /&gt;  while (my ($value, $weight) = each %$data) {&lt;br /&gt;   $dist{keys %dist} = $value foreach 1 .. $weight;&lt;br /&gt;  }&lt;br /&gt;  return sub {&lt;br /&gt;   $dist{int rand keys %dist};&lt;br /&gt;  };&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Смотрите также модуль Math::Random - Random Number Generators.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-928083750113130525?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/928083750113130525/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=928083750113130525' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/928083750113130525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/928083750113130525'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/11/weighted-random.html' title='Weighted Random'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-7869230771009423109</id><published>2009-11-09T09:00:00.002+02:00</published><updated>2009-11-09T09:00:02.066+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Светлая и темная стороны силы Perl</title><content type='html'>"Существует множество способов сделать это", и в каждой конкретной ситуации следует предпочесть наиболее простой, ясный и оптимальный вариант. Вот это белая сторона силы Perl.&lt;br /&gt;&lt;br /&gt;На темной же стороне те "Just another Perl Hackers", кто, используя мощь Perl, делает простые вещи сложными в угоду своему самолюбию.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-7869230771009423109?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/7869230771009423109/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=7869230771009423109' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7869230771009423109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7869230771009423109'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/11/perl.html' title='Светлая и темная стороны силы Perl'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-736234371866648826</id><published>2009-11-02T09:00:00.003+02:00</published><updated>2009-11-02T09:36:17.317+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>"Сегодня без..." - точка, превратившаяся в запятую</title><content type='html'>Чтобы диалектически соединить на новом витке последнюю заметку (&lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/05/blog-post_27.html"&gt;Сегодня без того - не знаю чего&lt;/a&gt;) с первыми из цикла заметок "Сегодня без...", написал нижеприведенный код.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub sum(&amp;$@);&lt;br /&gt; sub sum(&amp;$@) {&lt;br /&gt;  my $sub = shift;&lt;br /&gt;  my ($sum, $h, @t) = @_;&lt;br /&gt;  if (defined $h) {&lt;br /&gt;   sum { $sub-&gt;(@_) } $sum + $h, @t;&lt;br /&gt;  } else {&lt;br /&gt;   $sub-&gt;($sum);&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; my @vector = 1 .. 5;&lt;br /&gt; sum { print shift } 0, @vector;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Вот только эта точка, поставленная в конце цикла заметок "Сегодня без...", превратилась в запятую!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-736234371866648826?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/736234371866648826/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=736234371866648826' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/736234371866648826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/736234371866648826'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/11/blog-post.html' title='&quot;Сегодня без...&quot; - точка, превратившаяся в запятую'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-2442593608124539845</id><published>2009-10-29T09:00:00.000+02:00</published><updated>2009-10-29T09:00:04.638+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>each и return - опасное соседство</title><content type='html'>&lt;pre&gt;&lt;br /&gt; keys %foo;&lt;br /&gt; while (my ($k, $v) = each %foo) {&lt;br /&gt;  ...&lt;br /&gt;  return ...;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Для вышеприведенного кода, если while вызывается более чем один раз за время существования хеша %foo, не следует забывать о сбросе итератора each при помощи keys.&lt;br /&gt;&lt;br /&gt;Я вот забыл, так как практически не использую each, и потратил время на поиски причины, почему код выдает неверный результат. Хорошо, что сразу написал тест и увидел, что есть ошибка.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-2442593608124539845?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/2442593608124539845/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=2442593608124539845' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2442593608124539845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2442593608124539845'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/10/each-return.html' title='each и return - опасное соседство'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-78530221390744734</id><published>2009-10-23T09:00:00.000+03:00</published><updated>2009-10-23T09:00:00.752+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Прототипы и аргументы из списка</title><content type='html'>Вызывая подпрограмму&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub foo($$$$) { }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Так хочется вместо, например,&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; foo(1, $foo{1}, $foo{3}, $foo{5});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Написать&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; foo(1, @foo{qw(1 3 5)});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Но нельзя, так как Perl ругается, что недостаточно аргументов. :-(&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-78530221390744734?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/78530221390744734/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=78530221390744734' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/78530221390744734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/78530221390744734'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/10/blog-post.html' title='Прототипы и аргументы из списка'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-8363519671850366735</id><published>2009-10-15T11:21:00.001+03:00</published><updated>2009-10-15T11:26:54.831+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>PSGI и SpeedyCGI</title><content type='html'>Благодаря &lt;a href="http://kkapp.vox.com/library/post/%D0%B4%D0%B5%D0%B2%D1%8F%D1%82%D1%8C-%D0%BF%D0%BB%D1%8E%D1%81-%D0%B5%D1%89%D1%91-%D0%B4%D0%B2%D0%B0-%D1%81%D0%BF%D0%BE%D1%81%D0%BE%D0%B1%D0%B0-%D0%BE%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D1%82%D1%8C-http-get-%D0%BD%D0%B0-%D0%BF%D0%B5%D1%80%D0%BB%D0%B5.html"&gt;Алексею Капранову&lt;/a&gt; узнал о появлении &lt;a href="http://plackperl.org"&gt;PSGI/Plack&lt;/a&gt;. PSGI - cпецификация интерфейса между Perl web приложениями и web серверами. Plack - реализация.&lt;br /&gt;&lt;br /&gt;Интересно, а &lt;a href="http://www.daemoninc.com/SpeedyCGI"&gt;SpeedyCGI (PersistentPerl)&lt;/a&gt; часто используют для HTTP? Для тех кто не знает: SpeedyCGI можно использовать не только для HTTP при помощи mod_speedycgi из под Apache, а как полноценный PersistentPerl для любых Perl приложений.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-8363519671850366735?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/8363519671850366735/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=8363519671850366735' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8363519671850366735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8363519671850366735'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/10/psgi-speedycgi.html' title='PSGI и SpeedyCGI'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-4638511349230399652</id><published>2009-10-01T09:01:00.002+03:00</published><updated>2009-10-01T09:01:00.282+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Reduced map</title><content type='html'>Как известно в Perl 6 имеются гипер- и редакшноператоры&lt;br /&gt;(заметка о них http://laziness-impatience-hubris.blogspot.com/2009/01/perl6.html).&lt;br /&gt;&lt;br /&gt;Но что же делать в Perl 5?&lt;br /&gt;&lt;br /&gt;Для замены редакшноператоров можно воспользоваться подпрограммой reduce из модуля List::Util или&lt;br /&gt;воспользоваться "reduced map" (rmap) из нижеприведенного модуля (List::Rmap).&lt;br /&gt;Замена же гипероператоров осуществляется при помощи "hyper map" (hmap) того же модуля.&lt;br /&gt;&lt;br /&gt;Рассмотрим примеры.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use strict;&lt;br /&gt; use warnings;&lt;br /&gt; &lt;br /&gt; use List::Rmap qw(reduce rmap hmap);&lt;br /&gt; &lt;br /&gt; my @a = (1, 2, 3);&lt;br /&gt; my @b = (4, 5, 6);&lt;br /&gt; &lt;br /&gt; print           reduce { $a + $b } @a;&lt;br /&gt; # Бyдет напечатано 6&lt;br /&gt; # Это в Perl6 эквивалентно [+] @x&lt;br /&gt; print "\n";&lt;br /&gt; &lt;br /&gt; # reduced map&lt;br /&gt; print join " ", rmap   { $a + $b } @a;&lt;br /&gt; # Бyдет напечатано 1 3 6&lt;br /&gt; # Это в Perl6 эквивалентно [\+] @x&lt;br /&gt; print "\n";&lt;br /&gt;&lt;br /&gt; # hyper map&lt;br /&gt; print join " ", hmap   { $a + $b } @a, @b;&lt;br /&gt; # Бyдет напечатано 5 7 9&lt;br /&gt; # Это в Perl6 эквивалентно @x &gt;&gt;+&lt;&lt; @y&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt; &lt;br /&gt;А вот содержимое вышеупомянутого модуля List::Rmap:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; # Reduced map&lt;br /&gt; &lt;br /&gt; package List::Rmap;&lt;br /&gt; &lt;br /&gt; use strict;&lt;br /&gt; use warnings;&lt;br /&gt; &lt;br /&gt; no strict qw(refs);&lt;br /&gt; &lt;br /&gt; use Exporter;&lt;br /&gt; our @EXPORT_OK = qw(reduce rmap hmap);&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; sub import {&lt;br /&gt; &lt;br /&gt;  # Avoid "Name "..." used only once" warnings for $a and $b.&lt;br /&gt;  my $caller = caller;&lt;br /&gt;  local *{"${caller}::a"};&lt;br /&gt;  local *{"${caller}::b"};&lt;br /&gt; &lt;br /&gt;  goto &amp;Exporter::import&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt; sub reduce (&amp;@) {&lt;br /&gt;  my $code = shift;&lt;br /&gt; &lt;br /&gt;  my $caller = caller;&lt;br /&gt;  local *{"${caller}::a"} = \ my $a;&lt;br /&gt;  local *{"${caller}::b"} = \ my $b;&lt;br /&gt; &lt;br /&gt;  $a = shift;&lt;br /&gt;  foreach (@_) {&lt;br /&gt;   $b = $_;&lt;br /&gt;   $a = &amp;{$code}();&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  return $a;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt; sub rmap (&amp;@) {&lt;br /&gt;  my $code = shift;&lt;br /&gt; &lt;br /&gt;  my $caller = caller;&lt;br /&gt;  local *{"${caller}::a"} = \ my $a;&lt;br /&gt;  local *{"${caller}::b"} = \ my $b;&lt;br /&gt; &lt;br /&gt;  my @r = ($a = shift);&lt;br /&gt;  foreach (@_) {&lt;br /&gt;   $b = $_;&lt;br /&gt;   push @r, $a = &amp;{$code}();&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  return @r;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt; sub hmap (&amp;\@\@) {&lt;br /&gt;  my $code = shift;&lt;br /&gt;  my ($ra, $rb) = @_;&lt;br /&gt; &lt;br /&gt;  @$ra == @$rb or die "Different length of lists.";&lt;br /&gt; &lt;br /&gt;  my $caller = caller;&lt;br /&gt;  local *{"${caller}::a"} = \ my $a;&lt;br /&gt;  local *{"${caller}::b"} = \ my $b;&lt;br /&gt; &lt;br /&gt;  my @r = ();&lt;br /&gt;  foreach ($[ .. $#$ra) {&lt;br /&gt;   $a = $$ra[$_];&lt;br /&gt;   $b = $$rb[$_];&lt;br /&gt;   push @r, &amp;{$code}();&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  return @r;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; 1;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-4638511349230399652?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/4638511349230399652/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=4638511349230399652' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4638511349230399652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4638511349230399652'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/10/reduced-map.html' title='Reduced map'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-7273062509635172931</id><published>2009-09-25T12:03:00.000+03:00</published><updated>2009-09-25T12:04:06.987+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='parrot'/><title type='text'>Parrot: Request Tracker и Trac Tracker</title><content type='html'>Разработчики Parrot отказались от использования Request Tracker в пользу Trac Tracker. А на душе остался осадок: ведь первый написан на Perl, а второй на Python.&lt;br /&gt;&lt;br /&gt;Как-то не очень выглядит ситуация, когда разработчика виртуальной машины, предназначенной в первую очередь для языка Perl, уходят с инструмента, написанного на Perl, тем более, что этот инструмент весьма не плох.&lt;br /&gt;&lt;br /&gt;Но может в Trac есть нечто, о чем я не знаю?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-7273062509635172931?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/7273062509635172931/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=7273062509635172931' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7273062509635172931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7273062509635172931'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/09/parrot-request-tracker-trac-tracker.html' title='Parrot: Request Tracker и Trac Tracker'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-248125706035180212</id><published>2009-09-18T14:55:00.003+03:00</published><updated>2009-09-28T09:41:46.653+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Списки</title><content type='html'>Иногда забываю о таких замечательных модулях как List::Util и List::MoreUtils.&lt;br /&gt;Почему забываю? Потому, что маленькие полезные подпрограммы по работе со списками из этих модулей легко и быстро реализовать самому.&lt;br /&gt;&lt;br /&gt;Но почему не не стоит забывать? Потому, что эти полезные подпрограммы написаны на C, что положительно сказывается на больших списках.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;use strict;&lt;br /&gt;use warnings;&lt;br /&gt;&lt;br /&gt;use List::Util;&lt;br /&gt;&lt;br /&gt;use Benchmark qw(cmpthese);&lt;br /&gt;&lt;br /&gt;my $foo = [1 .. 10000];&lt;br /&gt;&lt;br /&gt;use vars qw($a $b);&lt;br /&gt;&lt;br /&gt;cmpthese(1000, {&lt;br /&gt; 'manual' =&gt; sub {&lt;br /&gt;  my $s = 0;&lt;br /&gt;  $s += $_ foreach @$foo;&lt;br /&gt; },&lt;br /&gt; 'List::Util::sum' =&gt; sub {&lt;br /&gt;  List::Util::sum(@$foo);&lt;br /&gt; },&lt;br /&gt; 'List::Util::reduce' =&gt; sub {&lt;br /&gt;  List::Util::reduce { $a + $b } @$foo;&lt;br /&gt; },&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;__END__&lt;br /&gt;&lt;br /&gt;                     Rate            manual List::Util::reduce   List::Util::sum&lt;br /&gt;manual              153/s                --               -11%              -91%&lt;br /&gt;List::Util::reduce  171/s               12%                 --              -90%&lt;br /&gt;List::Util::sum    1662/s              987%               871%                --&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-248125706035180212?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/248125706035180212/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=248125706035180212' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/248125706035180212'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/248125706035180212'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/09/blog-post_18.html' title='Списки'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-2164682060968589918</id><published>2009-09-10T11:26:00.002+03:00</published><updated>2009-09-10T11:30:48.624+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Url, обработчики и диспетчера</title><content type='html'>&lt;b&gt;Url и обработчики&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Первоначально web сайты целиком состояли из статических HTML страниц.  Затем появился CGI, и сайты стали обзаводиться формами отправки данных и прочими динамическими станицами.  Постепенно процент динамических страниц все увеличивался и увеличивался.  Но url вида http://www.server.com/cgi-bin/foo.cgi не индексировались поисковиками, а также страдала эстетика, поэтому динамические страницы стали маскировать под обычные html: http://www.server.com/foo.html.&lt;br /&gt;&lt;br /&gt;В то же время шло усложнение CGI скриптов, и повторяющийся код стали выносить в общие модули.  Но не весь такой код можно было вынести в модули, в скриптах оставался код простой инициализации.  Проще иметь одну точку входа, в которой посредством диспетчера вызывались обработчики конкретных команд, url.  &lt;br /&gt;&lt;br /&gt;Кстати, одну точку входа имели изначально те, что прятал статику за динамикой при помощи назначения обработчиков в Apache, а не при помощи mod_rewrite. Для тех, кто не прятал динамику за статикой, единая точка входа приводила к не слишком красивым url: http://www.server.com/index.php?action=foo, хотя при помощи mod_rewrite этого можно избежать.&lt;br /&gt;&lt;br /&gt;Далее в статье web сайты являются лишь частным случаем.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Обработчики и диспетчера&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;В perl есть несколько возможностей сообщить диспетчеру какой код необходимо выполнять для каждой конкретной команды (url).&lt;br /&gt;&lt;br /&gt;Можно просто вручную прописать таблицу диспетчеризации. Но при создании нового обработчика, можно забыть его зарегистрировать в таблице диспетчеризации, поэтому желательно чтобы эта регистрации происходила автоматически.&lt;br /&gt;&lt;br /&gt;Автоматизации можно добиться при помощи задания необходимого атрибута подпрограммам-обработчикам и определения подпрограммы MODIFY_CODE_ATTRIBUTES. Например, модуль с обработчиками может иметь следующий вид:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; package Foo::C::Too;&lt;br /&gt; use base qw(Foo::C);&lt;br /&gt; sub foo : Handler(foo) { '...' }&lt;br /&gt; sub too                { '...' }&lt;br /&gt; sub baz : Handler(abc) { '...' }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Где подпрограммы foo и baz являются обработчиками команд foo и abc или обработчиками url http://www.server.com/foo.html и http://www.server.com/abc.html, а подпрограмма too не является обработчиком.&lt;br /&gt;&lt;br /&gt;Модуль Foo::C::Too унаследован от Foo::C, в котором определена MODIFY_CODE_ATTRIBUTES:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; package Foo::C;&lt;br /&gt; sub MODIFY_CODE_ATTRIBUTES {&lt;br /&gt;  my ($package, $sub, @attr) = @_;&lt;br /&gt;  foreach (@attr) {&lt;br /&gt;   if (m/^Handler\((.+)\)$/) {&lt;br /&gt;    # Регистрация в таблице диспетчеризации &lt;br /&gt;    # подпрограммы $sub для команды $1.&lt;br /&gt;    # ...&lt;br /&gt;    last;&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  return ();&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;При запуске ядро просматривает каталог Foo/C/ и загружает все модули Foo::C::*, а perl уже сам, вызывает Foo::C::MODIFY_CODE_ATTRIBUTES для каждой подпрограммы модуля, унаследованного от Foo::C.&lt;br /&gt;&lt;br /&gt;Подробности работы с атрибутами смотрите в perldoc attributes.&lt;br /&gt;&lt;br /&gt;Другим способом создания таблицы диспетчеризации является использования таблицы символов.  После загрузки всех модулей с обработчиками, диспетчер ищет в них подпрограммы, имена которых соответствуют определенным правилам.  В нижеприведенном примере осуществляет поиск обработчиков, имена подпрограмм которых начинаются с префикса "h_":&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; no strict "refs";&lt;br /&gt; foreach (keys %INC) {&lt;br /&gt;  if (m/(Foo\/C\/.+)\.pm$/) {&lt;br /&gt;   my $p = $1;&lt;br /&gt;   $p =~ s/\//::/g;&lt;br /&gt;   while (my ($key, $val) = each(%{*{"$p\::"}})) {&lt;br /&gt;    if ($key =~ m/^h_(.+)/ and my $sub = *$val{CODE}) {&lt;br /&gt;     # Регистрация в таблице диспетчеризации&lt;br /&gt;     # подпрограммы $sub для команды $1.&lt;br /&gt;     # ...&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Соответственно в модуле Foo::C::Too, обработчиками являются h_foo и h_baz:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; package Foo::C::Too;&lt;br /&gt; sub h_foo { '...' }&lt;br /&gt; sub too   { '...' }&lt;br /&gt; sub h_baz { '...' }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;На практике вместо префикса "h_" лучше использовать набор префиксов, например: "u_" - пользовательские команды, "a_" - команды администраторов, "o_" - команды доступные всем.&lt;br /&gt;&lt;br /&gt;Дополнительные свойства обработчиков можно помещать в our переменные с именами, идентичными именам подпрограмм-обработчиков.&lt;br /&gt;&lt;br /&gt;Последний способ: имя обработчика соответствует имени модуля. Этот способ хорошо подходит тогда, когда обработчики являются не просто подпрограммами, а целыми классами. Обычно такие обработчики находятся глубоко в системе и запрятаны за каким-то простым обработчиком.&lt;br /&gt;&lt;br /&gt;Как видим, каждый из перечисленных способов имеет свои особенности, и в зависимости от цели стоит использовать наиболее подходящий.&lt;br /&gt;&lt;br /&gt;А если вы занимаетесь просто созданием сайтов, то посмотрите готовые фреймворки.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-2164682060968589918?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/2164682060968589918/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=2164682060968589918' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2164682060968589918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2164682060968589918'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/09/url.html' title='Url, обработчики и диспетчера'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-8331827886916612402</id><published>2009-09-04T09:59:00.001+03:00</published><updated>2009-09-04T10:25:27.916+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>О вреде программирования</title><content type='html'>Каждая профессия накладывает на человека свой специфический отпечаток. Нередко этот отпечаток имеет негативную составляющую.&lt;br /&gt;&lt;br /&gt;Специальность программирование взращивает в человеке иллюзию легкого исправления будь чего.&lt;br /&gt;Но в реальной жизни не так просто исправить что-то.&lt;br /&gt;&lt;br /&gt;До определенного времени не задумываешься об этом. А вот если, например, залезть на лестницу, провести измерения, запомнить результаты в уме, слезть, взять в руки ножовку, посмотреть, вспоминая замеры, на последнюю подходящих размеров доску, то в голову сразу приходит эта мысль.&lt;br /&gt;&lt;br /&gt;Реальный мир имеет дело с материальными вещами, а их нельзя перекомпилировать после исправления ошибки.&lt;br /&gt;&lt;br /&gt;P.S.&lt;br /&gt;Знание языка Perl лишь усугубляет ситуацию, так как Perl является чрезвычайно гибким языком программирования.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-8331827886916612402?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/8331827886916612402/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=8331827886916612402' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8331827886916612402'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8331827886916612402'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/09/blog-post.html' title='О вреде программирования'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-2294936679159363651</id><published>2009-08-27T09:52:00.000+03:00</published><updated>2009-08-27T09:54:08.306+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - предотвратить случайное изменение данных</title><content type='html'>Когда необходимо предотвратить случайное изменение входных данных в плагине, можно либо передать копию данных, воспользовавшись модулем Clone, либо сделать данные неизменяемыми. Для последнего наиболее оптимальным является использование модуля Data::Lock или Hash::Util (идет в стандартной поставке Perl).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-2294936679159363651?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/2294936679159363651/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=2294936679159363651' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2294936679159363651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2294936679159363651'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/08/perl_27.html' title='Perl - предотвратить случайное изменение данных'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-2330566671169225422</id><published>2009-08-20T09:10:00.002+03:00</published><updated>2009-08-20T09:10:00.132+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl7 за 7 секунд :-)</title><content type='html'>Сейчас идет разработка Perl6, а используется Perl5:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; perl -e 'print "This is Perl v$]!\n"'&lt;br /&gt; This is Perl v5.008008!&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Per6, Perl6 - все хотят Perl6. А я хочу Perl7! :-)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; perl -e '$] = 7; print "This is Perl v$]!\n"'&lt;br /&gt; Modification of a read-only value attempted at -e line 1.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Не вышло... :-(&lt;br /&gt;А если постараться?&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; perl -e 'Internals::SvREADONLY($],0); $]=7; print "This is Perl v$]!\n"'&lt;br /&gt; This is Perl v7!&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ура!!! Perl7 существует!!! На радостях пошел купятся в море!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-2330566671169225422?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/2330566671169225422/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=2330566671169225422' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2330566671169225422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2330566671169225422'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/08/perl7-7.html' title='Perl7 за 7 секунд :-)'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-7156913047964290095</id><published>2009-08-13T10:14:00.001+03:00</published><updated>2009-08-13T10:17:50.616+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl Closure - последний бастион пал</title><content type='html'>Perl предоставляет разработчику полную свободу действий и доступа к любым данным.&lt;br /&gt;&lt;br /&gt;Правда в Perl6 частично отходят от этого принципа, но это лишь внешняя уступка современным объектно-ориентированным предрассудкам, которые легко обходятся при помощи ролей.&lt;br /&gt;&lt;br /&gt;Perl не ограничивает свободу, но и не препятствует ограничению свободы. Вы можете создать полностью закрытые области данных при помощи замыканий. Замыкание - это закрытый и нерушимый бастион в свободном мире Perl.&lt;br /&gt;&lt;br /&gt;Однако на данный момент этот бастион пал.&lt;br /&gt;При помощи новой версии модуля PadWalker можно не только проникнуть за стены крепости-замыкания, но и изменить непосредственно то, что находиться за этими стенами.&lt;br /&gt;&lt;br /&gt;Рассмотрим пример:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use PadWalker;&lt;br /&gt;&lt;br /&gt; sub foo {&lt;br /&gt;     my $foo = shift;&lt;br /&gt;     sub { print "$foo\n" };&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; my $foo = foo(3);&lt;br /&gt; $foo-&gt;();&lt;br /&gt;&lt;br /&gt; PadWalker::set_closed_over($foo, { '$foo' =&gt; \5 });&lt;br /&gt; $foo-&gt;();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В этом примере мы изменили значение переменной $foo c 3 на 5.&lt;br /&gt;Внимание, если эта переменная не read-only, то модификацию замыкания необходимо производить следующим способом:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; PadWalker::set_closed_over($foo, { '$foo' =&gt; \ do { my $foo = 5 } });&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Как говориться в старой военной мудрости: "Нет такой крепости, которую не возможно было бы взять".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-7156913047964290095?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/7156913047964290095/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=7156913047964290095' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7156913047964290095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7156913047964290095'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/08/perl-closure.html' title='Perl Closure - последний бастион пал'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-6837350525626388530</id><published>2009-08-06T09:17:00.001+03:00</published><updated>2009-08-06T09:29:54.659+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='parrot'/><title type='text'>Perl - когда наступит Рождество</title><content type='html'>&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Parrot 2 - начало 2010 года (по материалом Parrot рассылки для разработчиков)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Perl 6   - весна 2010 года (объявлено на YAPC::Europe 2009)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Parrot 3 - начало 2011 года&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-6837350525626388530?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/6837350525626388530/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=6837350525626388530' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/6837350525626388530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/6837350525626388530'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/08/perl.html' title='Perl - когда наступит Рождество'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-2418422023989027478</id><published>2009-07-31T12:00:00.003+03:00</published><updated>2009-08-06T09:13:39.345+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Причины популярности PHP на фоне Perl Web Frameworks</title><content type='html'>Я не согласен с автором заметки &lt;a href="http://dklab.ru/chicken/nablas/55.html"&gt;Причины стремительного успеха PHP&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Истоки PHP находятся в Perl. Он один из многих. Но он "застолбил" себе расширение файлов php, в то время, как другие использовали расширение cgi в каталоге /cgi-bin/, или "цепляли" свой Perl обработчик на страницы с расширением htm или html.&lt;br /&gt;PHP выделился, он стал узнаваемый - а это 80% успеха. Остальные же оставались безликим множеством.&lt;br /&gt;&lt;br /&gt;Следующим по значению фактом является то, что в те далекие времена поисковые машины не индексировали динамику, не индексировали ничего, что находилось в каталоге /cgi-bin/. Поэтому сайты на PHP были целиком известны поисковикам, а на Perl не всегда. Ведь большинство в то время не могли использовать Perl скрипты вне каталога /cgi-bin/ или не знали о такой возможности.&lt;br /&gt;&lt;br /&gt;Мой первый хостер для статики предоставлял url следующего вида: http://hoster/~user/, а для cgi - http://hoster/cgi-bin/user.&lt;br /&gt;PHP в то время обычно также ставился в каталог cgi-bin, но Apache был настроен на обработку расширения php.&lt;br /&gt;Вот и третья причина: url http://server/foo.php выглядит более красивым, чем http://server/cgi-bin/project.cgi?foo.&lt;br /&gt;Кажется пустяк, но психология так не считает.&lt;br /&gt;&lt;br /&gt;Я уверен, что если бы Perl сообществу в те далекие времена удалось бы "протолкнуть" в Apache настройки поумолчанию привязку расширения, например, plp к виртуальному обработчику /cgi-bin/plp.cgi, а с Perl поставлялся бы простой обработчик plp.cgi (обработчик-каркас), то сегодня расстановка сил была бы иной.&lt;br /&gt;&lt;br /&gt;Но история не имеет сослагательного наклонения.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-2418422023989027478?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/2418422023989027478/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=2418422023989027478' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2418422023989027478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2418422023989027478'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/07/php-perl-web-frameworks.html' title='Причины популярности PHP на фоне Perl Web Frameworks'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-4973813485721250679</id><published>2009-07-24T12:00:00.002+03:00</published><updated>2009-08-06T09:14:03.733+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Невидимый Perl</title><content type='html'>Недавно один знакомый удивленно спросил: "А разве проект N не был статическим?". "Нет", - ответил я: "он изначально был полностью написан на Perl".&lt;br /&gt;&lt;br /&gt;На момент создания проекта его основной целью было SEO исследование, объектом которого являлся Google.&lt;br /&gt;В те далекие времена поисковики не индексировали динамику, поэтому проект извне виделся как набор статических HTML страниц.&lt;br /&gt;Проект выполнил свою SEO задачу на отлично и был передан дочерней структуре.&lt;br /&gt;&lt;br /&gt;Дальнейшая судьба проект протекала без моего участия. У проекта появились новые цели, сменился дизайн и одновременно проект был почти полностью переписан на PHP. Именно смена расширения HTML страниц вызвала вопрос с которого начата эта заметка.&lt;br /&gt;&lt;br /&gt;Зачем я рассказал эту историю? Даже не знаю. Наверно чтобы сказать, что вокруг существует множество проектов на Perl, но не видно как и на чем они сделаны. Вот такой невидимый Perl.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-4973813485721250679?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/4973813485721250679/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=4973813485721250679' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4973813485721250679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4973813485721250679'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/07/perl_24.html' title='Невидимый Perl'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-7997476860189237127</id><published>2009-07-17T09:14:00.002+03:00</published><updated>2009-07-17T09:27:58.456+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Аспектно-ориентированное программирование в Perl</title><content type='html'>Существует замечательные модуль &lt;a href="http://search.cpan.org/search?module=Memoize"&gt;Memoize&lt;/a&gt;, который оборачивает указанные подпрограммы чтобы предотвратить их идентичные повторные вызовы и быстро вернуть ранее вычисленный результат. Модуль позволяет в качестве хранилища использовать не только память, но и любой другой объект, связанный с хешем. Также имеется возможность снять "обертку".&lt;br /&gt;&lt;br /&gt;В терминах Аспектно-ориентированного программирования модуль Memoize является аспектом, который применяет к указанным подпрограммам.&lt;br /&gt;&lt;br /&gt;Частичная реализация Аспектно-ориентированного программирования в Perl осуществляется модулем &lt;a href="http://search.cpan.org/search?module=Aspect"&gt;Aspect&lt;/a&gt;.&lt;br /&gt;Этот модуль позволяет применять аспекты по маске ко множеству подпрограмм или к модулям целиком.&lt;br /&gt;Кроме точки применения аспекта "before", существует также точка "after". Аспекты можно применять так, что при выходе из текущей лексической области видимости, они будет автоматически сняты.&lt;br /&gt;&lt;br /&gt;Элементы Aspect-ориентированного программирования имеются и в &lt;a href="http://search.cpan.org/search?module=Moose"&gt;Moose&lt;/a&gt; (Moose::Manual::MethodModifiers).&lt;br /&gt;Аспекты очень гармонично сочетаются с ролями (Moose::Manual::Roles).&lt;br /&gt;&lt;br /&gt;В Perl6 поддержка Aspect-ориентированного программирования сделана на уровне самого языка.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-7997476860189237127?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/7997476860189237127/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=7997476860189237127' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7997476860189237127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7997476860189237127'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/07/perl.html' title='Аспектно-ориентированное программирование в Perl'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-8945993851583410940</id><published>2009-07-08T11:36:00.002+03:00</published><updated>2009-07-08T11:43:57.346+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Tailcall оптимизация в Perl5</title><content type='html'>Еду вчера вечером домой и с интересом наблюдаю за хаотичным блужданием мыслей в своей голове. Так забавно! И вдруг, в мгновение ока все замирает и тут же исчезает - остается лишь одна единственная мысль. Мысль о том, что "все-таки она вертится". То есть - существует. Это я о tailcall оптимизации в Perl5.&lt;br /&gt;&lt;br /&gt;B &lt;a href="/2009/05/2-tail-call.html"&gt;одной заметке&lt;/a&gt; из цикла &lt;a href="/2009/05/blog-post_27.html"&gt;"Сегодня без..."&lt;/a&gt; было упомянуто, что в Per5, в отличии от Perl6, нет tailcall оптимизации. Так вот, это утверждение не совсем корректное. Да, в Perl5 нет автоматической tailcall оптимизации, но ее можно сделать вручную при помощи выражения "goto &amp;NAME".&lt;br /&gt;&lt;br /&gt;В качестве примера узнаем чему равен факториал десяти тысяч:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub fact {&lt;br /&gt;  my ($i) = @_;&lt;br /&gt;  if ($i) {&lt;br /&gt;   return $i * fact($i - 1);&lt;br /&gt;  } else {&lt;br /&gt;   return 1;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Хотя, зачем мне знать это большое число? Да и кто на практике считать факториал рекурсией, если можно циклом. Но пример есть пример. И так, запускаем код на выполнение - Perl выводит предупреждение о слишком глубокой рекурсии и начинает "пухнуть", пытаясь вычислить факториал. Ой, память закончилась...&lt;br /&gt;&lt;br /&gt;Перепишем подпрограмму для tailcall оптимизации:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub fact { _fact(1, $_[0]) }&lt;br /&gt; sub _fact {&lt;br /&gt;  my ($r, $i) = @_;&lt;br /&gt;   if ($i) {&lt;br /&gt;   return _fact($r * $i, $i - 1);&lt;br /&gt;   } else {&lt;br /&gt;    return $r;&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Результат вычисления, как и следовало ожидать, такой же - нехватка памяти.&lt;br /&gt;&lt;br /&gt;А теперь воспользуемся магией "goto &amp;NAME" и сделаем tailcall:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub _fact {&lt;br /&gt;  my ($r, $i) = @_;&lt;br /&gt;   if ($i) {&lt;br /&gt;   @_ = ($r * $i, $i - 1);&lt;br /&gt;   goto &amp;_fact;&lt;br /&gt;   } else {&lt;br /&gt;    return $r;&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Да... Большое число вышло: 35 с половиной тысяч знаков (использовалась прагма bigint).&lt;br /&gt;&lt;br /&gt;Вывод. Не перестаю удивляться возможностям Perl в умелых руках.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-8945993851583410940?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/8945993851583410940/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=8945993851583410940' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8945993851583410940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8945993851583410940'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/07/tailcall-perl5.html' title='Tailcall оптимизация в Perl5'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-1885182502281022325</id><published>2009-07-01T09:18:00.002+03:00</published><updated>2009-07-01T09:29:20.463+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='parrot'/><title type='text'>Parrot: PIR, PASM и L1</title><content type='html'>&lt;div style="padding-left:10em;font-style:italic;"&gt;&lt;br /&gt;                 PASM слишком низкоуровневый для человека и&lt;br /&gt;                 слишком высокоуровневый для машины.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Часть критического кода, используемого виртуальной машиной Parrot, написана на PIR, а часть на С. Постоянное переключение между этими слоями: PASM (PIR) регистрами и C стеком, - существенно снижает производительность Parrot.&lt;br /&gt;&lt;br /&gt;Поэтому сейчас ведутся работы по переписыванию некоторых частей с C на PIR. Это уже было сделано для подсистемы ввода-вывода, и что, как показала практика, повысило ее производительность.&lt;br /&gt;&lt;br /&gt;Однако не все, что хотелось, можно переписать с C на PIR.&lt;br /&gt;&lt;br /&gt;В связи с этим в среде разработчиков Parrot ведутся обсуждения о создании внутреннего языка специального назначения, известного под рабочим названием L1. Это язык будет максимально простым и быстрым.&lt;br /&gt;Если провести аналогию с процессорами, то L1 - это аналог микрокода, на котором реализованы CISC команды поверх RICS ядра процессоров таких как x86.&lt;br /&gt;&lt;br /&gt;По аналогии с PIR (PASM) L1 будет компилироваться в байткод L1BC, который будет исполнятся подсистемой, условно называемой nanoparrot.&lt;br /&gt;&lt;br /&gt;Не надо пугаться, обычной PBC никуда не денется! Он будет на лету транслироваться в L1. Так что разработчики компиляторов языков высокого уровня ничего и не заметят, кроме прироста производительности! :-)&lt;br /&gt;&lt;br /&gt;В заключении можно сказать, что:&lt;br /&gt;PASM - слишком низкоуровневый для человека и появился PIR.&lt;br /&gt;PASM - слишком высокоуровневый для машины и создается L1.&lt;br /&gt;&lt;br /&gt;P.S.&lt;br /&gt;Ссылки по теме:&lt;br /&gt;&lt;a href="https://trac.parrot.org/parrot/wiki/L1Recap"&gt;https://trac.parrot.org/parrot/wiki/L1Recap&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wknight8111.blogspot.com"&gt;http://wknight8111.blogspot.com&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-1885182502281022325?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/1885182502281022325/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=1885182502281022325' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1885182502281022325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1885182502281022325'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/07/parrot-pir-pasm-l1.html' title='Parrot: PIR, PASM и L1'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-4226608698920424672</id><published>2009-06-30T09:42:00.001+03:00</published><updated>2009-06-30T10:20:06.942+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='parrot'/><title type='text'>Скорость Rakudo</title><content type='html'>Как говорилось в &lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/06/parrot-2009-2002.html"&gt;предыдущей заметке&lt;/a&gt; пришло время посмотреть на &lt;a href="http://rakudo.org"&gt;Rakudo&lt;/a&gt; (Parrot реализация Perl6) с практической точки зрения.&lt;br /&gt;&lt;br /&gt;Собираем свежие Parrot и Rakudo (2009-06-30) и запускаем:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; time ./perl6 -e 'say "Just another Perl Hacker"'&lt;br /&gt; Just another Perl Hacker&lt;br /&gt; 3.180u 0.203s 0:04.19 80.6%     4979+37881k 0+10io 0pf+0w&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Что-же так долго?!&lt;br /&gt;&lt;br /&gt;Посмотрим NQP - Not Quite Perl (6):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; cd compilers/nqp&lt;br /&gt; &gt; time ../../parrot nqp.pbc -e 'say("Just another Perl Hacker")'&lt;br /&gt; Just another Perl Hacker&lt;br /&gt; 0.518u 0.031s 0:00.70 77.1%     31+5715k 0+10io 0pf+0w&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;И Perl5:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; time perl -e ' print "Just another Perl Hacker\n"'&lt;br /&gt; Just another Perl Hacker&lt;br /&gt; 0.000u 0.010s 0:00.01 100.0%    0+0k 0+0io 0pf+0w&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Подробное, исследование показало, что основное время занимает загрузка самого perl6.pir. Так что, вероятно, следует направить дальнейшие поиски причины медлительности Rakudo непосредственно в сторону Parrot.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-4226608698920424672?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/4226608698920424672/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=4226608698920424672' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4226608698920424672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4226608698920424672'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/06/rakudo.html' title='Скорость Rakudo'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-776727773147430400</id><published>2009-06-23T10:39:00.002+03:00</published><updated>2009-06-23T10:42:54.037+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='parrot'/><title type='text'>Parrot 2009 - взгляд с 2002 года</title><content type='html'>Parrot 2009 - a 2002 point of view&lt;br /&gt;&lt;br /&gt;Недавно на своем стареньком компьютере обнаружил parrot 2002 года (версия 0.0.9)!&lt;br /&gt;&lt;br /&gt;Да, много воды утекло. Тогда parrot ничего не знал о PASM, а PBC создавался при помощи perl:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; perl assemble.pl -o foo.pbc foo.pasm&lt;br /&gt; parrot foo.pbc&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Конечно этот байт-код не понятен текущей версии parrot (1.3.0).&lt;br /&gt;&lt;br /&gt;Да что говорить о PBC, если даже PASM того времени уже большей частью не совместим с современным. Например, полностью убран "классический" вариант вызова подпрограмм - следует использовать стиль передачи продолжений (Continuation-passing style), что позволило писать более компактно.&lt;br /&gt;&lt;br /&gt;Убрали также пользовательский стек и стеки регистров, вместо них следует использовать Array PMC.&lt;br /&gt;&lt;br /&gt;Полностью изменились Parrot Calling Conventions. Что сделало Parrot совершенно другим, а не тем, которым я знал его в 2002 году.&lt;br /&gt;&lt;br /&gt;Текущие состояние parrot позволяет сказать:&lt;br /&gt;Да здравствуют продолжения и сопрограммы!&lt;br /&gt;Да здравствуют легковесные user-level потоки!&lt;br /&gt;Да здравствуют возможность dataflow execution!&lt;br /&gt;&lt;br /&gt;И самое главное, появился PIR (Parrot Intermediate Representation), за которым прячутся все тонкости работы с подпрограммами, и с которым отпадает необходимость жонглировать регистрами.&lt;br /&gt;&lt;br /&gt;На PASM уже никто не пишет и его не развивают. Все используют PIR!&lt;br /&gt;&lt;br /&gt;PIR - это:&lt;br /&gt; + subroutine linkage&lt;br /&gt; + named, optional, and slurpy parameters&lt;br /&gt; + method calls&lt;br /&gt; + multimethod dispatch&lt;br /&gt; + register allocation&lt;br /&gt; + macros&lt;br /&gt;&lt;br /&gt;Имеется также Parrot Compiler Tools - набор инструментов для написание компиляторов с различных языков. Rakudo уже давно использует его. Вероятно, скоро и сам Parrot не будет нуждаться в perl.&lt;br /&gt;&lt;br /&gt;Parrot набрал силу. Это уже не ребенок, а отрок.&lt;br /&gt;Настала пора посмотреть в сторону Perl6 (Rakudo) с практической точки зрения.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-776727773147430400?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/776727773147430400/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=776727773147430400' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/776727773147430400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/776727773147430400'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/06/parrot-2009-2002.html' title='Parrot 2009 - взгляд с 2002 года'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-8890433678878910948</id><published>2009-06-17T09:10:00.001+03:00</published><updated>2009-06-17T10:02:00.311+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Поддержка YAML в Perl</title><content type='html'>Недавно узнал, что с момента моего знакомства с &lt;a href="http://www.yaml.org/"&gt;YAML&lt;/a&gt; (1.0) у него появились новые возможности. Проверим поддержку их в Perl модулях:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; YAML       VERSION: 0.68&lt;br /&gt; YAML::XS   VERSION: 0.32&lt;br /&gt; YAML::Syck VERSION: 1.07&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Поддержка utf-8 реализована во всех этих модулях (у YAML::Syck - включается опционально, как и многое другое). Но есть нюансы: входные данные должны быть последовательностью байтов, а не Perl строкой (подразумевается is_utf8 флаг). На выходe YAML и YAML::XS дают YAML в виде последовательности байтов, а YAML::Syck - Perl строки. YAML::Syck может принимать YAML в виде Perl строки.&lt;br /&gt;&lt;br /&gt;Комментарии поддерживаются в YAML::XS и YAML::Syck, а в модуле YAML нет.&lt;br /&gt;&lt;br /&gt;Ссылки на другие элементы поддерживаются всеми модулями, а слияния - ни одним из них.&lt;br /&gt;&lt;br /&gt;Поддержка тегов и типов данных оставляет желать лучшего, так что на практике их использовать затруднительно. Модуль YAML::Syck имеет поддержку binary типа, но только для чтения.&lt;br /&gt;&lt;br /&gt;Производительность YAML::XS и YAML::Syck примерно одинакова.&lt;br /&gt;&lt;br /&gt;Если сравнивать YAML и JSON, то JSON в первую очередь стоит использовать для обмена информацией между программами, а YAML - для записи и редактирования информации человеком, тем более, что YAML более нагляден, чем JSON.&lt;br /&gt;&lt;br /&gt;P.S.&lt;br /&gt;Внимание! В текущей версии YAML::XS (0.32) имеется утечка памяти.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-8890433678878910948?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/8890433678878910948/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=8890433678878910948' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8890433678878910948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8890433678878910948'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/06/yaml-perl.html' title='Поддержка YAML в Perl'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-1555223914971920380</id><published>2009-06-10T09:25:00.001+03:00</published><updated>2009-06-10T09:32:26.523+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Moose Benchmark - as swift as an arrow!</title><content type='html'>Moose (постмодерн объектная система для Perl 5) с первого взгляда кажется монстром. Даже в названии: Лось - животное не маленькое. Но, как говориться, у страха глаза велики, поэтому возьмем и банально измерим как он велик и быстр.&lt;br /&gt;&lt;br /&gt;Не будем мерить скорость загрузки, компиляции... - у нас ведь persistent perl (mod_perl, FastCGI). Да и место занимаемое в памяти не так важно важно, так как мы используем операционные системы, которые умеют Copy-on-Write. Остановимся только на быстродействии.&lt;br /&gt;&lt;br /&gt;Чтобы тест не был искусственным, возьмем объект из реального проекта. Сделаем различные реализации его и посмотрим какова скорость выполнения всех регрессионных тестов этого объекта для каждой из реализаций.&lt;br /&gt;&lt;br /&gt;В тестировании принимали участие следующие реализации:&lt;br /&gt;&lt;br /&gt;- классическая Perl 5;&lt;br /&gt;- построенная на замыканиях - для массовки; смотрите подобный объект в заметке &lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/06/blog-post.html"&gt;Объекты на замыканиях - надежная защита&lt;/a&gt;);&lt;br /&gt;- Mouse (version 0.22) - как частичный заменитель Moose, когда есть жесткое ограничение по памяти;&lt;br /&gt;- Moose (version 0.77).&lt;br /&gt;&lt;br /&gt;Вот результаты теста (в секундах):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; Perl 5                 0.041&lt;br /&gt; Closure                0.045&lt;br /&gt; Mouse                  0.074&lt;br /&gt; Moose                  0.105&lt;br /&gt; Moose make_immutable   0.048&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Моему удивлению не было предела! Работа с Mouse объектом почти в 2 раза дольше, чем с классическим, с Moose - в 2.5, Но если make_immutable, то скорость Moose близка к скорости обычных perl объектов!!!&lt;br /&gt;&lt;br /&gt;А вот скорость Mouse подтвердила слова своего автора, что необходимо применять Moose, а не Mouse.&lt;br /&gt;Mouse сделал лишь для того, чтобы можно было использовать возможности Moose там, где мало памяти и важна скорость загрузки.&lt;br /&gt;&lt;br /&gt;Вывод. Использование Moose, при условии make_immutable, не оказывает существенного снижения производительности!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-1555223914971920380?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/1555223914971920380/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=1555223914971920380' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1555223914971920380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1555223914971920380'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/06/moose-benchmark-as-swift-as-arrow.html' title='Moose Benchmark - as swift as an arrow!'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-1323454059772789863</id><published>2009-06-10T09:15:00.009+03:00</published><updated>2009-06-10T11:53:14.455+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vcs'/><title type='text'>Введение в контроль версий</title><content type='html'>&lt;b&gt;Предисловие&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Контроль версий? А зачем он вообще нужен? Нужен, более того вы всегда используете контроль версий в той или иной степени, даже не подозревая об этом! Контроль версий - это летопись, это история. А история, как известно, - это путеводитель в будущее.&lt;br /&gt;&lt;br /&gt;Даже, когда вы работаете в одиночку над статьей или маленькой программой, вы используете контроль версий. Вот только системой контроля версий выступает ваш ум, ваша память.&lt;br /&gt;&lt;br /&gt;При работе над более крупным проектом без системы контроля версий уже не обойтись. Создание каждодневной копии проекта - это тоже по сути примитивная система контроля версий. Так вы страхуетесь: вы можете не бояться "поломать все", так как всегда имеете под рукой рабочую копию проекта.&lt;br /&gt;&lt;br /&gt;При работе в команде на первый план выходит поддержка целостности системы, помогающая предотвращать ситуации, когда один разработчик "затирает" работу другого. Конечно и в этом случае можно обойтись "ручной регулировкой", но зачем, если можно автоматизировать процесс.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Экскурс в историю&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;У каждого произведения есть автор, а также могут быть и соавторы. Когда соавтор приносит новую версию какой либо части произведения, автору необходимо узнать об этих изменениях и внести их в оригинал.&lt;br /&gt;&lt;br /&gt;Для этих целей была создана а начале 1970 годов программы diff. Она сравнивает два файла (оригинал и новую версию) и показывает, какие строки были изменены (diff умеет также сравнивать целые каталоги).&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; diff -u file_old.txt file_new.txt &gt; file.diff&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Затем автор, имея перед глазами результат работы diff, вносил правки в оригинал. Вносил, вносил, вносил... Первому надоело так делать автору программы patch, которая появилась на свет в 1985 году. Эта программа автоматически применяет патч (diff файл) к исходному файлу или каталогу:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; patch &lt; file.diff&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Несмотря на солидный возраст эти программы до настоящего времени продолжают оставаться актуальными. А любой уважающий себя текстовый редактор умеет работать в diff режиме.&lt;br /&gt;&lt;br /&gt;Вернемся к контролю версий. Хранить состояния проекта в виде полных копий слишком накладно, особенно в те далекие времена, когда объемы дисков измерялись килобайтами.&lt;br /&gt;Поэтому в 1985 году используя механизмы работы diff, patch и diff3 создали RCS (Revision Control System), которая для каждого файла хранит самую последнюю версию и набор изменений между состояниями, что позволяет получить любую из предыдущих версий файла.&lt;br /&gt;Однако у RCS был существенный недостаток - она не была предназначена для групповой работы, поэтому на ее основе сделали CVS (Concurrent Versions System). Но у CVS также имелись недостатки, связанные с тем, что CVS работала на уровне файлов, а не на уровне проекта целиком. В связи с этим для замены CVS была разработана более удобная в работе SVN (Subversion).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Азы "садоводства"&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Поскольку репозиторий системы контроля версий, в отличии от набора копий проекта, является целостной структурой, чтобы ориентироваться в нем принято ставить метки - этакие маркеры, отмечающие различные состояний, например версии продукта.&lt;br /&gt;&lt;br /&gt;Развитие любого продукта редко происходит линейно. Имеется главное направление, в терминах систем контроля версий - ствол, и направления развития стабильных версий продукта, а также экспериментальные направления. Направления, отличные от основного, называют ветками. То есть развитие продукта можно представить в виде абстрактного дерева.&lt;br /&gt;&lt;br /&gt;Рассмотрим пример. Ваша команда, работая на стволе, выпустила первую версию продукта - в репозитории поставили метку RELENG_1_0_REL (RELENG - это сокращение от release engineering) и продолжили работать, двигаясь ко второй версии. В это время в релизе 1.0 обнаруживается досадная оплошность, тогда вы от метки RELENG_1_0_REL, создаете ветку RELENG_1, на которой исправляете ошибку и выпускаете версию 1.1, поставив в репозитории метку RELENG_1_1_REL. Затем оказывается, что одно реализованное на стволе важное новшество можно легко перенести в версию 1.1, так как выход версии 2.0 будет не скоро, вы принимаете решение, выпустить версию 1.2, содержащую это новшество. Для этого необходимые изменения сливаются со ствола на ветку RELENG_1, и с выпуском релиза 1.2 ставиться метка RELENG_1_2_REL.&lt;br /&gt;&lt;br /&gt;Кроме вышеупомянутых веток, можно создавать так называемые экспериментальные ветки, на которых обкатываются какие-то уж очень неординарные новшества проекта. Если эти оказались полезными, то код с экспериментальной ветки сливают на ствол, иначе ветку "забрасывают".&lt;br /&gt;&lt;br /&gt;Если непосредственно перед релизом требуется дополнительная подготовка, например документации или части исходников, то релиз RELENG_1_0_REL делают не на стволе, а непосредственно на ветке RELENG_1, место отщепления которой маркируют тегом RELENG_1_BP (break point). Этот тег необходим, чтобы, например, можно было посмотреть различия ветки от ствола в момент отщепления.&lt;br /&gt;&lt;br /&gt;Конечно, есть и другие принципы построения дерева проекта, но вышеприведенный мне кажется наиболее оптимальным.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Особенности систем контроля версий&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Системы контроля версий можно разбить на два типа: централизованные и распределенные. К централизованным относятся CVS, Subversion (он же SVK), к распределенным - Darcs, Mercurial, Git.&lt;br /&gt;&lt;br /&gt;Основные особенности централизованных систем:&lt;br /&gt;&lt;br /&gt;1. Все дерево проекта храниться в одном едином репозитории.&lt;br /&gt;2. Можно получить лишь необходимую часть проекта, ветки.&lt;br /&gt;3. Для работы необходимо быть online.&lt;br /&gt;&lt;br /&gt;Основные особенности распределенных систем:&lt;br /&gt;&lt;br /&gt;1. Каждая ветка проекта обычно - это отдельный репозиторий.&lt;br /&gt;2. Нельзя получить часть проекта - только репозиторий полностью.&lt;br /&gt;3. Можно работать offline.&lt;br /&gt;&lt;br /&gt;Рассмотрим подробней каждый из 3 пунктов.&lt;br /&gt;&lt;br /&gt;1. У централизованой системы создание ветки - это очень легкая операция, а сами ветки - всего лишь изменения. А у распеределенной системы, чтобы сделать ветку, необходимо создать полноценную копию репозитория. Чтобы минимизировать занимаемое место набор распределенных репозиториев оптимизируют за счет использования жестких ссылок файловой системы. Эту операцию желательно повторять после масштабных слияний между локальными ветками.&lt;br /&gt;&lt;br /&gt;2. Когда вы работаете над чаcтью очень большого проекта, то возможность получить лишь необходимую составляющую - это достаточно полезное свойство централизованных систем контроля версий. Например, вас не отвлекают коммиты в те части проекта, к которым вы не имеете прямого отношения.&lt;br /&gt;&lt;br /&gt;3. Необходимость быть online при современном развитии коммуникаций можно считать незначительным требованием. Это требование становиться еще мягче, если учесть, что можно работать не со всем репозиторием, а лишь с необходимой частью, Да и самые часто используемые команды: state и diff - можно использовать offline.&lt;br /&gt;&lt;br /&gt;Работая с распределенной системой, не следует забывать, что чем дольше находишься offline, тем выше вероятность возникновения конфликтов. Кстати, конфликты проще решать, когда для каждого независимого участка работы используется отдельная локальная копия репозитория.&lt;br /&gt;&lt;br /&gt;Если вы используете централизованную систему контроля версий планируете находиться вне сети продолжительное время, то можно перейти в режим создания патчей. К слову, манипулировать патчами удобно при помощи Darcs, который представляет собой скорее систему обмена патчами, нежели систему контроля версий. В крайнем случае, поверх централизованной системы всегда можно сделать распределенную, например SVK поверх SVN.&lt;br /&gt;&lt;br /&gt;Подводя итоги, можно сказать, что выбор между централизованной и распределенной системой контроля версий целиком зависит от стиля работы команды. И централизованные, и распределенные системы имеют как преимущества так и недостатки, но ни один из них не является критичным. Совместить достоинства обоих подходов обещают в Subversion 2, добавив некоторые элементы распределенных систем.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-1323454059772789863?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/1323454059772789863/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=1323454059772789863' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1323454059772789863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1323454059772789863'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/06/blog-post_10.html' title='Введение в контроль версий'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-5301356756488807901</id><published>2009-06-03T11:50:00.002+03:00</published><updated>2009-06-03T11:56:48.179+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Объекты на замыканиях - надежная защита</title><content type='html'>Perl не препятствует прямому обращению и управлению данными объектов. Просто существует договоренность, что так делать не хорошо. Если все-таки необходимо явно возвести препятствие прямому доступу, можно воспользоваться Inside-out объектами. Однако Inside-out содержат лазейку, которая позволяет заглянуть за кулисы объекта (смотрите &lt;a href="http://laziness-impatience-hubris.blogspot.com/2008/12/perl5-perl6.html"&gt;"Закрытые объекты" в Perl5 и Perl6&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Полную закрытость данных объекта обеспечивает лишь замыкание.&lt;br /&gt;&lt;br /&gt;Рассмотрим в качестве примера объект, конструктор которого принимает число, и который имеет два метода: too - возвращает инициализирующие число, baz - возвращает результат сложения с указным числом:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; package Foo;&lt;br /&gt; &lt;br /&gt; sub new {&lt;br /&gt;  shift;&lt;br /&gt;  my $foo  = shift;&lt;br /&gt;  my $self = \$foo;&lt;br /&gt;   bless $self;&lt;br /&gt;   return $self;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub too {&lt;br /&gt;  my $self = shift;&lt;br /&gt;  return $$self;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub baz {&lt;br /&gt;  my $self = shift;&lt;br /&gt;  return $$self + shift;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; package main;&lt;br /&gt; my $foo = Foo-&gt;new(2);&lt;br /&gt; print $foo-&gt;too(),  "\n"; # 2&lt;br /&gt; print $foo-&gt;baz(3), "\n"; # 5&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Замыкание с аналогичным функционалом выглядит следующим образом:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub new_foo {&lt;br /&gt;  my $foo  = shift;&lt;br /&gt;  return sub {&lt;br /&gt;   my $method = shift;&lt;br /&gt;   if ($method eq "too") {&lt;br /&gt;    return $foo;&lt;br /&gt;   } elsif ($method eq "baz") {&lt;br /&gt;    return $foo + shift;&lt;br /&gt;   }&lt;br /&gt;  };&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; my $foo = new_foo(2);&lt;br /&gt; print $foo-&gt;("too"),    "\n"; # 2&lt;br /&gt; print $foo-&gt;("baz", 3), "\n"; # 5&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Вызов методов объекта-замыкания несколько необычен для тех, кто привык к объектам на основе классов. К счастью, Perl очень гибкий языки и позволяет устранить вышеупомянутое "неудобство", "посвятив" быть объектом непосредственно само замыкание:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; package Foo;&lt;br /&gt; &lt;br /&gt; sub new {&lt;br /&gt;  shift;&lt;br /&gt;  my $foo  = shift;&lt;br /&gt;  my $self =  sub {&lt;br /&gt;   my $method = shift;&lt;br /&gt;   if ($method eq "too") {&lt;br /&gt;    return $foo;&lt;br /&gt;   } elsif ($method eq "baz") {&lt;br /&gt;    return $foo + shift;&lt;br /&gt;   }&lt;br /&gt;  };&lt;br /&gt;   bless $self;&lt;br /&gt;   return $self;&lt;br /&gt; } &lt;br /&gt;&lt;br /&gt; foreach my $method (qw(too baz)){&lt;br /&gt;  no strict 'refs';&lt;br /&gt;  *$method = sub { my $self = shift; return $self-&gt;($method, @_) };&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; package main;&lt;br /&gt; my $foo = Foo-&gt;new(2);&lt;br /&gt; print $foo-&gt;too(),  "\n"; # 2&lt;br /&gt; print $foo-&gt;baz(3), "\n"; # 5&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Как видим, все просто, единственно, что пришлось добавить, так это трансляцию методов доступа в вызовы замыкания. Но при этом, имея единственную точку входа, можно легко добавить различные проверки доступа к методам объекта.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-5301356756488807901?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/5301356756488807901/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=5301356756488807901' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5301356756488807901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5301356756488807901'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/06/blog-post.html' title='Объекты на замыканиях - надежная защита'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-2697519876836159251</id><published>2009-05-27T09:21:00.010+03:00</published><updated>2009-10-29T09:56:48.714+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Сегодня без того - не знаю чего</title><content type='html'>На этот раз Perl Фея дала мне время окончательно проснуться, а не шептала сонному задание на ушко.&lt;br /&gt;После предыдущей встречи, описанной в &lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/05/return_20.html"&gt;http://laziness-impatience-hubris.blogspot.com/2009/05/return_20.html&lt;/a&gt;, я был готов ко всему что угодно, но такого даже не мог представить. Увидев, что я открыл глаза, Фея подошла, приложила свой тоненький пальчик к кончику моего носа, загадочно подмигнула и тихо прошептала: "А сегодня без того - не знаю чего".&lt;br /&gt;&lt;br /&gt;Я смотрел на нее как баран на новые ворота, а она села на край дивана, взяла с полки книгу о виноградарстве и стала ее неторопливо листать. Через некоторое время, видя, что я еще нахожусь в замешательстве от задания, Фея сказала: "Я подожду тут - на улице ведь ливень, а ты не отвлекайся, работай".&lt;br /&gt;&lt;br /&gt;Прошла минута или больше, а я все еще продолжал стоять на месте как вкопанный. "Кстати, вот тут, при описании процесса формирования высокоштамбового двуплечного кордона со свисающим приростом, забыли упомянуть про резервные сучки замещения. А ты ведь недавно посадил четыре куста винограда и собираешься придавать им эту форму, так что обрати внимание на возможность быстрой замены поврежденных рукавов", - Фей взглянула в мою сторону и ее улыбка вернула мне способность мыслить. "Какая все таки разносторонне образованная Фея!", - подумал я и спросил: "Насчет задания... Я не понимаю, что ты хочешь чтобы я сделал".&lt;br /&gt;&lt;br /&gt;"Ну как не понимаешь? Ты, наверно, еще не проснулся. В позапрошлый раз я попросила тебя сделал "без return", затем - "без return, но наоборот". Сегодня сделай что-то нечто среднее! Все очень просто", - лукаво улыбнулась она и опустила взгляд в книгу.&lt;br /&gt;&lt;br /&gt;Легко сказать, что-то среднее... Возвращать не возвращая, вызывать не вызывая... Точно! Придумал! Надо вызывать возвращаемое, не передавая информацию как вызывать! Если бы я не был так увлечен придуманным решениям, то я бы заметил, как Фея украдкой одобрительно посмотрела на меня. Нет, феи, не способны читать мысли людей, но они способны тонко чувствовать их.&lt;br /&gt;&lt;br /&gt;И так, через минуту код из предыдущих заданий (&lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/05/return.html"&gt;http://laziness-impatience-hubris.blogspot.com/2009/05/return.html&lt;/a&gt;, &lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/05/return_20.html"&gt;http://laziness-impatience-hubris.blogspot.com/2009/05/return_20.html&lt;/a&gt;) был преобразован к следующему виду:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub mul(&amp;\@\@) {&lt;br /&gt;  my ($sub, $x, $y) = @_;&lt;br /&gt; my @r = map { $$x[$_] * $$y[$_] } 0 .. $#$x;&lt;br /&gt; return sub { $sub-&gt;(@r) };&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub minus(&amp;\@\@) {&lt;br /&gt;  my ($sub, $x, $y) = @_;&lt;br /&gt;  my @r = map { $$x[$_] - $$y[$_] } 0 .. $#$x;&lt;br /&gt; return sub { $sub-&gt;(@r) };&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; sub say(&amp;@) {&lt;br /&gt;  my $sub = shift;&lt;br /&gt;  print join(" ", @_), "\n";&lt;br /&gt; return sub { $sub-&gt;() };&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; sub main() {&lt;br /&gt;  my @i = (1, 2, 3);&lt;br /&gt;  my @j = (2, 3, 4);&lt;br /&gt;  my @k = (3, 4, 5);&lt;br /&gt;&lt;br /&gt;  return mul { minus { say {} @_ } @_, @k } @i, @j;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; my $sub = \&amp;main;&lt;br /&gt; $sub = $sub-&gt;() while $sub;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Подпрограммы-кирпичики не возвращают ссылку на подпрограммы-клей и результаты свой работы. Они возвращают ссылку на подпрограммы, которые в свою очередь вызывают подпрограммы-клей, передавая им в качестве аргументов результат работы подпрограммы-кирпичика. Таким образом "большая вызывалка" ничего не знает о результатах работы подпрограммы-кирпичиков.&lt;br /&gt;&lt;br /&gt;Поставив последнюю точку, хотел было позвать Фею, но она уже стояла за моей спиной. Посмотрела, одобрительно кивнула и сказала: "Ну, я полетела, тем более, что дождь закончился".&lt;br /&gt;&lt;br /&gt;"Постой", - остановил ее я: "а каков смысл этих заданий?" "Все таки мне нельзя быть такой обворожительно красивой, ведь глядя на меня твой мысли пытаются", - игриво ответила она.&lt;br /&gt;&lt;br /&gt;"Ну посмотри, я же вплотную подвела тебя к...", - не успела Фея закончить фразу, как я ее перебил: "... к событийно-управляемому стилю программирования БЕЗ каких либо глобальных структур данных!"&lt;br /&gt;"Молодец, все верно. Стоит лишь заменить return на регистратор обработчиков, а "большую вызывалку", как ты ее смешно называешь, - на генератор или цикл ожидания событий...", - продолжила она.&lt;br /&gt;&lt;br /&gt;А на улице уже во всю светило яркое солнце, воздух после дождя был свеж как никогда. "Все, мне пора. До встречи." - сказала Фей, послала воздушный поцелуй и в туже мить растаяла в воздухе.&lt;br /&gt;&lt;br /&gt;Вот, а вы говорите, что Фей нет. Они есть, к тому же очень симпатичные и обворожительные!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-2697519876836159251?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/2697519876836159251/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=2697519876836159251' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2697519876836159251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2697519876836159251'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/05/blog-post_27.html' title='Сегодня без того - не знаю чего'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-3451870727515500893</id><published>2009-05-20T09:12:00.004+03:00</published><updated>2009-05-20T09:20:32.477+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Сегодня без return - выворачиваем наизнанку</title><content type='html'>Похоже это уже становиться традицией - задавать задачки спозаранку.&lt;br /&gt;Оказывается, существует Perl Фея, которая по утрам, когда пора вставать, будит всех Just another Perl Hacker.&lt;br /&gt;О прошлом появлении Феи читайте в &lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/05/return.html"&gt;http://laziness-impatience-hubris.blogspot.com/2009/05/return.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Она очень осторожна, но сегодня, устроив засаду, я ее увидел первый раз.&lt;br /&gt;Фей, поняв, что я не сплю, от неожиданности смутилась, похвалила меня за решение задачи "Сегодня без return",&lt;br /&gt;и тут же кокетливо спросила:&lt;br /&gt;- А сможешь наоборот?!&lt;br /&gt;- Это как? - удивился я.&lt;br /&gt;- Ну, ведь это ты Perl Hacker, а не я - придумай, - стрельнув зелеными глазами ответила она и улетела.&lt;br /&gt;&lt;br /&gt;Да... Озадачила...&lt;br /&gt;И так, в прошлый раз мы избавились от return и это наш резерв.&lt;br /&gt;Если наоборот, то возвращаем все return, и используем их чтобы, чтобы...&lt;br /&gt;Неужели чтобы предотвратить вызовы подпрограммы!!!&lt;br /&gt;&lt;br /&gt;Что-то тут не так - совсем без вызовов невозможно.&lt;br /&gt;Может стоит лишь упорядочить их, централизовать в одном месте?&lt;br /&gt;И будет один "большой вызов", не множество "маленьких".&lt;br /&gt;&lt;br /&gt;Возьмем пример из предыдущей заметки и перепишем его так, что подпрограммы-кирпичики не вызывают подпрограммы-клей,&lt;br /&gt;а возвращают их вместе с результатом своей работы. Получиться цепочка из подпрограмм.&lt;br /&gt;А "большая вызывалка" будет получать в цикле ссылки на подпрограммы и вызывать их, передавая идущие с ними аргументы.&lt;br /&gt;И так до самого конца, до пустой подпрограммы.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;sub mul(&amp;amp;\@\@) {&lt;br /&gt; my ($sub, $x, $y) = @_;&lt;br /&gt; my @r = map { $$x[$_] * $$y[$_] } 0 .. $#$x;&lt;br /&gt; return $sub, @r;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;sub minus(&amp;amp;\@\@) {&lt;br /&gt; my ($sub, $x, $y) = @_;&lt;br /&gt; my @r = map { $$x[$_] - $$y[$_] } 0 .. $#$x;&lt;br /&gt; return $sub, @r;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;sub say(&amp;amp;@) {&lt;br /&gt; my $sub = shift;&lt;br /&gt; print join(" ", @_), "\n";&lt;br /&gt; return $sub;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;sub main() {&lt;br /&gt; my @i = (1, 2, 3);&lt;br /&gt; my @j = (2, 3, 4);&lt;br /&gt; my @k = (3, 4, 5);&lt;br /&gt;&lt;br /&gt; return mul { minus { say {} @_ } @_, @k } @i, @j;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# А вот и "большая вызывалка", которая все это запускает.&lt;br /&gt;my $sub = \&amp;main;&lt;br /&gt;my @param = ();&lt;br /&gt;do {&lt;br /&gt;  ($sub, @param) = $sub-&gt;(@param);&lt;br /&gt;} while ($sub);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В вышеприведенном коде "большая вызывалка" вызывает лишь подпрограммы-клей, которые в свою очередь вызывают подпрограммы-кирпичики.&lt;br /&gt;Конечно можно сделать так, чтобы она вызывала все подпрограммы:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;return \&amp;amp;mul, sub { \&amp;amp;minus, sub { \&amp;amp;say, undef, @_ }, \@_, \@k }, \@i, \@j;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Но в этом случае, мы лишаемся магии прототипов, так что первый вариант - предпочтительней.&lt;br /&gt;&lt;br /&gt;Чувствую, что Фея будет довольна. Интересно только, зачем она меня подталкивает в этом направлении?&lt;br /&gt;Хотя, всему свое время: скоро, наверно, узнаю.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-3451870727515500893?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/3451870727515500893/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=3451870727515500893' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3451870727515500893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3451870727515500893'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/05/return_20.html' title='Сегодня без return - выворачиваем наизнанку'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-2051642932851990411</id><published>2009-05-13T09:30:00.001+03:00</published><updated>2009-05-14T08:54:23.216+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Сегодня без return</title><content type='html'>Подозрения оправдались. История продолжается, после описанных в &lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/05/blog-post.html"&gt;http://laziness-impatience-hubris.blogspot.com/2009/05/blog-post.html&lt;/a&gt; и &lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/05/2-tail-call.html"&gt;http://laziness-impatience-hubris.blogspot.com/2009/05/2-tail-call.html&lt;/a&gt;&lt;br /&gt;цветочков пошли ягодки.&lt;br /&gt;&lt;br /&gt;Итак сегодня работаем без return!&lt;br /&gt;&lt;br /&gt;В качестве примера умножим поэлементно пару векторов и отнимем третий:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (1, 2, 3) &gt;&gt;*&lt;&lt; (2, 3, 4) &gt;&gt;-&lt;&lt; (3, 4, 5)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Для этого в perl6 имеются гипероператоры - &lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/01/perl6.html"&gt;http://laziness-impatience-hubris.blogspot.com/2009/01/perl6.html&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Но сейчас разговор не о perl6, а о perl5. Вот код, который выполняет вышеупомянутые действия:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub mul(\@\@) {&lt;br /&gt;  my ($x, $y) = @_;&lt;br /&gt;  map { $$x[$_] * $$y[$_] } 0 .. $#$x;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub minus(\@\@) {&lt;br /&gt;  my ($x, $y) = @_;&lt;br /&gt;  map { $$x[$_] - $$y[$_] } 0 .. $#$x;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; my @i = (1, 2, 3);&lt;br /&gt; my @j = (2, 3, 4);&lt;br /&gt; my @k = (3, 4, 5);&lt;br /&gt; &lt;br /&gt; my @ij = mul(@i, @j);&lt;br /&gt; my @r  = minus(@ij, @k);&lt;br /&gt; print join(" ", @r), "\n";&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Хотя в этом коде return явно не прописан он присутствует.&lt;br /&gt;Обе подпрограммы возвращают результаты в виде списков.&lt;br /&gt;&lt;br /&gt;Теперь попробуем избавиться от return. Сразу говорю, что модификация передаваемого по ссылки массива, - это не наш путь.&lt;br /&gt;Не для того существует perl, чтобы на нем писать с C стиле.&lt;br /&gt;&lt;br /&gt;Мы пойдем другим путем, похожем на стиль передачи продолжений.&lt;br /&gt;Подпрограммы не будут возвращать результат, а будет вызывать другие, передавая им результат в качества аргументов,&lt;br /&gt;например, вот так:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; mul(@i, @j, sub { minus(@_, @k, sub { say(@_, sub {}) }) });&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Или вот так, чтобы было удобней работать с параметрами подпрограмм,&lt;br /&gt;ссылку на подпрограмму сделаем первой, а не последней среди передаваемых параметров:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; mul(sub { minus(sub { say( sub {}, @_) }, @_, @k) }, @i, @j);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Что, при использовании магии прототипов, можно записать следующим образом:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; mul { minus { say {} @_ } @_, @k } @i, @j;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Соответственно, подпрограммы в качестве первого параметра принимают ссылку на подпрограмму,&lt;br /&gt;которую и вызывают, передав ей результат своей работы:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub mul(&amp;\@\@) {&lt;br /&gt;  my ($sub, $x, $y) = @_;&lt;br /&gt; my @r = map { $$x[$_] * $$y[$_] } 0 .. $#$x;&lt;br /&gt; $sub-&gt;(@r);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub minus(&amp;\@\@) {&lt;br /&gt;  my ($sub, $x, $y) = @_;&lt;br /&gt;  my @r = map { $$x[$_] - $$y[$_] } 0 .. $#$x;&lt;br /&gt; $sub-&gt;(@r);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; sub say(&amp;@) {&lt;br /&gt;  my $sub = shift;&lt;br /&gt;  print join(" ", @_), "\n";&lt;br /&gt; $sub-&gt;();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; my @i = (1, 2, 3);&lt;br /&gt; my @j = (2, 3, 4);&lt;br /&gt; my @k = (3, 4, 5);&lt;br /&gt;&lt;br /&gt; mul { minus { say {} @_ } @_, @k } @i, @j;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Вот и все. Поставленная задача выполнена. Теперь немного порассуждаем.&lt;br /&gt;&lt;br /&gt;Подпрограммы в вышеприведенном коде можно разбить на два типа:&lt;br /&gt;1) подпрограммы-кирпичики (mul, minus, say);&lt;br /&gt;2) подпрограммы-клей (анонимные подпрограммы).&lt;br /&gt;&lt;br /&gt;Подпрограммы-клей связывают подпрограммы-кирпичики.&lt;br /&gt;Подпрограммы-клей содержат основную логику программы, а подпрограммы-кирпичики - это повторно используемый код.&lt;br /&gt;&lt;br /&gt;Этот стиль очень любят использовать там, где подпрограммы являются сущностями высшего порядка.&lt;br /&gt;В perl также для него есть своя ниша, но об этом позже.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-2051642932851990411?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/2051642932851990411/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=2051642932851990411' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2051642932851990411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/2051642932851990411'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/05/return.html' title='Сегодня без return'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-6812781444191077882</id><published>2009-05-07T08:53:00.005+03:00</published><updated>2009-05-13T09:07:23.334+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Сегодня без циклов, часть 2 - tail call оптимизация</title><content type='html'>Продолжение истории, начало - &lt;a href="http://laziness-impatience-hubris.blogspot.com/2009/05/blog-post.html"&gt;http://laziness-impatience-hubris.blogspot.com/2009/05/blog-post.html&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Сегодня я не был разбужен мыслью: "сегодня без ...".&lt;br /&gt;Сегодня меня разбудило порицание: "а-я-яй, рекурсия..., а где же tail call оптимизация?!"&lt;br /&gt;&lt;br /&gt;- Отстань, - отвечаю я: в perl нет поддержки tail call оптимизации".&lt;br /&gt;- В perl5 - да, но в perl6 будет!&lt;br /&gt;- Ладно, вот вариант с оптимизаций:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my @vector = 1 .. 5;&lt;br /&gt; &lt;br /&gt; sub _sum {&lt;br /&gt;  my ($s, $h, @t) = @_;&lt;br /&gt;  @t ? _sum($s + $h, @t) : $s + $h;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub sum { _sum(0, @_) }&lt;br /&gt; &lt;br /&gt; print sum(@vector), "\n";&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Краткое пояснение к коду: tail call оптимизация используется когда функция завершается вызовом другой.&lt;br /&gt;&lt;br /&gt;Сильно подозреваю, что завтра будет продолжение! :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-6812781444191077882?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/6812781444191077882/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=6812781444191077882' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/6812781444191077882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/6812781444191077882'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/05/2-tail-call.html' title='Сегодня без циклов, часть 2 - tail call оптимизация'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-3754045710378711855</id><published>2009-05-06T10:16:00.002+03:00</published><updated>2009-05-13T09:07:02.970+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Сегодня без циклов</title><content type='html'>Сегодня мое пробуждение от сладкого сна было грубо и бесцеремонно нарушено невесть откуда прилетевшей мыслью: "сегодня без циклов"!&lt;br /&gt;&lt;br /&gt;"Без циклов, так без циклов", - в ответ подумал я.&lt;br /&gt;&lt;br /&gt;В качестве примера рассмотрим сложение элементов массива.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my @vector = 1 .. 5;&lt;br /&gt; &lt;br /&gt; # Вариант с циклом.&lt;br /&gt; {&lt;br /&gt;  my $sum = 0;&lt;br /&gt;  $sum += $_ for @vector;&lt;br /&gt;  print $sum, "\n";&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; # Вариант без цикла.&lt;br /&gt; {&lt;br /&gt;  sub sum {&lt;br /&gt;   my ($h, @t) = @_;&lt;br /&gt;   @t ? $h + sum(@t) : $h;&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  print sum(@vector), "\n";&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Вот так просто можно обойтись без циклов, используя рекурсию.&lt;br /&gt;&lt;br /&gt;Интересно, а вдруг и завтра я буду разбужен мыслью: "сегодня без ...", и это "без ..." будет намного сложней?&lt;br /&gt;Но, как говориться, утро вечера мудренее.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-3754045710378711855?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/3754045710378711855/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=3754045710378711855' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3754045710378711855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3754045710378711855'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/05/blog-post.html' title='Сегодня без циклов'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-7030947149315681291</id><published>2009-01-15T09:56:00.005+02:00</published><updated>2009-01-15T10:40:38.162+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='J'/><title type='text'>Гипер-, редакшн- и кроссоператоры в Perl6</title><content type='html'>Perl насквозь пронизан магией. Возможно, из-за этого адепты языков программирования, лишенных волшебных свойств, так ненавидят его. Они просто боятся и не умеют обращаться с магией. Хотя, что тут уметь! Магия, как и все, подчиняется простым законам природы.&lt;br /&gt;&lt;br /&gt;Еще в 1748 году М. В. Ломоносов открыл закон сохранения магии. Или все-таки вещества? - да какая разница! Этот закон гласит: "Так, ежели где убудет несколько магии, то умножится в другом месте".&lt;br /&gt;&lt;br /&gt;В соответствии с законом сохранения магии в Perl6, когда многие вещи стали простыми, появились очень интересные новые возможности. Среди нововведений - гипероператоры, reduction и cross операторы. Это операторы предназначены для работы со списками. Кстати, подобные им операторы изначально имеются в магических языках семейства APL.&lt;br /&gt;&lt;br /&gt;Наличие таких нововведений в Perl6 позволяет выражать мысли более компактно и ясно. Рассмотрим некоторые примеры и сравним их с примерами на языке J (&lt;a href="http://jsoftware.com"&gt;http://jsoftware.com&lt;/a&gt;), который является потомком языка APL. Для простоты в нижеприведенных примерах код обозначен отступом вправо, а результат работы - отступом влево.&lt;br /&gt;&lt;br /&gt;Примеры выполнены при помощи Rakudo (компилятор Perl 6, основанный на Parrot) Rakudo - сокращение от японского Rakuda-do, что означает "Путь верблюда".&lt;br /&gt;&lt;br /&gt;Перед основыми примерами создаем списки (массивы, вектора):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;     Perl                  |     J&lt;br /&gt; ------------------------------------------------&lt;br /&gt;     @x = (1 .. 3)         |     x=. 1 2 3&lt;br /&gt;     @y = (4 .. 6)         |     y=. 4 5 6&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В J списки создаем вручную, чтобы не забегать вперед.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Гипероператоры&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Гипероператоры производят операции над списками поэлементно. Смотрите &lt;a href="http://perlcabal.org/syn/S03.html#Hyper_operators"&gt;http://perlcabal.org/syn/S03.html#Hyper_operators&lt;/a&gt;. Сложение двух списков при помощи гипероператора и прибавление к списку числа:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;     Perl                  |     J&lt;br /&gt; ------------------------------------------------&lt;br /&gt;     @x &gt;&gt;+&lt;&lt; @y           |  x + y&lt;br /&gt; 5, 7, 9                   | 5 7 9&lt;br /&gt;     @x &gt;&gt;+&gt;&gt; 3            |     x + 3&lt;br /&gt; 4, 5, 6                   | 4 5 6&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В J оператор является аналогом Perl гипероператора, что не удивительно, ведь APL - язык векторных вычислений.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Reduction операторы&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Эти операторы работают не с единичными элементами списка, а с учетом результата действий над предыдущими элементами. &lt;a href="http://perlcabal.org/syn/S03.html#Reduction_operators"&gt;http://perlcabal.org/syn/S03.html#Reduction_operators&lt;/a&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;     Perl                  |     J&lt;br /&gt; ------------------------------------------------&lt;br /&gt;     [+] @x                |    +/ x&lt;br /&gt; 6                         | 6&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Для достижения аналогичного результата в J оператор модифицируется наречием "поэлементно".&lt;br /&gt;&lt;br /&gt;Следующий пример еще не работает в Rakudo (parrot revision 35576). Отличие этого примера от предыдущего в том, что сумма считаеться не для всего списка, а для каждой его части:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;     Perl                  |     J&lt;br /&gt; ------------------------------------------------&lt;br /&gt;     [\+] @x               |     +/\ x&lt;br /&gt; 1, 3, 6                   | 1 3 6&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В J это делается при помощи наречия "префиксно".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Cross операторы&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Эти операторы производят действие над каждой комбинацией элементов списков.&lt;br /&gt;&lt;a href="http://perlcabal.org/syn/S03.html#Cross_operators"&gt;http://perlcabal.org/syn/S03.html#Cross_operators&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Сделаем фрагмент таблицы умножения:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;     Perl                       |     J&lt;br /&gt; ------------------------------------------------&lt;br /&gt;     @x X*X @y                  |     x */ y&lt;br /&gt; 4, 5, 6, 8, 10, 12, 12, 15, 18 |  4  5  6&lt;br /&gt;                                |  8 10 12&lt;br /&gt;                                | 12 15 18&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В J оператор модифицируется наречием "таблично". Отличие Perl от J в том, что в J сразу создается матрица, а Perl придется список преобразовать в таблицу. Просто у Perl и J разное распределение магии.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Выводы&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Как видим, Perl получил в свой арсенал мощные возможности для работы со списками, Нельзя сказать, что они соизмеримы с возможностями векторных языков, но их вполне хватает для "бытовых" нужд.&lt;br /&gt;&lt;br /&gt;Для "профессиональных" векторных вычислений рекомендуется использовать Perl Data Language (&lt;a href="http://pdl.perl.org"&gt;http://pdl.perl.org&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-7030947149315681291?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/7030947149315681291/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=7030947149315681291' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7030947149315681291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7030947149315681291'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2009/01/perl6.html' title='Гипер-, редакшн- и кроссоператоры в Perl6'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-3470487939626934642</id><published>2008-12-26T09:24:00.005+02:00</published><updated>2009-08-27T13:06:47.541+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>"Закрытые объекты" в Perl5 и Perl6</title><content type='html'>&lt;span style="font-weight:bold;"&gt;Введение&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Как вы знаете на геральдическом гербе Perl красуется надпись TMTOWTDI (There's More Than One Way To Do It - есть более одного способа сделать это). Но чтобы использовать один из способов, необходимо обладать свободой - свободой выбора. Идея свободы выбора насквозь пронизывает Perl. Кстати, как и христианство.&lt;br /&gt;&lt;br /&gt;Используя Perl, вы полностью свободны! Свободны и в том, насколько быть свободным и открытым.&lt;br /&gt;&lt;br /&gt;Обычно и вас не ограничивают. Просто там, куда не следует лезть без особой на то нужды, вывешивают табличку с предупреждающей надписью. Некоторые таблички являются табличками по умолчанию и  продиктованы здравым смыслом. Конечно вам никто не запрещает проигнорировать предупреждение, но тогда только вы сами будете отвечать за все последствия. Вспомните, что произошло с Адамом и Евой, когда они съели то злополучное яблоко.&lt;br /&gt;&lt;br /&gt;Но соблазн велик. К тому-же нарушитель попытается повесить всех собак на других. Как попытался это сделать в свое время Адам, сказав: "Это все Ева, а ведь ТЫ дал мне ее в жены". Так вот, чтобы такие Адамы не лезли куда ни попадя, можно ограничить свободу при использовании вашего модуля.&lt;br /&gt;&lt;br /&gt;Если в качеств Эдемского сада рассмотреть объекты, то Адам может получить или изменить свойства класса в обход методов доступа, вызвать приватный метод или даже посягнуть на самое святое - изменить родительский класс.&lt;br /&gt;&lt;br /&gt;При разработке Perl6 учли все это и предоставили возможность оградить Адама от самого себя: у объектов Perl6 имеются защищенный атрибуты, методы, а также дружественные методы.&lt;br /&gt;&lt;br /&gt;А как же Perl5?! Perl - гибкий язык, поэтому можно и в Perl5 предпринять кое-что для защиты объектов. Одним из самых популярных способов сделать это является "выворачивание объекта наизнанку" :-).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Inside-out объекты&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Классические Perl объекты - это просто структуры данных, благословленные быть объектами при помощи функции bless. Методами объекта являются подпрограммы пакета, который привязан к объекту при благословении. Благословить быть объектом можно ссылку как на скаляр, так и на массив, хеш или замыкание.&lt;br /&gt;&lt;br /&gt;Наиболее часто используется хеш. Атрибуты такого объекта являются ключами хеша, соответственно к значениям атрибутов можно обратиться как обращаются к значениям ключей хеша. Например, для объекта:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; package Foo;&lt;br /&gt; &lt;br /&gt; sub new {&lt;br /&gt;  my $self = { name =&gt; "My name" };&lt;br /&gt;  bless $self;&lt;br /&gt;  return $self;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub name {&lt;br /&gt;  my $self = shift;&lt;br /&gt;  return $$self{name};&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; 1;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Можно получить значения foo в обход одноименного метода:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my $foo = Foo-&gt;new();&lt;br /&gt; print $foo-&gt;{name};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Чтобы предотвратить это, необходимо запрятать от внешнего взора значение foo. Вопрос только как и где?! Например, в лексической области пакета. То есть объект перестает быть совокупностью данных с привязанными к нему процедурами, он становиться некоторым идентификатором с привязанными к нему процедурами, которые в свою очередь по этому идентификатору знают о местоположении данных.&lt;br /&gt;&lt;br /&gt;Такие объекты называются Inside-out объектами. Кстати, в стандартной поставе Perl 5.10 имеется модуль Hash::Util::FieldHash, предназначенный для создания таких объектов.&lt;br /&gt;&lt;br /&gt;Рассмотрим пример Inside-out объекта:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; package Foo;&lt;br /&gt; &lt;br /&gt; use Scalar::Util 'refaddr';&lt;br /&gt; my %name;&lt;br /&gt; sub new {&lt;br /&gt;  my $self = bless \do {my $anon_scalar}, "Foo";&lt;br /&gt;  $name{ refaddr $self } = "My name";&lt;br /&gt;  return $self;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub name {&lt;br /&gt;  my $self = shift;&lt;br /&gt;   return $name{ refaddr $self };&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub DESTROY {&lt;br /&gt;     my $self = shift;&lt;br /&gt;     delete $name{ refaddr $self };&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; 1;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Этот объект функционально полностью идентичен первому, и работа с ним осуществляется как с обычными объектами:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my $foo = Foo-&gt;new();&lt;br /&gt; print $foo-&gt;name();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;А вот получить значение name в обход метода доступа невозможно. Строка print $foo-&gt;{name}; приведет к ошибке: "Not a HASH reference".&lt;br /&gt;&lt;br /&gt;Чтобы облегчить создание Inside-out объектов и, не дай Бог, не забыть о DESTROY существует множество модулей-конструкторов, среди которых особое место занимают Class::InsideOut и Object::InsideOut. Объекты, созданные при помощи их, можно клонировать, сериализовать и&lt;br /&gt;использовать под mod_perl.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;О наследовании&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;При всех своих преимуществах Inside-out объекты не лишены недостатков. А  именно, при их использовании возникают определенные трудности с наследованием.&lt;br /&gt;&lt;br /&gt;Вообще-то наследование и закрытость - это взаимоисключающие вещи. И приходиться чем-то жертвовать.&lt;br /&gt;&lt;br /&gt;Например, объекты, созданные при помощи Class::InsideOut могут наследовать другие, но от них наследоваться невозможно. А при использовании Object::InsideOut, наследование реализовано как делегирование.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Маленький хак&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Закрытость - закрытостью, но насколько это закрытость сильна?!&lt;br /&gt;&lt;br /&gt;Попробуем добраться до приватных атрибутов Inside-out объекта, внедрив в модуль объекта маленькую подпрограмму-шпиона по имени hook:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use Scalar::Util 'refaddr';&lt;br /&gt; &lt;br /&gt; # Внедряем метод доступа.&lt;br /&gt; sub Foo::hook {&lt;br /&gt;  my $self = shift;&lt;br /&gt;   return $name{ refaddr $self };&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; my $foo = Foo-&gt;new();&lt;br /&gt; print $foo-&gt;hook();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;И, вуаля, все тайное становиться явным!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;О Perl6&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Если внимательно посмотреть на вышеприведенный хак, то можно увидеть что-то очень знакомое... Да это же аналог роли из Perl6!&lt;br /&gt;&lt;br /&gt;Роль добавляет к объектам как методы, так и атрибуты. Добавляет либо на этапе компиляции, либо на этапе исполнения.&lt;br /&gt;&lt;br /&gt;По сути роли, кроме всего прочего, открывают то, что cкрыто за приватными методами и атрибутами!&lt;br /&gt;&lt;br /&gt;А когда роль добавляется на этапе исполнения, это привносит в class-based объекты черты prototype-based. Если пойти еще дальше: то там, где есть роли, в классическом наследовании вообще нет необходимости.&lt;br /&gt;&lt;br /&gt;Но prototype-based стиль не приемлет закрытости. С другой стороны, как говорит, Stevan Little, один из основных разработчиков Moose, нужда в private методах и атрибутах - это социальная проблема и должна решаться именованием, документированием и хорошей поркой.  &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Подводя итоги&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;В perl можно сделать закрытые объекты. Но такие объекты в первую очередь предназначены для защиты от случайных изменений.&lt;br /&gt;&lt;br /&gt;Если нужно, то "закрытой" объект можно "открыть". Кончено, кроме объекта, построенного на замыкании, но такой объект является вещью в себе - он не может ни наследовать, ни наследоваться.&lt;br /&gt;&lt;br /&gt;Perl в воем развитии продолжает движение навстречу людям, не знакомым с ним. Но Perl6 остается perl, он лишь принимает формы привычные многим.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-3470487939626934642?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/3470487939626934642/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=3470487939626934642' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3470487939626934642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3470487939626934642'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/12/perl5-perl6.html' title='&quot;Закрытые объекты&quot; в Perl5 и Perl6'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-35689505691941571</id><published>2008-11-26T11:31:00.000+02:00</published><updated>2008-11-26T13:07:19.267+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Многоликие объекты</title><content type='html'>Иногда Perl обвиняют что у него "неправильные объекты". В ответ так и хочется спросить: "у Вас мания "объектно-ориентированного величия" или вы любитель "священных войн"? Кто сказал, что объекты должны быть основаны только на классах?&lt;br /&gt;&lt;br /&gt;Вон в List вообще нет "классических" объектов, зато есть CLOS, которая заткнет за пояс многие объектно-ориентированные языки программирования. А в perl, если не нравятся perl5 объекты можно использовать все что угодно, например:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; Moose - A postmodern object system for Perl 5.&lt;br /&gt; Mouse - Moose minus the antlers&lt;br /&gt; Class::Prototyped - Fast prototype-based OO programming in Perl&lt;br /&gt; Class::Closure - Encapsulated, declarative class style&lt;br /&gt; Class::Spiffy - Spiffy Framework with No Source Filtering&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;А сколько разных генераторов классов есть.&lt;br /&gt;&lt;br /&gt;Уверен, что и к perl6 будет претензии: дескать зачем так все сложно, зачем эти &lt;br /&gt;role, если можно все можно сделать наследованием?&lt;br /&gt;&lt;br /&gt;Ради бога! Делайте, никто не связывает руки. Perl позволяет многое, почти все. Можно даже использовать нижеследующие:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use strict;&lt;br /&gt; use warnings;&lt;br /&gt; &lt;br /&gt; use Clone qw(clone);&lt;br /&gt; &lt;br /&gt; sub new {&lt;br /&gt;  my $protos  = ref $_[0] eq "ARRAY" ? shift || [] : [];&lt;br /&gt;  my $data    = shift || {};&lt;br /&gt;  my $methods = shift || {};&lt;br /&gt; &lt;br /&gt;  my $self;&lt;br /&gt;  return $self = sub {&lt;br /&gt;   my $method = shift;&lt;br /&gt; &lt;br /&gt;   if ($method eq "clone") {&lt;br /&gt;    return new(clone($protos), clone($data), clone($methods));&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   if ($method eq "add_slot") {&lt;br /&gt;    %{$methods} = (%{$methods}, @_);&lt;br /&gt;    return $self;&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   if ($method eq "get_slot") {&lt;br /&gt;    return $$methods{$_[0]};&lt;br /&gt;   }&lt;br /&gt;   if ($method eq "slot_names") {&lt;br /&gt;    return keys %$methods;&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   if (my $sub = $$methods{$method}) {&lt;br /&gt;    return $sub-&gt;($self, $data, @_);&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   foreach (@$protos) {&lt;br /&gt;    if (my $sub = $_-&gt;("get_slot", $method)) {&lt;br /&gt;     return $sub-&gt;($self, $data, @_);&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; # Пример использования.&lt;br /&gt; &lt;br /&gt; use Test::More tests =&gt; 12;&lt;br /&gt; &lt;br /&gt; my $c1 = new(&lt;br /&gt;   { foo =&gt; 3 },&lt;br /&gt;   {&lt;br /&gt;    foo =&gt; sub { my ($self, $data) = @_;&lt;br /&gt;     return $$data{foo};&lt;br /&gt;    },&lt;br /&gt;    add =&gt; sub {&lt;br /&gt;     my ($self, $data, $delta) = @_;&lt;br /&gt;     $$data{foo} += $delta;&lt;br /&gt;     return $self;&lt;br /&gt;    },&lt;br /&gt;   },&lt;br /&gt;  );&lt;br /&gt; &lt;br /&gt; is($c1-&gt;("foo"), 3, "c1");&lt;br /&gt; &lt;br /&gt; my $c2 = $c1-&gt;("clone");&lt;br /&gt; is($c2-&gt;("foo"), 3, "c2");&lt;br /&gt; &lt;br /&gt; ok($c1-&gt;("add", 2), "c1: add 2");&lt;br /&gt; &lt;br /&gt; is($c1-&gt;("foo"), 5, "c1");&lt;br /&gt; is($c2-&gt;("foo"), 3, "c2");&lt;br /&gt; &lt;br /&gt; is($c1-&gt;("add", 3)-&gt;("foo"), 8, "c1: add 3 and return");&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; $c1-&gt;("add_slot", multiply =&gt; sub {&lt;br /&gt;   my ($self, $data, $y) = @_;&lt;br /&gt;   $$data{foo} *= $y;&lt;br /&gt;   return $self;&lt;br /&gt;  });&lt;br /&gt; &lt;br /&gt; ok($c1-&gt;("multiply", 2), "multiply");&lt;br /&gt; is($c1-&gt;("foo"), 16, "multiply, get");&lt;br /&gt; &lt;br /&gt; ok(ref $c1-&gt;("get_slot", "multiply") eq "CODE", "get_slot");&lt;br /&gt; &lt;br /&gt; is(join(" ", sort $c1-&gt;("slot_names")), "add foo multiply", "slot_names");&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt; my $c3 = new(&lt;br /&gt;   [$c1], # inheritance&lt;br /&gt;   { foo =&gt; 3 },&lt;br /&gt;   {&lt;br /&gt;    baz =&gt; sub { my ($self, $data) = @_;&lt;br /&gt;     return join " ", "baz", $$data{foo};&lt;br /&gt;    },&lt;br /&gt;   }&lt;br /&gt;  );&lt;br /&gt; &lt;br /&gt; is($c3-&gt;("baz"), "baz 3", "c3, baz");&lt;br /&gt; is($c3-&gt;("foo"), 3, "c3, foo");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Так что, если нечто отличается от привычного, не следует стразу обвинять это нечто в "неправильности", может просто мы столкнулись с тем, что является лишь немного другим. &lt;span style="font-weight:bold;"&gt;Другим, а не неправильным!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-35689505691941571?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/35689505691941571/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=35689505691941571' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/35689505691941571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/35689505691941571'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/11/blog-post.html' title='Многоликие объекты'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-817199815800244922</id><published>2008-11-13T13:56:00.001+02:00</published><updated>2008-11-13T13:56:30.195+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Использование Perl Data Language для расчета Page Rank</title><content type='html'>В среде SEO (search engine optimization) долгое время ходила, а может и сейчас продолжает ходить, легенда о том, что добавление ссылки на страницу приводит к "утеканию" с нее Page Rank. Другая легенда гласит, что можно так расставить внутренние ссылки на сайте, что Google Page Rank сайта подскочит до небес.&lt;br /&gt;&lt;br /&gt;Вообще-то SEO мне чет-то нравятся: из забавно слушать сразу после обеду, когда ничего делать не хочется, разве что послушать какую-то забавную историю или легенду.&lt;br /&gt;&lt;br /&gt;Так вот о Page Rank. Как-то во время одной беседы с SEO, слушая легенду о Page Rank, вспомнил о передаче "Разрушители легенд", которая шла по каналу "Дискавери", и подумал: "а не разрушить ли в среде знакомых SEO некоторые легенды о Page Rank?"&lt;br /&gt;&lt;br /&gt;Перед тем как делать скрипт расчета локального Page Rank, заглянул на CPAN. Оказалось, что там имеется модуль Algorithm::PageRank. Но при ближайшем рассмотрении оказалось, что в этом модуле используется какие-то другая формула, а не&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;PR(A) = (1-d) + d (PR(T1)/C(T1) + ... + PR(Tn)/C(Tn))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(&lt;a href="http://infolab.stanford.edu/%7Ebackrub/google.html"&gt;http://infolab.stanford.edu/~backrub/google.html&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;Пришлось немного подправить модуль. Во время правки выяснилось, что модуль использует PDL (Perl Data Language, &lt;a href="http://pdl.perl.org/"&gt;http://pdl.perl.org&lt;/a&gt;), но не слишком оптимально.&lt;br /&gt;&lt;br /&gt;Кстати, при первом знакомстве с PDL, я столкнулся с подобным нюансом. Объекты pdl можно создавать таким способом:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;my $foo = pdl(1 .. n);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Это вектор со значениями от 1 до n. Создавая таким образом объекты, я в один прекрасным момент столкнулся с нехваткой памяти. Расследование того, почему PDL так требователен к памяти, показало, что PDL был напрасно обвинен. В вышеприведенном примере сначала создается perl массив (!), а PDL затем достаются лишь крохи памяти, которые не были использованы perl для создания гигантского массива.&lt;br /&gt;&lt;br /&gt;Но вернемся к Page Rank. Поскольку алгоритм расчета ранга прост - решил написать пару строк самостоятельно. Тем более если посмотреть на формулу со стороны матричной алгебры:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;R = (1 - d) + d * M * R,&lt;br /&gt;&lt;br /&gt;где: R - вертикальный вектор рангов страниц,&lt;br /&gt;     M - матрица взвешенных ссылок.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Матрица взвешенных ссылок получаемся посредством деления элементов матрица&lt;br /&gt;ссылок на количество ссылок со ссылающихся станиц.&lt;br /&gt;&lt;br /&gt;Ну что ж, приступим. Будем использовать итерационный алгоритм расчета. Первым делом считываем из файла связей информацию, о том какие страницы на какие ссылаются. Файл содержит два столбика, разделенные пробелом.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;use PDL;&lt;br /&gt;my ($from, $to) = rcols 'links.dat';&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Затем определяем максимальной значение, которыми закодированы конкретные страницы:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;my $size = 1 + maximum(pdl(maximum($from), maximum($to)));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Это необходимо для создания матрицы связей:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(my $M = zeroes(double, $size, $size))-&gt;index2d($to, $from) .= 1;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Функция zeroes создает матрицу, заполненную нулями, а index2d на основе информации от ссылках заменяет значения ее соответствующих элементов единицами.&lt;br /&gt;&lt;br /&gt;Из матрицы связей получаем взвешенную матрицу:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$M-&gt;inplace-&gt;divide($M-&gt;sumover-&gt;transpose, 0);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;inplace говорит, что не будет копирования, а - замена значений по месту.&lt;br /&gt;&lt;br /&gt;На следующем этапе создаем вектор первоначальных значений ранга и коэффициент затухания:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;my $R = ones(double, $size);&lt;br /&gt;my $d = 0.85;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Затем за 30 итераций рассчитываем ранг:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;for (my $i = 0; $i&lt;=30; $i++) {   $R = 1 - $d + $d * $R x $M;  } &lt;/pre&gt;&lt;br /&gt;Конечно, в реальном скрипте число итераций определяется автоматически на основе требуемого значения погрешности расчета.&lt;br /&gt;&lt;br /&gt;Сохраняем результаты расчета в файл r.dat при помощи следующего кода:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;wcols sequence($size-&gt;sclr), $R-&gt;slice(',(0)'), 'r.dat';&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ну вот и все. Надеюсь, я смог заинтересовать вас познакомиться c Perl Data Language.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-817199815800244922?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/817199815800244922/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=817199815800244922' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/817199815800244922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/817199815800244922'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/11/perl-data-language-page-rank.html' title='Использование Perl Data Language для расчета Page Rank'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-6122352644859550526</id><published>2008-10-22T17:14:00.002+03:00</published><updated>2008-10-22T17:19:18.305+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Background execution of subroutines in child processes</title><content type='html'>При работе с распределенной базой данных иногда возникает необходимость выполнить один и тот-же запрос на каждом сегменте базы. По-очереди - долго, хочется параллельно.&lt;br /&gt;&lt;br /&gt;Для решения этой и подобных задач написал маленький модуль &lt;a href="http://search.cpan.org/~kni/BGS-0.01/"&gt;BGS - Background execution of subroutines in child processes&lt;/a&gt;. Модуль позволяет упростить выполнение подпрограмм в дочерних процессах, ожидание их завершения и возврат результатов работы подпрограмм из дочерних процессов в основной.&lt;br /&gt;&lt;br /&gt;Пример использования:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use BGS;&lt;br /&gt; &lt;br /&gt; my @foo;&lt;br /&gt; &lt;br /&gt; foreach my $i (1 .. 2) {&lt;br /&gt; &lt;br /&gt;   bgs_call {&lt;br /&gt;     # child process&lt;br /&gt;     return "Start $i";&lt;br /&gt;   }&lt;br /&gt; &lt;br /&gt;   bgs_back {&lt;br /&gt;     # callback subroutine&lt;br /&gt;     my $r = shift;&lt;br /&gt;     push @foo, "End $i. Result: '$r'.\n";&lt;br /&gt;   };&lt;br /&gt; &lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; bgs_wait();&lt;br /&gt; &lt;br /&gt; print foreach @foo;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Код, который будет выполняться в дочерних процессах, помещается в блок bgs_call.&lt;br /&gt;&lt;br /&gt;Код, который выполниться в основном процессе, при завершении bgs_call, находиться в блоке bgs_back. Ответ bgs_call (скаляр или ссылка, но не список) передается в bgs_back в качестве аргумента.&lt;br /&gt;&lt;br /&gt;Механизм запускается командой bgs_wait. Не забудьте перед созданием дочерних процессов, закрыть все соединения к базе. Почему это желательно сделать, смотрите в заметке &lt;a href="http://laziness-impatience-hubris.blogspot.com/2007/12/perl-fork.html"&gt;"Отцы и дети или perl, fork и деструкторы"&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Внимание, код, который будет вызываться из bgs_call, на данный момент ничего не должен печатать на STDOUT! Надо, все таки, собраться и устранить этот недостаток. А может еще добавить timeout ожидания?&lt;br /&gt;&lt;br /&gt;Кстати, на CPAN недавно обнаружил модуль Parallel::SubFork с похожим функционалом. Судя по датам BGS и Parallel::SubFork писались приблизительно в одно время. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-6122352644859550526?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/6122352644859550526/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=6122352644859550526' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/6122352644859550526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/6122352644859550526'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/10/background-execution-of-subroutines-in.html' title='Background execution of subroutines in child processes'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-7709279015774872377</id><published>2008-10-21T14:11:00.006+03:00</published><updated>2008-10-22T17:24:17.673+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Cooking Plain Old Documentation</title><content type='html'>Недокументированный код - это, обычно, одноразовый код.&lt;br /&gt;А плохая документация - хуже, чем ее отсутствие.&lt;br /&gt;Следовательно, надо писать хорошую документацию.&lt;br /&gt;А хорошую документацию хочется читать в хороших условиях.&lt;br /&gt;&lt;br /&gt;Я, например, предпочитаю читать не с экрана монитора, а с бумажной копии, сидя в уютном кресле с чашечкой ароматного зеленого чая.&lt;br /&gt;&lt;br /&gt;Документацию пишу в Plain Old Documentation.&lt;br /&gt;Конечно, если необходимы математические формулы или графика, то привлекаю более мощные средства, но сейчас разговор не о них. Кстати, не забывайте о podchecker, а то некоторые трансляторы с POD слишком снисходительны.&lt;br /&gt;&lt;br /&gt;Но вернемся к подготовке POD к печати.&lt;br /&gt;Под Windows самым простым способом является преобразование POD в HTML и печать его из под MS Office. А чтобы документ был более красивым, то можно использовать свой шаблон со стилями.&lt;br /&gt;&lt;br /&gt;Под UNIX, как все знают, MS Office нет :-), а Open Office тогда еще не было.&lt;br /&gt;Да и изучать Open Office нет желания, так как считаю не рациональным знать и MS Office, и Open Office, тем более, что есть альтернативы. Например, pod2man или pod2latex.&lt;br /&gt;&lt;br /&gt;Вариант с man и groff мне как-то не пришелся по душе, поэтому я даже не пытался его использовать. А вот вариант с LaTeX применял, но все таки ставить TeX систему ради одного POD - это, по моему, перебор, тем более, что есть крошка lout.&lt;br /&gt;&lt;br /&gt;Lout - система форматирования текста, подобная TeX и производящая PostScript файл.&lt;br /&gt;http://lout.wiki.sourceforge.net В lout входит также программа prg2lout, предназначенная для трансляции исходников в lout разметку. Среди поддерживаемых языков имеется Perl и POD.&lt;br /&gt;&lt;br /&gt;Например, чтобы распечатать документацию по модулю Foo, я набираю следующие команды:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; podselect Foo.pm &gt; Foo.pod&lt;br /&gt; prg2lout -l pod -n Foo.pod | lout -s | ps2pdf - &gt; Foo.pdf&lt;br /&gt; lpr Foo.pdf&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Кончено, я это делаю не вручную, а при помощи make (кроме вызова lpr, разумеется).&lt;br /&gt;&lt;br /&gt;Но листы формата A4 иногда не очень мне нравятся...&lt;br /&gt;Какой я все таки бываю капризным: "хочу книжечку читать и точка!"&lt;br /&gt;&lt;br /&gt;В таком случаете, я использую вот такой конвейер команд:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; prg2lout -l pod -n Foo.pod | lout -s | psbook | psnup -2 | ps2pdf - &gt; Foo.pdf&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Несколько сгибов, две скрепки - и у меня имеется красивая брошюра формата А5!&lt;br /&gt;Осталось только сделать чай. :-)&lt;br /&gt;&lt;br /&gt;А как вы "готовите" POD?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;P.S.&lt;br /&gt;Когда необходимо сделать документацию в виде набора HTML документов с перекрестными ссылками,&lt;br /&gt;более всех понравился мне модуль Pod::Simple::HTML. Его просто использовать для пакетной обработки, создания индекса и кастомизации.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-7709279015774872377?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/7709279015774872377/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=7709279015774872377' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7709279015774872377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/7709279015774872377'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/10/cooking-plain-old-documentation.html' title='Cooking Plain Old Documentation'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-8480406749449617682</id><published>2008-10-13T16:33:00.003+03:00</published><updated>2008-10-15T09:51:29.467+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl: Асинхронный конвейер HTTP клиентов</title><content type='html'>Как-то давным давно почувствовал я на работе запах дыма. Думал - пожар, но выглянув в коридор, увидел, что дым не так уж и велик, и валит из офиса SEO (search engine optimization).&lt;br /&gt;&lt;br /&gt;Хотя было вернуться к себе на рабочие место, но природное любопытство пересилило и я решил пойти посмотреть, что твориться у оптимизаторов. Оказалось, все просто - на экранах мельтешили окна, все были ужасно заняты, а дым шел от клавиатур - плавилась пластмасса от такой нагрузки!&lt;br /&gt;&lt;br /&gt;Когда мне наконец-то удалось привлечь к себе внимание, выяснил, что для какого-то исследования оптимизатором надо было закачать несколько десятков тысяч web страниц. Что за исследования и где они взяли этот список url я уточнять не стал, просто пожелал им плодотворной работы, а сам запомнил где лежит этот список url.&lt;br /&gt;&lt;br /&gt;Да, придется ликвидировать причину дымa, - подумал я на обратной дороге. Нет, оптимизаторов я ликвидировать не собирался, просто решил им сделать скриптик, которых закачает все эти странички, тем более, что у меня уже был опыт работы с модулем LWP::Parallel::UserAgent.&lt;br /&gt;&lt;br /&gt;Задача сводилась к тому, чтобы по мере обработки читать с файла новые url, асинхронно запрашивать страницы и записывать HTTP ответы в файлы. Конечно можно было все сделать последовательно, но уж больно много времени потребовалось бы на это.&lt;br /&gt;&lt;br /&gt;Как оказалось, для организации такого конвейера более подходит модуль HTTP::Async, а не LWP::Parallel::UserAgent.&lt;br /&gt;&lt;br /&gt;Вот примерный код, который использовался для этого (работа с файлами опущена):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use HTTP::Message 1.57;&lt;br /&gt; use HTTP::Request;&lt;br /&gt; use HTTP::Async;&lt;br /&gt; &lt;br /&gt; my @urls    = (&lt;br /&gt;  'http://www.perl.com',&lt;br /&gt;  'http://www.perl.org',&lt;br /&gt;  'http://perlmonks.org',&lt;br /&gt;  'http://www.pm.org',&lt;br /&gt;  'http://kiev.pm.org',&lt;br /&gt;  'http://www.parrot.org',&lt;br /&gt;  'http://www.parrotcode.ks.ua',&lt;br /&gt; );&lt;br /&gt; &lt;br /&gt; my $async = HTTP::Async-&gt;new;&lt;br /&gt; &lt;br /&gt; my $max_connects = 3;&lt;br /&gt; my $cnt = @urls &gt; $max_connects ? $max_connects : @urls;&lt;br /&gt; add_request() foreach (1 .. $cnt);&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; while ( my $res = $async-&gt;wait_for_next_response ) {&lt;br /&gt;  if($res-&gt;is_success()) {&lt;br /&gt;    print "Succeeded for '", $res-&gt;request-&gt;url, "'\n";&lt;br /&gt;   # print $res-&gt;content, "\n";&lt;br /&gt;  }&lt;br /&gt;  add_request();&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; sub add_request {&lt;br /&gt;  my $url = shift @urls or return;&lt;br /&gt;  my $req = HTTP::Request-&gt;new(GET =&gt; $url,&lt;br /&gt;  ['User-Agent' =&gt; "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)"]);&lt;br /&gt;  $async-&gt;add($req);&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В это пример первоначально создается $max_connects запросов и по мере их завершения, создаются все новые и новые.&lt;br /&gt;&lt;br /&gt;Все очень просто. Но опять у меня проснулась любопытство: а нельзя это все таки для такой конвейерной обработки приспособить модуль LWP::Parallel::UserAgent?&lt;br /&gt;&lt;br /&gt;Оказалось можно. Для этого просто нужно переопределить события on_return и on_failure:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; $SIG{PIPE} = 'IGNORE';&lt;br /&gt; use LWP::Parallel::UserAgent;&lt;br /&gt; &lt;br /&gt; my @urls    = (&lt;br /&gt;   'http://www.perl.com',&lt;br /&gt;   'http://www.perl.org',&lt;br /&gt;   'http://perlmonks.org',&lt;br /&gt;   'http://www.pm.org',&lt;br /&gt;   'http://kiev.pm.org',&lt;br /&gt;   'http://www.parrot.org',&lt;br /&gt;   'http://www.parrotcode.ks.ua',&lt;br /&gt; );&lt;br /&gt; &lt;br /&gt; my $ua = LWP::Parallel::UserAgent-&gt;new();&lt;br /&gt; $ua-&gt;agent("Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)");&lt;br /&gt; $ua-&gt;nonblock(1);&lt;br /&gt; &lt;br /&gt; my $max_connects = 3;&lt;br /&gt; my $cnt = @urls &gt; $max_connects ? $max_connects : @urls;&lt;br /&gt; add_request() foreach (1 .. $cnt);&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; sub add_request {&lt;br /&gt;  my $url = shift @urls or return;&lt;br /&gt;  my $req = HTTP::Request-&gt;new(GET =&gt; $url);&lt;br /&gt;  $ua-&gt;register($req);&lt;br /&gt; } &lt;br /&gt; &lt;br /&gt; &lt;br /&gt; { &lt;br /&gt; no warnings;&lt;br /&gt; sub LWP::Parallel::UserAgent::on_return  {&lt;br /&gt;   my ($self, $request, $response, $entry) = @_;&lt;br /&gt;   if($response-&gt;is_success()) {&lt;br /&gt;     print "Succeeded for '", $response-&gt;request-&gt;url, "'\n";&lt;br /&gt;   }&lt;br /&gt;   add_request();&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt; sub LWP::Parallel::UserAgent::on_failure { add_request() }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; my $entries = $ua-&gt;wait(3);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Что ж не так красиво, как при использовании HTTP::Async, но свою задачу этот код выполняет. Разве что очень не понравилась необходимость установить $SIG{PIPE} = 'IGNORE';&lt;br /&gt;&lt;br /&gt;Ну вот и все история... :-) Да... давно это было... Но тем не-менее, кому-то может и пригодиться этот опыт и сейчас.&lt;br /&gt;&lt;br /&gt;Копия: &lt;a href="http://kiev.pm.org/node/253"&gt;http://kiev.pm.org/node/253&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-8480406749449617682?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/8480406749449617682/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=8480406749449617682' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8480406749449617682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8480406749449617682'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/10/perl-http.html' title='Perl: Асинхронный конвейер HTTP клиентов'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-4871856472163586188</id><published>2008-09-18T11:12:00.002+03:00</published><updated>2008-10-15T09:53:08.316+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>О ключике -w замолвите слово</title><content type='html'>Прагм strict и warnings обычно достаточно.&lt;br /&gt;Ключик -w использую в основном в однострочниках.&lt;br /&gt;Но, как оказалось, о нем забывать не стоит!&lt;br /&gt;&lt;br /&gt;Вот реальная история.&lt;br /&gt;&lt;br /&gt;При разработке системы, использующих подгруздку модулей, в одном из таких модулей была сделана ошибка. По какой-то причине кто-то поставил двоеточие после слова package, подобно вот этому:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; cat Foo.pm &lt;br /&gt; package: Foo;&lt;br /&gt; &lt;br /&gt; use strict;&lt;br /&gt; use warnings;&lt;br /&gt; &lt;br /&gt; # ...&lt;br /&gt; &lt;br /&gt; 1;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Однако, при загрузке этого модуля никаких предупреждений не выводится:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; perl -c -MFoo -e 1&lt;br /&gt; -e syntax OK&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Хотя перед загрузкой включены и strict, и warnings:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&gt; perl -c -Mstrict -Mwarnings -MFoo -e 1&lt;br /&gt;-e syntax OK&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Все дело в том, что в файле Foo.pm прагма warnings подключается после объявления модуля.&lt;br /&gt;Если в подключать прагму до объявления модуля, то ошибка легко диагностируется:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; cat Foo.pm &lt;br /&gt; use strict;&lt;br /&gt; use warnings;&lt;br /&gt; &lt;br /&gt; package: Foo;&lt;br /&gt; &lt;br /&gt; # ...&lt;br /&gt; &lt;br /&gt; 1;&lt;br /&gt;&lt;br /&gt; &gt; perl -c -MFoo -e 1&lt;br /&gt; Bareword "Foo" not allowed while "strict subs" in use at Foo.pm line 4.&lt;br /&gt; Compilation failed in require.&lt;br /&gt; BEGIN failed--compilation aborted.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Но писать так как-то не очень привычно и не хочется, да и где гарантия, что другой разработчик будут также писать так?&lt;br /&gt;&lt;br /&gt;Вот тут и приходит на помощь ключик -w:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; perl -wc -MFoo -e 1&lt;br /&gt; Useless use of a constant in void context at Foo.pm line 1.&lt;br /&gt; -e syntax OK&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Хотя файл Foo.pm и загружен, но предупреждение позволяет легко понять, что имеется ошибка.&lt;br /&gt;&lt;br /&gt;Так что ключик -w рано выкидывать на свалку истории, как это можно подумать из perldoc perllexwarn.&lt;br /&gt;&lt;br /&gt;Копия: &lt;a href="http://kiev.pm.org/node/235"&gt;http://kiev.pm.org/node/235&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-4871856472163586188?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/4871856472163586188/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=4871856472163586188' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4871856472163586188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/4871856472163586188'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/09/w.html' title='О ключике -w замолвите слово'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-6825478122357259872</id><published>2008-06-19T09:20:00.003+03:00</published><updated>2008-06-24T13:36:33.477+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl: Cooking warnings</title><content type='html'>Данная заметка касается некоторых тактических приемов обработки предупреждений и не претендует на полноценный обзор систем логирования будь-то Log::Dispatch или Log::Log4perl.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Обработка предупреждений&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Обычно имея лишь предупреждение подобное этому: "Use of uninitialized value in hash element at ...", - практически не возможно установить, что привело к нему. Необходима дополнительная информация: минимум входящие данные. Поэтому обработку предупреждений можно разделить на два уровня.&lt;br /&gt;&lt;br /&gt;Первый уровень обработки предупреждений простой: он отлавливает предупреждения и ошибки, которые возникают до того, как заработает второй уровень. Для этого можно использовать CGI::Carp, например:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use CGI::Carp qw(carpout);&lt;br /&gt; open (LOG, "&gt;&gt;/var/log/.../foo.log");&lt;br /&gt; carpout(*LOG);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Второй уровень обработки предупреждений начинается стразу как только приняты входящие данные, поскольку первой задачей второго уровня обработки предупреждений является запись входящих данных с указанием, если это возможно, их источника.&lt;br /&gt;Кроме того, одно предупреждение редко бывает без другого, поэтому второй задачей является группировка предупреждений и запись в лог единым целым.&lt;br /&gt;&lt;br /&gt;Простейшая реализация обработки предупреждений второго уровня показана ниже.&lt;br /&gt;&lt;br /&gt;Подключение обработчика и вызов подпрограммы записи предупреждений:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use Foo::Log;&lt;br /&gt; &lt;br /&gt; sub main {&lt;br /&gt;     # ...&lt;br /&gt;     local SIG{__WARN__} = warn_trap();&lt;br /&gt;     # ...&lt;br /&gt;     write_warn($id_source, $id_input_data);&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Непосредственно модуль обработки (без экспорта имен и полезных прагм):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; package Foo::Log;&lt;br /&gt; &lt;br /&gt; my @warnings = ();&lt;br /&gt; &lt;br /&gt; sub warn_trap() {&lt;br /&gt;     @warnings = ();&lt;br /&gt;     my $old_warn_trap = $SIG{__WARN__};&lt;br /&gt;     return sub {&lt;br /&gt;         my $warn = shift;&lt;br /&gt;         push @warnings, $warn;&lt;br /&gt;         if ($old_warn_trap) {&lt;br /&gt;             # Конечно, если хотим передать сообщение&lt;br /&gt;             # вышестоящему обработчику.&lt;br /&gt;             local $SIG{__WARN__} = $old_warn_trap;&lt;br /&gt;             eval { &amp;$old_warn_trap($warn) };&lt;br /&gt;         }&lt;br /&gt;     };&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; sub write_warn(;$$) {&lt;br /&gt;     my ($id_source, $id_input_data) = @_;&lt;br /&gt;     if (@warnings) {&lt;br /&gt;         # Открываем лог файл и &lt;br /&gt;         # сохраняем $id_source, $id_input_data и @warnings.&lt;br /&gt;         # ...&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Почему не устанавливаю ловушку для __DIE__?&lt;br /&gt;Потому что предпочитаю ловить die в eval и вызывать warn $@, да и первый уровень на страже.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Отладка&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Вышеприведенная обработка предупреждений желательна, но не достаточна для легкого обнаружения причин предупреждений в приложениях, в которых поток обработки входных данных зависит от уже имеющихся данных.&lt;br /&gt;&lt;br /&gt;Почему? Потому что на момент анализа состояние системы отличается от состояния, когда было сгенерировано предупреждение, да и входящие данные слишком далеки в потоку обработки от места возникновения предупреждения, чтобы можно пройтись вручную по логическим цепочкам.&lt;br /&gt;&lt;br /&gt;Необходимо получить входящие данные как можно ближе к точке возникновения предупреждения. Такими данными являются аргументы подпрограммы, в которой генерируется предупреждение и, возможно, находиться ошибка. Ведь предупреждение - это сигнал об ошибке либо в логике, либо в данных.&lt;br /&gt;&lt;br /&gt;Нет проблем: используем callar и @DB::args в __WARN__ обработчике.&lt;br /&gt;&lt;br /&gt;Но когда поток обработки входных данных зависит от уже имеющихся данных в базе и эти данные изменяются во времени, иметь аргументы подпрограммы бывает не достаточно для поиска ошибки, нужно также знать эти "уже имеющиеся в базе данные" на момент возникновения ошибки. &lt;br /&gt;&lt;br /&gt;Конечно, полученные данных из базы и логику можно разнести по разным подпрограммам - так и стараюсь делать, но не всегда это возможно сделать красиво. Ведь данные из базы извлекаются при необходимости по мере прохождения по логическим цепочкам.&lt;br /&gt;&lt;br /&gt;Более красивым решением может быть тактика точечных обработчиков предупреждений.&lt;br /&gt;&lt;br /&gt;Локальный точечный обработчик устанавливается максимально близко к месту возникновения ошибки и ему указывается что необходимо сделать при возникновении предупреждения.&lt;br /&gt;&lt;br /&gt;Пример реализации точечного обработчика:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use Data::Dumper;&lt;br /&gt;&lt;br /&gt; sub pointed_warn_trap(@) {&lt;br /&gt;     my @data = @_;&lt;br /&gt;     my $old_warn_trap = $SIG{__WARN__};&lt;br /&gt;     return sub { &lt;br /&gt;         my $message = join "", shift, Dumper @data;&lt;br /&gt;         $old_warn_trap ? eval { &amp;$old_warn_trap($message) } :&lt;br /&gt;              warn $message;&lt;br /&gt;     };&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Пример использования точечного обработчика:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; local $SIG{__WARN__} = pointed_warn_trap($foo, $too);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;В этом примере $foo может быть обрабатываемыми данными, а $too - информацией из базы.&lt;br /&gt;&lt;br /&gt;После того как разместили точечный обработчик остается только, подобно рыбаку, набраться немного терпения и словить "рыбку".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Заключение&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Эти приемы обработки предупреждений хоть и просты, но очень помогают отлавливать ошибки и сделать код более качественным.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;P.S.&lt;/span&gt;&lt;br /&gt;Копия: &lt;a href="http://kiev.pm.org/node/188"&gt;http://kiev.pm.org/node/188&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-6825478122357259872?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/6825478122357259872/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=6825478122357259872' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/6825478122357259872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/6825478122357259872'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/06/perl-cooking-warnings.html' title='Perl: Cooking warnings'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-1113320217332295980</id><published>2008-05-27T08:57:00.002+03:00</published><updated>2008-05-27T09:07:03.295+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Один нюанс использования map</title><content type='html'>Когда блок map должен вернуть ссылку на анонимный хеш и этот блок содержит более чем одну логическую строку, то необходимо подсказать, что фигурные скобки являются обозначением анонимного хеша, а не блока лексической области видимости. В качестве подсказки могут выступать круглые скобки, в которые обрамляется анонимный хеш.&lt;br /&gt;&lt;br /&gt;Примеры.&lt;br /&gt;&lt;br /&gt;Простой блок - perl понимает сам, что имеет дело с анонимным хешем:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; perl -MData::Dumper -e 'print Dumper [map { { 1 .. 4 } } (1 .. 2)]'&lt;br /&gt; $VAR1 = [&lt;br /&gt;           {&lt;br /&gt;             '1' =&gt; 2,&lt;br /&gt;             '3' =&gt; 4&lt;br /&gt;           },&lt;br /&gt;           {&lt;br /&gt;             '1' =&gt; 2,&lt;br /&gt;             '3' =&gt; 4&lt;br /&gt;           }&lt;br /&gt;         ];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Сложный блок - perl думает, что имеет дело с лексической областью видимости:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; perl -MData::Dumper -e 'print Dumper [map { 1; { 1 .. 4 } } (1 .. 2)]'&lt;br /&gt; $VAR1 = [&lt;br /&gt;           1,&lt;br /&gt;           2,&lt;br /&gt;           3,&lt;br /&gt;           4,&lt;br /&gt;           1,&lt;br /&gt;           2,&lt;br /&gt;           3,&lt;br /&gt;           4&lt;br /&gt;         ];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Подсказка про анонимный хеш при помощи круглых скобок:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &gt; perl -MData::Dumper -e 'print Dumper [map { 1; ({ 1 .. 4 }) } (1 .. 2)]'&lt;br /&gt; $VAR1 = [&lt;br /&gt;           {&lt;br /&gt;             '1' =&gt; 2,&lt;br /&gt;             '3' =&gt; 4&lt;br /&gt;           },&lt;br /&gt;           {&lt;br /&gt;             '1' =&gt; 2,&lt;br /&gt;             '3' =&gt; 4&lt;br /&gt;           }&lt;br /&gt;         ];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Кстати, когда анонимный хеш возвращается из обычной подпрограммы при помощи return, то нет нужды в подсказке в виде круглых скобок, так как return устраняет вышеописанную неопределенность. А вот если return отсутствует и подпрограмма возвращает последние вычисленное значение, то подсказка необходима. В блоке map return использовать нельзя.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://kiev.pm.org/node/182"&gt;http://kiev.pm.org/node/182&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-1113320217332295980?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/1113320217332295980/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=1113320217332295980' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1113320217332295980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1113320217332295980'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/05/map.html' title='Один нюанс использования map'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-8490296369639715996</id><published>2008-02-22T13:32:00.005+02:00</published><updated>2009-09-04T10:26:50.930+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Осторожно, Perl!</title><content type='html'>Шуточная на половину статья, в которой упоминаются некоторые перловые хаки. Perl самый опасный язык программирования, поскольку он развивает "отвратительные" качества в людях. Некоторые их называют "добродетелями" программистов: лень, нетерпение, высокомерие (laziness, impatience, hubris).&lt;br /&gt;&lt;br /&gt;Первоначально задумывалось достоинства Perl показать как недостатки, а недостатки - как достоинства. Но, кажется, немного отклонился в сторону. Даже думал, как Гоголь, предать огню эту статью, чтобы не пугать неокрепших духом, но потом решил оставить. Правильно поступил или нет - об этом судить читателю.&lt;br /&gt;&lt;br /&gt;Вот собственно статья.&lt;br /&gt;&lt;br /&gt;Среди множества языков программирования один занимает особое место. Это язык Perl! Если вы его не знает и получите предложения его освоить - бегите как можно дальше, иначе...&lt;br /&gt;&lt;br /&gt;Иначе вы... Вы станете совсем другим не только в профессиональном плане, но и в человеческом. Perl - этот язык, который способствует развитию у людей самых отвратительных черт, среди которых: лень, нетерпение, высокомерие.&lt;br /&gt;&lt;br /&gt;Причем это происходит постепенно и от того более коварным является этот процесс. Человек этого не замечает и даже потом, когда Perl полностью им завладевает, человек не будет это осознавать. Более того, он будет даже превозносить эти отвратительные черты, как великие добродетели программистов. Но какие это же добродетели!&lt;br /&gt;&lt;br /&gt;Возьмем, например, высокомерие. Оно, якобы, помогает писать замечательные программы. Глупости все это. Высокомерие Perl программистов настолько велико, что они даже встревают в спор С++ и OCaml программистов о производительности их языков. Сам был очевидцем такого спора. В споре шел разговор как оптимально генерируется ассемблерный код, а также затрагивались вопросы оптимизации хвостовой рекурсии... Решили провести тесты, например, посредством вычисления чисел Фибоначчи.&lt;br /&gt;&lt;br /&gt;А тут мимо проходил Perl программист. И что вы себе думает, он посмел высокомерно утверждать, что вычислит на Perl числа Фибоначчи быстрей чем они. Поспорили на бутылку коньяка. Программисты C++ и Ocaml знали, что из себя представляет Perl, поэтому сразу согласились на спор. Но они не знали, что из себя представляют Perl программисты. Кто бы мог подумать, что этот Perl программист выиграет спор! Он первый вычислил числа Фибоначчи! Когда остальные участники спора, отказываясь верить словам, подошли увидеть все своими глазами, Perl программист запустил на исполнение следующий код:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use strict;&lt;br /&gt; use warnings;&lt;br /&gt; use Memoize;&lt;br /&gt; memoize('fib');&lt;br /&gt; &lt;br /&gt; sub fib {&lt;br /&gt;  my $n = shift;&lt;br /&gt;  return $n if $n &lt; 2;&lt;br /&gt;  fib($n-1) + fib($n-2);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; my $n = $ARGV[0];&lt;br /&gt; print "fin($n) = ", fib($n), "\n";&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Конечно, для тех, кто знаком с модулем Memoize, все становиться ясно с первого взгляда.&lt;br /&gt;&lt;br /&gt;Perl самый быстрый язык, не потому, что его интерпретатор быстр, а потому, что быстры и ясны мысли Perl программистов. Когда другие жонглирую байтами, Perl программисты не забывают об оптимизаций алгоритмов.&lt;br /&gt;&lt;br /&gt;С дрогой стороны, Perl не только "самый быстрый язык", но и самый ленивый. Нет, не надо говорить, что самый ленивый - это Haskell. Вы бы посмотрели, как иногда Haskell программисты борются с ленивостью своего языка. Perl ленив по другому. Правильно, он ленив, потому, что ленивы его использующие люди. Кстати, и потому что они ленивы, они даже не нагружают свой компьютер лишней работой: вспомните про модуль Memoize. А ленивые списки и прочие есть и у Perl, например: Data::Lazy, Scalar::Defer, Object::Lazy, Tie::Scalar, Tie::StdScalar и даже DBIx::LazyMethod.&lt;br /&gt;&lt;br /&gt;Perl также славиться тем, что "делает за вас вашу работу". Вроде-бы это очень хорошо, но постойте, это же самая большая "медвежья услуга". Со временем вы обленитесь и ваша лень не будет иметь границ.&lt;br /&gt;&lt;br /&gt;Ну а поскольку Perl очень быстр и ленив, то он делает людей его использующих очень нетерпеливыми.&lt;br /&gt;Быстро сделав свою работу, вы будете с нетерпением ждать, когда, например, программисты, реализующие клиентскую часть проекта, напишут и отладят свой код. Вы будите скучать от безделья, нервничать от осознания того, что вас сдерживают и проект движется черепашьими темпами. Придется пить валерьянку.&lt;br /&gt;&lt;br /&gt;Многие не в силах выдержать это, ломаются - бреют голову, посыпают ее пеплом и уходят в монастырь (http://perlmonks.org). Там они в спокойной обстановке, вдалеке от суетного мира занимаются каллиграфией, то есть обфускацией (http://www.perlmonks.org/index.pl?node=Obfuscated%20Code).&lt;br /&gt;&lt;br /&gt;Лень привела также к тому, что Perl является сосредоточением множество закорлючер и заклинаний. (Про семейство APL языков скромно умолчу.) И все это преподноситься под соусом "cуществует более одного способа сделать это". Да ни один силач не поднимет книгу Perl рецептов.&lt;br /&gt;&lt;br /&gt;А посмотрите, что Perl программисты сделали с совершенной и строгой концепцией Объектно-Ориентированного программирования!&lt;br /&gt;Ну разве это объекты? Правда Damian Conway (Tie::SecureHash, Class::Contract) пытался образумить Perl программистов, да что толку. Как-бы в ответ, появились модули, позволяющие делать всевозможные хаки, залезать в чужие области видимости и менять значения локальных структур! Ужас! (Перечень модулей, опасных для неокрепших духом, вырезан цензором.) Хотя, надо отдать должное, на основе этих идей появилась реализация Аспектно-Ориентированного программирования на Perl (Aspect).&lt;br /&gt;&lt;br /&gt;Так что, программисты, берегитесь Perl - это очень опасный язык! Когда Perl проникнет в ваши умы, вы никогда больше не сможете нормально писать на других языках программирования. И этому также будет способствовать то, что Perl из всех языков программирования дальше всего находиться от компьютера и ближе всего к человеку. Не дай Бой, вы из программиста станете писателем или поэтом. А ведь были уже прецеденты, например, королева поэзии Perl Sharon Hopkins.&lt;br /&gt;&lt;br /&gt;С другой стороны, чтобы стать настоящим мастером, надо пройти через все это. Но берегись.&lt;br /&gt;Perl - это как обоюдоострый меч, которым можно делать чудеса, а можно серьезно пораниться.&lt;br /&gt;&lt;br /&gt;Вы спросите, как же мне, использующему Perl, удалось избежать его пагубного влияния?&lt;br /&gt;А у меня иммунитет - я же не программист. Я химик! :-&lt;br /&gt;&lt;br /&gt;Коментарии и пожелания оставляте в &lt;a href="http://kiev.pm.org/?q=node/157"&gt;http://kiev.pm.org/?q=node/157&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-8490296369639715996?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/8490296369639715996/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=8490296369639715996' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8490296369639715996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/8490296369639715996'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/02/perl.html' title='Осторожно, Perl!'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-6695357113766272283</id><published>2008-02-06T08:54:00.001+02:00</published><updated>2008-02-13T08:58:11.971+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl JSON модули с поддержкой UTF-8</title><content type='html'>&lt;h2&gt;&lt;a name="введение"&gt;Введение&lt;/a&gt;&lt;/h2&gt;  &lt;p&gt;Статья представляет обзор perl модулей для работы с JSON в контексте UTF-8. Подразумевается работа с UTF-8 на уровне символов, а не байтов. Если нужна работа на уровне байт, то подойдет любой из нижеперечисленных моделей, который устроит по скорости.&lt;/p&gt;  &lt;p&gt;На CPAN существуют следующие модули:&lt;/p&gt;  &lt;ul&gt; &lt;li&gt; &lt;p&gt;&lt;strong&gt;JSON&lt;/strong&gt; - parse and convert to JSON (JavaScript Object Notation).&lt;/p&gt; &lt;/li&gt;&lt;li&gt; &lt;p&gt;&lt;strong&gt;JSON::XS&lt;/strong&gt; - JSON serialising/deserialising, done correctly and fast&lt;/p&gt; &lt;/li&gt;&lt;li&gt; &lt;p&gt;&lt;strong&gt;JSON::Syck&lt;/strong&gt; - JSON is YAML&lt;/p&gt; &lt;/li&gt;&lt;li&gt; &lt;p&gt;&lt;strong&gt;JSON::PC&lt;/strong&gt; - fast JSON Parser and Converter (JSON::PC is a XS version of JSON).&lt;/p&gt; &lt;/li&gt;&lt;li&gt; &lt;p&gt;&lt;strong&gt;JSON::DWIW&lt;/strong&gt; - JSON converter that Does What I Want&lt;/p&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;В качестве тестовых данных будем использовать следующий JSON:&lt;/p&gt;  &lt;pre&gt; { "hello":"Hello, \u00ab\u043f\u0440\u0438\u0432\u0435\u0442\u00bb \u2116 \u263a. Good by." }&lt;/pre&gt;  &lt;p&gt;В JSON содержится фраза ``Hello, &lt;&lt;привет&gt;&gt; #. Good by.'', в которой кавычки, номер и смайлик ``уникодные''. Именно как \uxxxx в JSON кодируются UTF-8 символы (http://json.org).&lt;/p&gt;  &lt;p&gt;Этому JSON соответствует следующая Perl структура:&lt;/p&gt;  &lt;pre&gt; { 'hello' =&gt; "Hello, \x{ab}\x{43f}\x{440}\x{438}\x{432}\x{435}\x{442}\x{bb} \x{2116} \x{263a}. Good by." }&lt;/pre&gt;  &lt;p&gt;Ну что-ж теперь приступим к тесту моделей.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;h2&gt;&lt;a name="обзор_модулей"&gt;Обзор модулей&lt;/a&gt;&lt;/h2&gt;  &lt;p&gt;&lt;strong&gt;JSON&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;Для работы у UTF-8 в конструкторе необходимо это указать:&lt;/p&gt;  &lt;pre&gt; JSON-&gt;new(utf8 =&gt; 1);&lt;/pre&gt;  &lt;p&gt;Модуль корректно ставит UTF-8 флаги, и обратном преобразовании кодирует UTF-8 символы. Но есть большое но: модель споткнулся на символах кавычки елочкой.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;JSON::PC&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;Как указано в документации на модуль, JSON::PC является XS версией модуля JSON, и как истинный приемник наследует туже проблему с русскими или французскими кавычками.&lt;/p&gt;  &lt;p&gt;Модуль сам разбирается где UTF-8, ничего явно указывать не нужно.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;JSON::Syck&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;Модуль JSON::Syck написан сообразительной китаянкой, которая заметила что JSON по сути является YAML, и просто использовала библиотеку libsyck.&lt;/p&gt;  &lt;p&gt;UTF-8 не поддерживается вообще, модель ориентирован на работу с октетами, о чем честно написано в документации. Подразумевается \uxxxx, а не ImplicitUnicode опция.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;JSON::XS&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;А вот модуль JSON::XS показал себя достойно со всех сторон. Правда перед преобразованием из JSON в Perl надо указать флаг utf8, а при обратном преобразовании - флаг ascii.&lt;/p&gt;  &lt;p&gt;Из JSON в Perl:&lt;/p&gt;  &lt;pre&gt; use JSON::XS;&lt;br /&gt;my $json_xs = JSON::XS-&gt;new();&lt;br /&gt;$json_xs-&gt;utf8(1);&lt;br /&gt;$json_xs-&gt;decode($json_data);&lt;/pre&gt;  &lt;p&gt;Из Perl в JSON:&lt;/p&gt;  &lt;pre&gt; use JSON::XS;&lt;br /&gt;my $json_xs = JSON::XS-&gt;new();&lt;br /&gt;$json_xs-&gt;ascii(1);&lt;br /&gt;$json_xs-&gt;encode($perl_data);&lt;/pre&gt;  &lt;p&gt;Можно также задать флаг pretty для красивого форматирования результирующего JSON.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;JSON::DWIW&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;Последний модуль JSON::DWIW также ведет себе отлично, необходимо лишь в конструкторе сообщить об UTF-8:&lt;/p&gt;  &lt;pre&gt; use JSON::DWIW;&lt;br /&gt;my $json_dwiw = JSON::DWIW-&gt;new({ escape_multi_byte =&gt; 1 });&lt;br /&gt;$json_dwiw-&gt;from_json($json_data);&lt;br /&gt;$json_dwiw-&gt;to_json($perl_data);&lt;/pre&gt;  &lt;p&gt; &lt;/p&gt;  &lt;h2&gt;&lt;a name="бонусы"&gt;Бонусы&lt;/a&gt;&lt;/h2&gt;  &lt;p&gt;Два пакета JSON::XS и JSON::DWIW нормально обрабатывают ситуацию, когда передаваемая им JSON строка не является последовательностью октетов, а является perl строкой с UTF-8 - не надо делать лишнюю проверку.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;h2&gt;&lt;a name="benchmark"&gt;Benchmark&lt;/a&gt;&lt;/h2&gt;  &lt;p&gt;До этапа тестирования производительности успешно добрались лишь два модуля: JSON::XS и JSON::DWIW, - к которым нет ни одной претензии.&lt;/p&gt;  &lt;p&gt;Собственно тест скорости на не слишком большой структуре:&lt;/p&gt;  &lt;pre&gt; use Benchmark qw(cmpthese);&lt;/pre&gt;  &lt;pre&gt; cmpthese(10000, {&lt;br /&gt;     'JSON::XS'   =&gt; sub {&lt;br /&gt;                     my $json_xs = JSON::XS-&gt;new();&lt;br /&gt;                     $json_xs-&gt;utf8(1);&lt;br /&gt;                     $json_xs-&gt;decode($json_data_u);&lt;br /&gt;                     $json_xs-&gt;ascii(1);&lt;br /&gt;                     $json_xs-&gt;encode($perl_data_expected)&lt;br /&gt;             },&lt;br /&gt;     'JSON::DWIW' =&gt; sub {&lt;br /&gt;                     my $json_obj = JSON::DWIW-&gt;new({ escape_multi_byte =&gt; 1 });&lt;br /&gt;                     $json_obj-&gt;from_json($json_data_u);&lt;br /&gt;                     $json_obj-&gt;to_json($perl_data_expected)&lt;br /&gt;             },&lt;br /&gt;});&lt;/pre&gt;  &lt;p&gt;А вот и результаты:&lt;/p&gt;  &lt;pre&gt;               Rate JSON::DWIW   JSON::XS&lt;br /&gt;JSON::DWIW  5246/s         --       -78%&lt;br /&gt;JSON::XS   24151/s       360%         --&lt;/pre&gt;  &lt;p&gt; &lt;/p&gt;  &lt;h2&gt;&lt;a name="вывод"&gt;Вывод&lt;/a&gt;&lt;/h2&gt;   &lt;p&gt;Для меня вывод однозначен --- JSON::XS. Модуль ведет себя отлично с UTF-8, корректно преобразовывает данные в Perl строки и к тому же обладает приличной скоростью.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;P.S. Для комментарий - &lt;a href="http://kiev.pm.org/?q=node/153"&gt;http://kiev.pm.org/?q=node/153&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-6695357113766272283?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/6695357113766272283/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=6695357113766272283' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/6695357113766272283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/6695357113766272283'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/02/perl-json-utf-8.html' title='Perl JSON модули с поддержкой UTF-8'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-1764934141496760534</id><published>2008-01-28T11:21:00.000+02:00</published><updated>2008-01-28T12:39:04.318+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Объекты? Зачем?! Точнее, не всегда. Замыкания!</title><content type='html'>Заметка не предназначена для разжигания священной войны: хорошо или плохо объектно ориентированное программирование. Я сам использую его наравне с другими.&lt;br /&gt;&lt;br /&gt;Цель заметки --- показать, что иногда проще обойтись без объектов, а использовать замыкания.&lt;br /&gt;&lt;br /&gt;Достаточно часто возникает ситуация, когда необходимо многократно произвести некоторое действие, но перед этим провести некоторую подготовительную работу. В объектно ориентированном стиле для этого используется объект с одним единственным методом.&lt;br /&gt;&lt;br /&gt;Рассмотрим подобный объект на примере абстрактного "сумматора" чисел. При инициализации "сумматору" передается первоначальное значение, а при каждом вызове метода к текущему значению прибавляется передаваемое. Вот код такого "сумматора" в объектно-ориентированном стиле:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; package Foo;&lt;br /&gt;&lt;br /&gt; sub new {&lt;br /&gt;  my $class = shift;&lt;br /&gt;  my $foo = shift;&lt;br /&gt;  return bless \$foo;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; sub foo {&lt;br /&gt;  my $self = shift;&lt;br /&gt;  $$self += shift;&lt;br /&gt;  print $$self, "\n";&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; 1;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Пример использования:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; use Foo;&lt;br /&gt; my $foo = Foo-&gt;new(3);&lt;br /&gt; $foo-&gt;foo(1);&lt;br /&gt; $foo-&gt;foo(1);&lt;br /&gt; $foo-&gt;foo(2);&lt;br /&gt; $foo-&gt;foo(2);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Теперь сделаем аналогичный по функционалу "сумматор" с использованием замыкания:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; sub make_foo {&lt;br /&gt;  my $foo = shift;&lt;br /&gt;  return sub {&lt;br /&gt;   $foo += shift;&lt;br /&gt;   print $foo, "\n";&lt;br /&gt;  };&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Пример использования:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; my $foo = make_foo(3);&lt;br /&gt; $foo-&gt;(1);&lt;br /&gt; $foo-&gt;(1);&lt;br /&gt; $foo-&gt;(2);&lt;br /&gt; $foo-&gt;(2);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Как видим вариант с замыканием проще, компактней и элегантней.&lt;br /&gt;&lt;br /&gt;Пожалуй на этом и остановимся --- читатель дальше сможет сам развить тему. Приведу лишь цитату Стива Маджевски: "Объект --- это совокупность данных вместе с привязанными к ним процедурами... Замыкание --- это процедура вместе с привязанной к ней совокупностью данных."&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;P.S.&lt;br /&gt;Кстати, &lt;a href="http://www.parrotcode.org"&gt;Parrot&lt;/a&gt; оперирует объектами (PMC),&lt;br /&gt;но при вызовах подпрограмм использует стиль передачи продолжений, который не мыслим без замыканий.&lt;br /&gt;&lt;br /&gt;P.P.S&lt;br /&gt;Копия и комментарии находятся на &lt;a href="http://kiev.pm.org/?q=node/147"&gt;kiev.pm.org&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-1764934141496760534?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/1764934141496760534/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=1764934141496760534' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1764934141496760534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/1764934141496760534'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/01/blog-post.html' title='Объекты? Зачем?! Точнее, не всегда. Замыкания!'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-3335278142045949442</id><published>2007-12-07T11:33:00.001+02:00</published><updated>2007-12-07T11:42:56.376+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Отцы и дети или perl, fork и деструкторы</title><content type='html'>Я конечно не Тургенев Иван Сергеевич, но также кое-что попробую рассказать о взаимоотношениях отцов и детей. Рассказать не все, а лишь то, что Иван Сергеевич умышленно опустил, чтобы не уменьшать художественную ценности своего произведения излишними техническими подробностями. Скажу сразу: поскольку эта история произошла давным-давно, то некоторые детали потеряны или, наоборот, обросли некоторыми выдумками и преувеличениями, так что за 100% достоверность не ручаюсь.&lt;br /&gt;&lt;br /&gt;А началась все тогда, когда при открытом соединении с базой данных процесс вызвал системный вызов fork, а затем с удивлением обнаружил, что база "упала". Пришлось ему звать на помощь. Вариант с базой проверили сразу: база как работала, так и продолжала работать. Пожурили процесс за ложные показания, и начали копаться в нем.&lt;br /&gt;&lt;br /&gt;И так его покрутили и этак, и пришли к выводу, что все дело в деструкторах. Дочерний процесс завершился и как положено все за собой почистил и убрал. При этом он закрыл разделяемый с родительским процессом сокет, по которому было установлено соединением с базой.&lt;br /&gt;&lt;br /&gt;Но как обычно, большинство дорожек уже протоптаны, и нужно лишь найти правильную. Посмотрели документацию на модуль DBI и увидели атрибут InactiveDestroy, который говорит, что не надо уничтожать соединение с базой, если оно не твое.&lt;br /&gt;&lt;br /&gt;Но как быть, когда пойдем путями неведанными, дорогами не хожеными? Стали искать решение и для такого случая, когда в сторонней библиотеке нет такого замечательного атрибута как InactiveDestroy.&lt;br /&gt;&lt;br /&gt;Как научиться управлять деструкторами? Искали, искали и наконец-то нашли в модуле POSIX вызов _exit. Этот вызов говорит: "а пошел-ка, то на ..., то есть убирай за собой сам!" Так это то, что нужно! Конечно прямо этому совету никто не последовал - кому самому все убирать охота. Обернули, то что необходимо прибрать в лексическую область видимости - пусть сборщик мусора убирается там, а после этой области прописали POSIX::_exit(0).&lt;br /&gt;&lt;br /&gt;На это можно было бы ставить точку. Все работает отлично, да и на вооружении теперь еще один трюк. Но интуиция подсказывала, что это только начало. Что будет, если дочерний процесс сам начнет использовать дескриптор к базе данных? Конечно так делать очень не хорошо. Но вдруг как-то явно или не явно это произойдет. Поэтому надо выработать простые правила, чтобы такой ситуации можно было бы легко избежать, то есть надо по полочкам разложить взаимоотношения "отцов и детей".&lt;br /&gt;&lt;br /&gt;Как оказалось эти взаимоотношения можно разделить на два варианта: когда дочерний процесс будет существовать дольше своего родителя и когда дочерний процесс, cделав свою работу, завершиться раньше родительского.&lt;br /&gt;&lt;br /&gt;Второй вариант был уже описан выше и для него достаточно использовать POSIX::_exit(0), если, конечно нет InactiveDestroy. В первом же варианте надо в дочернем процессе сразу же создать копии необходимых данных из родительского.&lt;br /&gt;&lt;br /&gt;Если забыть на минутку о процессах, fork и прочей компьютерной ерунде, закрыть глаза, то так и видишь как отцы общаются с детьми.&lt;br /&gt;&lt;br /&gt;Когда отец отпускает своего ребенка в самостоятельное плавание, он его наставляет: "сынок, воспользуйся моими трудами вовремя, создай на их основе как можно быстрей свой капитал и стань скорей независимым".&lt;br /&gt;&lt;br /&gt;А когда отец отпускает ребенка ненадолго погулять, он ему говорит: "дитя, когда прийдешь с улицы, то убери на место все, что брал играться, но так, чтобы то что я дал тебе, осталось в неизменном состоянии".&lt;br /&gt;&lt;br /&gt;Ну вот и все. Еще одна страница в отношении "отцов и детей" стала более ясной. По крайней мере в мире информационных технологий, а вот в жизни все намного сложней и одновременно проще!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-3335278142045949442?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/3335278142045949442/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=3335278142045949442' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3335278142045949442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/3335278142045949442'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2007/12/perl-fork.html' title='Отцы и дети или perl, fork и деструкторы'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-5168799698334129821</id><published>2007-12-06T13:27:00.001+02:00</published><updated>2009-08-06T09:14:41.636+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>FastCGI, mod_perl и прочие</title><content type='html'>С января 2001 года сфера моей профессиональной деятельности тесно связна с созданием web-сервисов, в основном аналитических.&lt;br /&gt;&lt;br /&gt;Одной из технологий, используемых в работе, является mod_perl. FastCGI не использовался ни разу. Почему? Как часто отвечают: "по историческим причинам". А вот сейчас решил посмотреть в сторону FastCGI подробней. Специфика нового проекта подразумевает наличие frontend'да, например, nignx. "Нет, проблем", - говорю сам себе: "frontend'ом будет nignx, а backend'ом - Apache". Но не так все просто.&lt;br /&gt;&lt;br /&gt;В рассылке по nignx, до того как было все разложено по полочкам в различных документациях и заметках, часто задавались вопросы по использованию PHP в режиме FastCGI. То есть люди массово избавлялись от Apache mod_php, переходя не FastCGI. При этом, что в тот момент, не знаю как сейчас, патч php-fpm (http://php-fpm.anight.org/) не был включен в официальные исходники, так что многие пользовалось spawn-fcgi от lighttpd.&lt;br /&gt;&lt;br /&gt;Что это? Дань моде или нечто большее? Тем не-менее этот процесс подтолкнул меня посмотреть подробней, какие есть у FastCGI преимущества. Да, я знаю, mod_perl и mod_php координально отличаются в области загрузки кода, но будем считать, что php акселераторы работают хорошо и это не является причиной перехода с mod_php на FastCGI.&lt;br /&gt;&lt;br /&gt;Известно, что процессы Apache с mod_perl очень прожорливы на память. Может с FastCGI ее требуется меньше? Теоретически разница не должна быть слишком большой: ведь под mod_perl можно все используемые модули загрузить до начала создания дочерних процессов.&lt;br /&gt;&lt;br /&gt;Стоп! Если мне не изменяет память, то mod_php так не может! Наверно это и есть причина перехода с mod_php на FastCGI. Хм, но ведь и spawn-fcgi в этом вопросе не помощник...&lt;br /&gt;&lt;br /&gt;Тем не-менее с FastCGI решил разобраться до конца. Прописал в конфиге nignx какой порт слушать и занялся perl. Для perl существует три основных модуля FCGI, FCGI::ProcManager и FCGI::Spawn. (о FCGI::Async и других разговор не ведем). Первый является основным, второй - это менеджер процессов. Третий является надстройкой над первым двумя и предназначен для запуска скриптов через require, то есть является в некотором смысле аналогом Apache::PerlRun, поэтому мы его не рассматриваем.&lt;br /&gt;&lt;br /&gt;Модули FCGI, FCGI::ProcManager являются очень "зрелыми" и все приведенные примеры предназначены для запуска FastCGI из-под "пускалок", а не как самостоятельные, поэтому все примеры слегка модифицируем. Перед основным циклом открываем сокет, который будет слушать nignx:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;use FCGI;&lt;br /&gt;use CGI;&lt;br /&gt;&lt;br /&gt;my $socket = FCGI::OpenSocket(":9000", 5);&lt;br /&gt;my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket);&lt;br /&gt;&lt;br /&gt;my $count = 0;&lt;br /&gt;&lt;br /&gt;while($request-&amp;gt;Accept() &amp;gt;= 0) {&lt;br /&gt;   $count++;&lt;br /&gt;   print &amp;lt;&amp;lt;TEXT;&lt;br /&gt;Content-Type: text/html&lt;br /&gt;&lt;br /&gt;&amp;lt;h1&amp;gt;hello&amp;lt;/h1&amp;gt;&lt;br /&gt;&amp;lt;p&amp;gt;$count&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;hr&amp;gt;&lt;br /&gt;TEXT&lt;br /&gt;&lt;br /&gt;   print "$_ = $ENV{$_}&amp;lt;br&amp;gt;\n" foreach sort keys %ENV;&lt;br /&gt;&lt;br /&gt;   print "&amp;lt;hr&amp;gt;\n";&lt;br /&gt;&lt;br /&gt;   my $query = CGI-&amp;gt;new();&lt;br /&gt;   print "$_ = ", $query-&amp;gt;param($_), "&amp;lt;br&amp;gt;\n" foreach sort $query-&amp;gt;param();&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;FCGI::CloseSocket($socket);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Но это пример имеет большой недостаток: всего лишь один процесс FastCGI.&lt;br /&gt;На помощь приходит модуль FCGI::ProcManager, который создает до основного цикла&lt;br /&gt;заданное количество потомков, выполняющих всю полезную работу по обработке запроса:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;use FCGI;&lt;br /&gt;use FCGI::ProcManager;&lt;br /&gt;use CGI;&lt;br /&gt;&lt;br /&gt;my $proc_manager = FCGI::ProcManager-&amp;gt;new({ n_processes =&amp;gt; 10 });&lt;br /&gt;&lt;br /&gt;my $socket = FCGI::OpenSocket(":9000", 5);&lt;br /&gt;&lt;br /&gt;my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket);&lt;br /&gt;&lt;br /&gt;$proc_manager-&amp;gt;pm_manage();&lt;br /&gt;&lt;br /&gt;my $count = 0;&lt;br /&gt;while($request-&amp;gt;Accept() &amp;gt;= 0) {&lt;br /&gt;   $proc_manager-&amp;gt;pm_pre_dispatch();&lt;br /&gt;   $count++;&lt;br /&gt;   print &amp;lt;&amp;lt;TEXT;&lt;br /&gt;Content-Type: text/html&lt;br /&gt;&lt;br /&gt;&amp;lt;h1&amp;gt;hello&amp;lt;/h1&amp;gt;&lt;br /&gt;&amp;lt;p&amp;gt;$count&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;hr&amp;gt;&lt;br /&gt;TEXT&lt;br /&gt;&lt;br /&gt;   print "$_ = $ENV{$_}&amp;lt;br&amp;gt;\n" foreach sort keys %ENV;&lt;br /&gt;&lt;br /&gt;   print "&amp;lt;hr&amp;gt;\n";&lt;br /&gt;&lt;br /&gt;   my $query = CGI-&amp;gt;new();&lt;br /&gt;   print "$_ = ", $query-&amp;gt;param($_), "&amp;lt;br&amp;gt;\n"&lt;br /&gt;         foreach sort $query-&amp;gt;param();&lt;br /&gt;&lt;br /&gt;   $proc_manager-&amp;gt;pm_post_dispatch();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;FCGI::CloseSocket($socket);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Кстати, если кто знает ответе: в линуксе до сих про плохо с большим количеством&lt;br /&gt;прослушивающих один сокет процессов и проходится перед аccept делать монопольную&lt;br /&gt;блокировку файла "регулировщика"?&lt;br /&gt;&lt;br /&gt;Вернемся к основной теме. В примерах использования FCGI::ProcManager используется модуль CGI::Fast, используя которых вышеприведенный вариант можно привести к следующему виду:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;BEGIN {&lt;br /&gt;$ENV{FCGI_SOCKET_PATH} = ":9000";&lt;br /&gt;$ENV{FCGI_LISTEN_QUEUE} = 5;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;use CGI::Fast;&lt;br /&gt;use FCGI::ProcManager;&lt;br /&gt;&lt;br /&gt;my $proc_manager = FCGI::ProcManager-&amp;gt;new({ n_processes =&amp;gt; 10 });&lt;br /&gt;&lt;br /&gt;$proc_manager-&amp;gt;pm_manage();&lt;br /&gt;&lt;br /&gt;my $count = 0;&lt;br /&gt;&lt;br /&gt;while(my $query = CGI::Fast-&amp;gt;new()) {&lt;br /&gt;   $proc_manager-&amp;gt;pm_pre_dispatch();&lt;br /&gt;&lt;br /&gt;   $count++;&lt;br /&gt;   print &amp;lt;&amp;lt;TEXT;&lt;br /&gt;Content-Type: text/html&lt;br /&gt;&lt;br /&gt;&amp;lt;h1&amp;gt;hello&amp;lt;/h1&amp;gt;&lt;br /&gt;&amp;lt;p&amp;gt;$count&amp;lt;/p&amp;gt;&lt;br /&gt;&amp;lt;hr&amp;gt;&lt;br /&gt;TEXT&lt;br /&gt;&lt;br /&gt;   print "$_ = $ENV{$_}&amp;lt;br&amp;gt;\n" foreach sort keys %ENV;&lt;br /&gt;&lt;br /&gt;   print "&amp;lt;hr&amp;gt;\n";&lt;br /&gt;&lt;br /&gt;   print "$_ = ", $query-&amp;gt;param($_), "&amp;lt;br&amp;gt;\n"&lt;br /&gt;         foreach sort $query-&amp;gt;param();&lt;br /&gt;&lt;br /&gt;   $proc_manager-&amp;gt;pm_post_dispatch();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Теперь рассмотрим фрейморки Catalyst и CGI::Application.&lt;br /&gt;&lt;br /&gt;Для Catalyst создаем новый проект&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;catalyst.pl MyApp&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;и запускаем&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;myapp_fastcgi.pl -listen=localhost:9000 -nproc=10&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Все просто. А вот с CGI::Application немного сложней. Модуль CGI::Application::FastCGI, как оказалось, предназначен для работы из-под "пускалки", поэтому используем не его, а непосредственно FCGI::ProcManager.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;BEGIN {&lt;br /&gt;   $ENV{FCGI_SOCKET_PATH} = ":9000";&lt;br /&gt;   $ENV{FCGI_LISTEN_QUEUE} = 5;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;use WebApp;&lt;br /&gt;use CGI::Fast;&lt;br /&gt;use FCGI::ProcManager;&lt;br /&gt;&lt;br /&gt;my $proc_manager = FCGI::ProcManager-&amp;gt;new({ n_processes =&amp;gt; 10 });&lt;br /&gt;$proc_manager-&amp;gt;pm_manage();&lt;br /&gt;&lt;br /&gt;while(my $query = CGI::Fast-&amp;gt;new()) {&lt;br /&gt;  $proc_manager-&amp;gt;pm_pre_dispatch();&lt;br /&gt;  my $app = WebApp-&amp;gt;new(QUERY =&amp;gt; $query);&lt;br /&gt;  $app-&amp;gt;run();&lt;br /&gt;  $proc_manager-&amp;gt;pm_post_dispatch();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ну вот, с запуском разобрались, теперь посмотрим на использование памяти в реальных условиях. Как и ожидалось выигрыша по памяти почти нет, разумеется, когда Apache собран без излишеств.&lt;br /&gt;&lt;br /&gt;Так что за nignx можно смело ставить либо mod_perl, либо FastCGI. Это когда один скрипт. А когда скриптов несколько и они используют множество общих модулей, то выигрыш варианта с mod_perl очевиден.&lt;br /&gt;&lt;br /&gt;Ну вот пожалуй и все.&lt;br /&gt;&lt;br /&gt;P.S. Если я где-то ошибся в рассуждения, просьба поправить.&lt;br /&gt;&lt;br /&gt;20 декабря 2007, Николай.&lt;br /&gt;&lt;br /&gt;P.P.S&lt;br /&gt;Первоначально опубликовано на &lt;a href="http://kiev.pm.org/?q=node/111"&gt;http://kiev.pm.org/?q=node/111&lt;/a&gt;.&lt;br /&gt;Дату оставил как есть. :-)&lt;br /&gt;В perl коде добавил вызовы pm_pre_dispatch pm_post_dispatch, которые для краткости примеров первоначально удалил.&lt;br /&gt;По адресу &lt;a href="http://kiev.pm.org/?q=node/111"&gt;http://kiev.pm.org/?q=node/111&lt;/a&gt; смотрите ценные замечания, так же оставляйте свои.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-5168799698334129821?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://laziness-impatience-hubris.blogspot.com/feeds/5168799698334129821/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7498141530276954327&amp;postID=5168799698334129821' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5168799698334129821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/5168799698334129821'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2007/12/fastcgi-modperl.html' title='FastCGI, mod_perl и прочие'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7498141530276954327.post-167504913761465472</id><published>2007-12-06T12:00:00.018+02:00</published><updated>2010-11-24T10:29:31.150+02:00</updated><title type='text'>Содержание</title><content type='html'>&lt;a href="/2010/11/ipcmps-message-passing-style-of-inter.html"&gt;IPC::MPS - Message Passing Style of Inter-process communication&lt;/a&gt;&lt;br /&gt;&lt;a href="/2010/10/perl.html"&gt;Почему Perl&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/11/blog-post.html"&gt;"Сегодня без..." - точка, превратившаяся в запятую&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/10/each-return.html"&gt;each и return - опасное соседство&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/10/reduced-map.html"&gt;Reduced map&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/09/url.html"&gt; Url, обработчики и диспетчера&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/08/perl_27.html"&gt;Perl - предотвратить случайное изменение данных&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/08/perl-closure.html"&gt;Perl Closure - последний бастион пал&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/07/perl.html"&gt;Аспектно-ориентированное программирование в Perl&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/07/tailcall-perl5.html"&gt;Tailcall оптимизация в Perl5&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/07/parrot-pir-pasm-l1.html"&gt;Parrot: PIR, PASM и L1&lt;/a&gt;, &lt;a href="/2009/06/rakudo.html"&gt;Скорость Rakudo&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/06/parrot-2009-2002.html"&gt;Parrot 2009 - взгляд с 2002 года&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/06/yaml-perl.html"&gt;Поддержка YAML в Perl&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/06/moose-benchmark-as-swift-as-arrow.html"&gt;Moose Benchmark - as swift as an arrow!&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/06/blog-post_10.html"&gt;Введение в контроль версий&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/06/blog-post.html"&gt;Объекты на замыканиях - надежная защита&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/05/blog-post_27.html"&gt;Сегодня без того - не знаю чего&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/05/return_20.html"&gt;Сегодня без return - выворачиваем наизнанку&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/05/return.html"&gt;Сегодня без return&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/05/2-tail-call.html"&gt;Сегодня без циклов, часть 2 - tail call оптимизаци...&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/05/blog-post.html"&gt;Сегодня без циклов&lt;/a&gt;&lt;br /&gt;&lt;a href="/2009/01/perl6.html"&gt;Гипер-, редакшн- и кроссоператоры в Perl6&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/12/perl5-perl6.html"&gt;"Закрытые объекты" в Perl5 и Perl6&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/11/blog-post.html"&gt;Многоликие объекты&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/11/perl-data-language-page-rank.html"&gt;Использование Perl Data Language для расчета Page Rank&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/10/background-execution-of-subroutines-in.html"&gt;Background execution of subroutines in child processes&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/10/cooking-plain-old-documentation.html"&gt;Cooking Plain Old Documentation&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/10/perl-http.html"&gt;Perl: Асинхронный конвейер HTTP клиентов&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/09/w.html"&gt;О ключике -w замолвите слово&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/06/perl-cooking-warnings.html"&gt;Perl: Cooking warnings&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/05/map.html"&gt;Один нюанс использования map&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/02/perl.html"&gt;Осторожно, Perl!&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/02/perl-json-utf-8.html"&gt;Perl JSON модули с поддержкой UTF-8&lt;/a&gt;&lt;br /&gt;&lt;a href="/2008/01/blog-post.html"&gt;Объекты? Зачем?! Точнее, не всегда. Замыкания!&lt;/a&gt;&lt;br /&gt;&lt;a href="/2007/12/perl-fork.html"&gt;Отцы и дети или perl, fork и деструкторы&lt;/a&gt;&lt;br /&gt;&lt;a href="/2007/12/fastcgi-modperl.html"&gt;FastCGI, mod_perl и прочие&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7498141530276954327-167504913761465472?l=laziness-impatience-hubris.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/167504913761465472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7498141530276954327/posts/default/167504913761465472'/><link rel='alternate' type='text/html' href='http://laziness-impatience-hubris.blogspot.com/2008/10/blog-post.html' title='Содержание'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry></feed>
