<?xml version="1.0" encoding="utf-8"?>
<!-- If you are running a bot please visit this policy page outlining rules you must respect. http://www.livejournal.com/bots/ -->
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:lj="http://www.livejournal.com">
  <id>urn:lj:livejournal.com:atom1:palm_mute</id>
  <title>Polytypic polyrythm</title>
  <subtitle>palm_mute</subtitle>
  <author>
    <name>palm_mute</name>
  </author>
  <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/"/>
  <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom"/>
  <updated>2008-04-08T11:58:04Z</updated>
  <lj:journal username="palm_mute" type="personal"/>
  <link rel="service.feed" type="application/x.atom+xml" href="http://palm-mute.livejournal.com/data/atom" title="Polytypic polyrythm"/>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:15199</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/15199.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=15199"/>
    <title>Reading on continuations</title>
    <published>2008-04-08T11:58:04Z</published>
    <updated>2008-04-08T11:58:04Z</updated>
    <category term="delimcc"/>
    <category term="continuations"/>
    <content type="html">1. &lt;a href="http://okmij.org/ftp/Computation/Continuations.html#tohoku-talk"&gt;Talk: Delimited Continuations in Computer Science and Linguistics&lt;/a&gt;&lt;br /&gt;Презентация О. Киселева и К. Шана, которая популярно объясняет значение терминов continuations, delimited continuations, и показывает, каким образом они относятся к операционным системам и лингвистике. Китайские иероглифы вместо привычных греческих букв смотрятся очень свежо.&lt;br /&gt;&lt;br /&gt;2. &lt;a href="http://www.brics.dk/~danvy/DSc/00_dissertation.pdf"&gt;An Analytical Approach to Programs as Data Objects&lt;/a&gt;&lt;br /&gt;Диссертация Olivier Danvy. Фундаментальная работа по теории языков программирования, рассматриваются вопросы семантики программ, трансформации программ, частичных вычислений, все изложение построено вокруг понятия "continuation". &lt;sup&gt;*&lt;/sup&gt; &lt;br /&gt;&lt;br /&gt;&lt;sup&gt;*&lt;/sup&gt;&lt;small&gt;Я ее еще не осилил, но выглядит как MUST READ. Как минимум, эпиграфы к каждой главе замечательные.&lt;/small&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:14909</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/14909.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=14909"/>
    <title>Coding for food</title>
    <published>2008-03-15T16:52:45Z</published>
    <updated>2008-03-15T16:52:45Z</updated>
    <content type="html">Если вдруг кто не заметил новое сообщество: &lt;span class='ljuser' lj:user='coding4fun_ru' style='white-space: nowrap;'&gt;&lt;a href='http://community.livejournal.com/coding4fun_ru/profile'&gt;&lt;img src='http://p-stat.livejournal.com/img/community.gif' alt='[info]' width='16' height='16' style='vertical-align: bottom; border: 0; padding-right: 1px;' /&gt;&lt;/a&gt;&lt;a href='http://community.livejournal.com/coding4fun_ru/'&gt;&lt;b&gt;coding4fun_ru&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:14664</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/14664.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=14664"/>
    <title>Загадка</title>
    <published>2008-03-05T10:59:17Z</published>
    <updated>2008-03-05T15:01:35Z</updated>
    <category term="c++"/>
    <content type="html">Пришлось по долгу службы вспоминать язык программирования Ц++. До чего же быстро забываются все эти overload resolution'ы, template argument deduction'ы, one definition rule'ы, 2-phase name lookup'ы и пр. без активного использования.&lt;br /&gt;&lt;a name="cutid1"&gt;&lt;/a&gt;&lt;br /&gt;Рассмотрим код единицы трансляции ниже:&lt;br /&gt;&lt;pre&gt;
#include &amp;lt;iostream&amp;gt;

template &amp;lt;class T&amp;gt;
void f()
{
    std::cerr &amp;lt;&amp;lt; "yo whazzup" &amp;lt;&amp;lt; std::endl;
}

void g()
{
    f&amp;lt;int&amp;gt;();
}
&lt;/pre&gt;&lt;br /&gt;Рассмотрели? Кто может, не подглядывая в "C++ Templates: The Complete Guide" или в &lt;strike&gt;священную корову&lt;/strike&gt; Стандарт, вообразить ситуацию, в которой замена void на int в объявлении шаблона функции f влияет на вывод функции g?&lt;br /&gt;Дополнение: в коде данной единицы трансляции ничего менять нельзя (кроме типа возвращаемого значения f, естественно).&lt;br /&gt;&lt;br /&gt;з.ы. совсем не исключаю, что это все знают, а я один такой деревянный; но язык, в котором такое возможно, - это кошмар, по-моему.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update&lt;/b&gt;.&lt;br /&gt;Внимание, &lt;a name="cutid2"&gt;&lt;/a&gt; правильный ответ:&lt;br /&gt;&lt;br /&gt;Я старался формулировать осторожно, потому надеюсь, что ни для кого не будет сюрпризом, что в загадке приведен не весь код - а именно, опущен код еще одной единицы трансляции (слово "ситуация" подразумевало такую возможность). Предположим, что код из загадки находится в файле b.cpp, а код ниже - в файле a.cpp&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
#include &lt;font color="#bc8f8f"&gt;&amp;lt;iostream&amp;gt;&lt;/font&gt;

&lt;font color="#a020f0"&gt;template&lt;/font&gt; &amp;lt;&lt;font color="#a020f0"&gt;class&lt;/font&gt; &lt;font color="#228b22"&gt;T&lt;/font&gt;&amp;gt;
&lt;font color="#228b22"&gt;void&lt;/font&gt; &lt;font color="#0000ff"&gt;f&lt;/font&gt;()
{
    &lt;font color="#5f9ea0"&gt;std&lt;/font&gt;::cerr &amp;lt;&amp;lt; &lt;font color="#bc8f8f"&gt;"surprise!"&lt;/font&gt; &amp;lt;&amp;lt; &lt;font color="#5f9ea0"&gt;std&lt;/font&gt;::endl;
}

&lt;font color="#a020f0"&gt;template&lt;/font&gt; &lt;font color="#228b22"&gt;void&lt;/font&gt; &lt;font color="#228b22"&gt;f&lt;/font&gt;&amp;lt;&lt;font color="#228b22"&gt;int&lt;/font&gt;&amp;gt;();

&lt;font color="#228b22"&gt;void&lt;/font&gt; &lt;font color="#0000ff"&gt;g&lt;/font&gt;();

&lt;font color="#228b22"&gt;int&lt;/font&gt; &lt;font color="#0000ff"&gt;main&lt;/font&gt; (&lt;font color="#228b22"&gt;int&lt;/font&gt; &lt;font color="#b8860b"&gt;argc&lt;/font&gt;, &lt;font color="#228b22"&gt;char&lt;/font&gt;* &lt;font color="#b8860b"&gt;argv&lt;/font&gt;[])
{    
    g();
    &lt;font color="#a020f0"&gt;return&lt;/font&gt; 0;
}
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Программа, скомпилированная командой g++ a.cpp b.cpp (g++ (GCC) 4.1.2 (Ubuntu 4.1.2-0ubuntu4)) печатает "yo whazzup" или "surprise!" в зависимости от типа возвращаемого значения шаблона функции f, определенного в b.cpp.&lt;br /&gt;Я понимаю это так: в разделе 12.2.1 книги "C++ Templates: The Complete Guide" (думаю, можно найти объяснение, основываясь прямо на тексте стандарта, но мне лень) перечисляются случаи, при которых в C++ могут сосуществовать в одной программе одноименные функции. Ключевая фраза: &lt;br /&gt;&lt;i&gt;"Two functions can coexist in a program if they have distinct signatures. We define the signature of a function as the following information: ... Its return type, if the function is generated from a function template"&lt;/i&gt;. Таким образом, определение шаблонов &lt;b&gt;template &amp;lt;class T&amp;gt; void f()&lt;/b&gt; в обеих единицах трансляции нарушает one definition rule, что приводит к Undefined Behaviour. g++ имел право в этом случае залить соседей или вызвать ОМОН, но он просто вызвал ту функцию, которая ему больше понравилась.&lt;br /&gt;Пусть знающие товарищи меня поправят.&lt;br /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:14538</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/14538.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=14538"/>
    <title>Опять барабанщики</title>
    <published>2008-02-27T13:54:31Z</published>
    <updated>2008-02-27T13:54:31Z</updated>
    <category term="show"/>
    <category term="music"/>
    <content type="html">&lt;a href="http://www.youtube.com/watch?v=KFtc_rpg-Wg"&gt;http://www.youtube.com/watch?v=KFtc_rpg-Wg&lt;/a&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:14305</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/14305.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=14305"/>
    <title>Юный барабанщик</title>
    <published>2008-02-22T15:02:43Z</published>
    <updated>2008-02-22T15:02:43Z</updated>
    <category term="music"/>
    <content type="html">&lt;a href="http://www.youtube.com/watch?v=b8TSsiD_ozY"&gt;http://www.youtube.com/watch?v=b8TSsiD_ozY&lt;/a&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:14079</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/14079.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=14079"/>
    <title>лингвистическое</title>
    <published>2008-01-10T15:17:54Z</published>
    <updated>2008-01-10T15:17:54Z</updated>
    <content type="html">"doesn't cut it" переводится как "не катит"</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:13058</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/13058.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=13058"/>
    <title>Опрос</title>
    <published>2007-11-25T10:14:13Z</published>
    <updated>2007-11-25T10:14:13Z</updated>
    <category term="teaching"/>
    <category term="survey"/>
    <category term="functional"/>
    <content type="html">Уважаемые друзья!&lt;br /&gt;Если бы вас коллеги-программисты попросили повести пару лекций о функциональном программировании, что бы вы рассказали? Первую главу SICP? "Why FP matters" Хьюза? Что-то еще?</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:13016</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/13016.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=13016"/>
    <title>Монады и continuations (shift/reset part 1.5)</title>
    <published>2007-11-21T18:31:39Z</published>
    <updated>2007-11-23T21:32:45Z</updated>
    <category term="tutorial"/>
    <category term="delimcc"/>
    <category term="continuations"/>
    <content type="html">&lt;h2&gt;In America, you execute a program.&lt;br /&gt;In Soviet Russia, a program executes you!&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;При реализации DSL часто нужна зависимость выражения от&lt;br /&gt;контекста. Нам часто требуется, чтобы что-то происходило за&lt;br /&gt;кулисами. Например, в комбинаторах парсеров состояние парсера —&lt;br /&gt;текущий фрагмент входной строки — передается неявно, и это удобно.&lt;br /&gt;&lt;a name="cutid1"&gt;&lt;/a&gt;&lt;br /&gt;В монаде State за кулисами протаскивается глобальное состояние.&lt;br /&gt;&lt;br /&gt;В монаде List недетерминизм является также неявным, каждая строка&lt;br /&gt;зависит от предыдущих.&lt;br /&gt;&lt;br /&gt;Ключевой идеей для введения такой зависимости от контекста является&lt;br /&gt;инверсия потока управления. Для этого у нас в распоряжении имеется 2&lt;br /&gt;варианта.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Пишем в ивертированном стиле сами&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;При использовании библиотек комбинаторов программа собирается из&lt;br /&gt;множества маленьких функций, соединяемых в одно целое при помощи&lt;br /&gt;библиотечных комбинаторов. В типичном выражении вида f&lt;br /&gt;`magicCombinator` g именно magicCombinator решает, когда и сколько раз&lt;br /&gt;вызывать функции f и g (потому это и является примером инверсии&lt;br /&gt;управления).&lt;br /&gt;&lt;br /&gt;Примерами этого подхода являются монадный стиль, continuation-passing style,&lt;br /&gt;ленивые потоки из SICP.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Используем continuations&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Если выбранный язык программирования поддерживает delimited&lt;br /&gt;continuations, нам не нужно разбивать сложное выражение на множество&lt;br /&gt;маленьких функций, связанных комбинаторами. Мы можем прервать процесс&lt;br /&gt;вычисления сложного выражения в любой момент, захватив текущий&lt;br /&gt;контекст (стек вызовов, то что осталось вычислить), а затем вызвать&lt;br /&gt;захваченный контекст как функцию:&lt;br /&gt;(some..big..expression .. (capture_context ctx (magicCombinator ctx))&lt;br /&gt;..)&lt;br /&gt;&lt;br /&gt;Имея в распоряжении continuations, мы можем реализовать любую монаду.&lt;br /&gt;&lt;br /&gt;Пример: монада State&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
;; magic happens here
(define (reflect ma)
  (shift k (bind ma k)))

;; ordinary State monad operations, copied verbatim from Haskell's

(define (return x)
  (lambda (s) (cons x s)))

(define (bind m f)
  (lambda (s)
    (let* ((as1 (m s))
           (a (car as1))
           (s1 (cdr as1)))
      ((f a) s1))))

(define (put x)
  (reflect (lambda (_) (cons (void) x))))

(define (get)
  (reflect (lambda (s) (cons s s))))

(define (run-state m s0)
  ((reset (return (m))) s0))

;; tests

(define (test0) 45)

(define (test1)
  (let ((x (get)))
    (begin
      (put (+ x 5))
      (put (+ (get) (get)))
      0)))

(run-state test0 10) ;; prints (45 . 10)
(run-state test1 10) ;; prints (0 . 30)
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Ссылки&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.diku.dk/~andrzej/papers/RM-abstract.html"&gt;Representing Monads by A. Filinski&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://rsdn.ru/forum/Default.aspx?mid=2737988"&gt;То же на РСДН, с обсуждением&lt;/a&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:12698</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/12698.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=12698"/>
    <title>Металлисты под микроскопом</title>
    <published>2007-10-31T09:35:27Z</published>
    <updated>2007-10-31T09:35:27Z</updated>
    <category term="music"/>
    <category term="мясо"/>
    <category term="meshuggah"/>
    <category term="fun"/>
    <content type="html">Музыкальные теоретики изучают творчество Meshuggah.&lt;br /&gt;"Re-casting Metal: Rhythm and Meter in the Music of Meshuggah" by Jonathan Pieslak:&lt;br /&gt;&lt;a href="http://caliber.ucpress.net/doi/abs/10.1525/mts.2007.29.2.219?journalCode=mts"&gt;Abstract&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.sendspace.com/file/199z1q"&gt;Полный текст (sendspace.com)&lt;/a&gt;&lt;br /&gt;Забавно.&lt;br /&gt;via &lt;span class='ljuser' lj:user='ru_meshuggah' style='white-space: nowrap;'&gt;&lt;a href='http://community.livejournal.com/ru_meshuggah/profile'&gt;&lt;img src='http://p-stat.livejournal.com/img/community.gif' alt='[info]' width='16' height='16' style='vertical-align: bottom; border: 0; padding-right: 1px;' /&gt;&lt;/a&gt;&lt;a href='http://community.livejournal.com/ru_meshuggah/'&gt;&lt;b&gt;ru_meshuggah&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:12291</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/12291.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=12291"/>
    <title>shift/reset для самых маленьких, часть 1</title>
    <published>2007-10-28T17:38:01Z</published>
    <updated>2007-10-28T21:57:02Z</updated>
    <category term="tutorial"/>
    <category term="delimcc"/>
    <category term="scheme"/>
    <category term="continuations"/>
    <content type="html">Как оказалось, я задумал написать больше, чем способен в ближайшее время. &lt;br /&gt;Потому принято решение выкладывать текст по частям. Приступим:&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Введение&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;  Мы познакомимся с очень мощным и опасным инструментом управления&lt;br /&gt;  ходом программы - delimited continuations, а точнее, с операторами&lt;br /&gt;  shift/reset. Творческое применение shift/reset открывает куда&lt;br /&gt;  большие возможности по запутыванию программ, чем могло бы сниться&lt;br /&gt;  несчастному goto. Но с другой стороны, continuations можно применять&lt;br /&gt;  и в мирных целях, причем в тех областях, где continuations&lt;br /&gt;  действительно нужны, их очень трудно чем-либо заменить. В конце&lt;br /&gt;  концов, о delimited continuations в последнее время довольно много&lt;br /&gt;  пишут, потому любому, кто интересуется теоретической информатикой,&lt;br /&gt;  полезно иметь представление об этом звере.&lt;br /&gt;&lt;br /&gt;  &lt;a name="cutid1"&gt;&lt;/a&gt;&lt;br /&gt;  Изложение будет неформальным, по возможности - "на пальцах", в&lt;br /&gt;  случае необходимости будут применяться не совсем корректные&lt;br /&gt;  аналогии: наша цель - интуитивное понимание предмета, за&lt;br /&gt;  математической строгостью всегда можно обратиться к статьям.&lt;br /&gt;&lt;br /&gt;  О терминологии: русскоязычной литературы по теме я не встречал,&lt;br /&gt;  потому термины "continuations", "delimited (partial, composable,&lt;br /&gt;  sub-) continuations" оставляю без перевода.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Prerequisites&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;  Большинство примеров кода будет на Scheme.&lt;br /&gt;  Язык Scheme выбран по следующим причинам:&lt;br /&gt;&lt;br /&gt;  1) родная поддержка  интересующих нас операторов call/cc и&lt;br /&gt;  shift/reset.&lt;br /&gt;&lt;small&gt;&lt;br /&gt; Все примеры будут работать в MzScheme 371, если&lt;br /&gt; предварительно импортировать модуль "control.ss": &lt;br /&gt;&lt;pre&gt;
(require (lib "control.ss"))
&lt;/pre&gt;&lt;br /&gt;&lt;/small&gt;&lt;br /&gt;&lt;br /&gt;  2) динамическая  типизация (типизация continuations - это отдельная&lt;br /&gt;  тема, которой бы  не хотелось сейчас касаться).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Контексты и стеки вызова&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt; Любое выражение (или инструкция) в программе вычисляется с какой-то&lt;br /&gt; целью. Влияние,  которое оказывает вычисление выражения на результат&lt;br /&gt; программы в целом, зависит от контекста. Например, одно и то же&lt;br /&gt; выражение "1" имеет различный эффект в различных контекстах:&lt;br /&gt;&lt;pre&gt;
// example 1

int i=1;            // 1
printf("i=%d\n", i);
exit(1);            // 2
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  Контекст, в котором вычисляется выражение, называют&lt;br /&gt;  continuation. Грубо говоря, continuation - это стек вызовов &lt;br /&gt;  в данной точке программы.&lt;br /&gt;&lt;br /&gt;  В традиционных языках (например, Java), прямого доступа к стеку&lt;br /&gt;  вызовов у программиста нет, стек вызовов используется специальными&lt;br /&gt;  управляющими операторами. Например, инструкция "return 5;" возвращает&lt;br /&gt;  управление в точку, из которой была вызвана функция, заменяя вызов&lt;br /&gt;  функции значением 5, адрес возврата определяется вершиной стека&lt;br /&gt;  вызовов. Инструкция "throw new SomeException();" &lt;br /&gt;  "разматывает" стек вызовов до первого подходящего блока catch,&lt;br /&gt;  передавая ему объект исключения.&lt;br /&gt;&lt;br /&gt;  Если бы программист имел доступ к стеку вызовов, он мог бы&lt;br /&gt;  самостоятельно реализовать операторы, подобные return или&lt;br /&gt;  throw/catch.&lt;br /&gt;  &lt;br /&gt;  В языке Scheme для этого существует оператор call-with-current-continuation, или call/cc.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;call/cc&lt;/h2&gt;&lt;br /&gt;  Оператор call/cc захватывает текущий контекст (стек вызовов) и&lt;br /&gt;  передает его функции, которая передается оператору call/cc как&lt;br /&gt;  аргумент:&lt;br /&gt;&lt;pre&gt;
    (call/cc (lambda (cont) expression))
&lt;/pre&gt;&lt;br /&gt;  cont - это контекст, в котором вычисляется выражение&lt;br /&gt;  (call/cc ...). Синтаксически вызов continuation выглядит как вызов&lt;br /&gt;  функции, но в отличие от вызова функции, управление из вызова&lt;br /&gt;  continuation не возвращается - точно так же, как не возвращается&lt;br /&gt;  управление из инструкций return или throw в Java. Вызов (cont x)&lt;br /&gt;  в теле expression  немедленно передает управление программе в точку &lt;br /&gt;  после вызова call/cc, и все выражение принимает значение x. Если в&lt;br /&gt;  теле expression обращения к cont не происходит, вычисление выражения&lt;br /&gt;  expression завершается обычным образом, и его значение&lt;br /&gt;  становится значением всего выражения, завернутого в call/cc.&lt;br /&gt;  &lt;br /&gt;  Рассмотрим пример. В фрагменте кода на языке C, приведенном ниже,&lt;br /&gt;  функция div может завершиться "нормально", или, если y=0,&lt;br /&gt;  "аварийно":&lt;br /&gt;&lt;pre&gt;
// example 2

int div(int x, int y)
{
    if (y==0)
        return 0;
    return x/y;
}

void call_site()
{
...
    int a = div(7, 3);
    int b = div(1, 0);
...
}
&lt;/pre&gt;&lt;br /&gt;  Ниже приведен аналогичный код на Scheme. Для аварийного выхода из&lt;br /&gt;  функции div используется call/cc:&lt;br /&gt;&lt;pre&gt;
;; example 2

(define (div x y)
  (call/cc (lambda (return)
             (if (= y 0)
                 (return 0)
                 (/ x y)))))

(define (call-site)
  (let ([a (div 7 3)]
        [b (div 1 0)])
    ...))
&lt;/pre&gt;&lt;br /&gt; &lt;br /&gt;В следующем примере call/cc используется для досрочного выхода из&lt;br /&gt;функции for-each, благодаря чему мы можем определить функцию find,&lt;br /&gt;которая находит первый элемент списка, удовлетворяющий условию:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
;; example 3

(define (find pred xs)
  (call/cc (lambda (return)
             (begin
               (for-each (lambda (x) (when (pred x) (return x))) xs)
               #f))))

(define test-find
  (find odd? (list 2 4 8 19 10 14 13))) ;; возвращает 19
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt; Возможности call/cc не ограничиваются досрочным выходом из функции, в&lt;br /&gt; сети можно найти множество головоломных примеров применения call/cc в&lt;br /&gt; сочетании с set!, с помощью которых реализуют "зеленые потоки",&lt;br /&gt; интерактивные веб-страницы и т.д. Мы не будем вдаваться здесь в&lt;br /&gt; подробности, заметим лишь, что применение изменяемого состояния в&lt;br /&gt; связке с call/cc является признаком эмуляции delimited continuations.&lt;br /&gt;&lt;br /&gt; Проблема оператора call/cc - он захватывает весь стек вызовов, в то&lt;br /&gt; время как в большинстве интересных случаев нам нужен лишь его фрагмент.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Знакомимся с shift/reset&lt;/h2&gt;&lt;br /&gt;  &lt;br /&gt;  Если мы хотим захватывать фрагменты стека вызовов, нам нужен способ&lt;br /&gt;  обозначать нужную его часть. Для обозначения границы интересующего&lt;br /&gt;  нас контекста служит оператор reset. Если в области действия&lt;br /&gt;  оператора reset не происходит обращения к оператору shift, reset не&lt;br /&gt;  имеет никакого эффекта: выражение (reset 1) равносильно просто 1,&lt;br /&gt;  (reset (+ 1 2 3)) равносильно (+ 1 2 3). (Аналогично, при применении&lt;br /&gt;  call/cc, если вызова continuation не происходит, call/cc не имеет&lt;br /&gt;  эффекта, (call/cc (lambda (k) 1)) принимает значение 1).&lt;br /&gt;&lt;br /&gt;  &lt;small&gt;&lt;br /&gt;  Примечание: в тексте ниже мы будем называть reset-выражением&lt;br /&gt;  выражение вида (reset ...), а shift-выражением - выражение вида&lt;br /&gt;  (shift k ...)&lt;br /&gt;  &lt;/small&gt;&lt;br /&gt;&lt;br /&gt;  Все становится значительно интереснее при наличии оператора shift.&lt;br /&gt;  Выражение (shift k body):&lt;br /&gt;  1) Захватывает фрагмент стека вызовов вплоть до ближайшего&lt;br /&gt;  окружающего reset и присваивает его идентификатору k.&lt;br /&gt;&lt;br /&gt;  2) Прерывает выполнение текущего контекста до ближайшего reset,&lt;br /&gt;  значением всего reset-выражения становится body.&lt;br /&gt;&lt;br /&gt;  3) В body можно обращаться к захваченному контексту k как к функции&lt;br /&gt;  произвольное число раз.&lt;br /&gt;&lt;br /&gt;  Здесь, конечно, необходимы примеры:&lt;br /&gt;&lt;pre&gt;
;; example 4
(reset (+ 10 (shift k 17))) ;; 17
&lt;/pre&gt;&lt;br /&gt;  В последнем примере контекстом вычисления выражения (shift k 17)&lt;br /&gt;  является (+  10 [*]), символом [*] мы обозначим "дыру". Другими&lt;br /&gt;  словами, k принимает  значение (lambda (x) (+ 10 x)). Но т.к. в теле&lt;br /&gt;  оператора shift мы ни разу не вызываем функцию k, контекст&lt;br /&gt;  игнорируется, и значением всего выражения становится 17.&lt;br /&gt;&lt;pre&gt;
;; example 5
(reset (+ 10 (shift k (k 17)))) ;; 27
&lt;/pre&gt;&lt;br /&gt;  example 5 отличается от example 4 тем, что после захвата контекста&lt;br /&gt;  мы сразу его вызываем. т.к. k = (lambda (x) (+ 10 x)), тело&lt;br /&gt;  оператора shift и, следовательно, все выражение принимает значение&lt;br /&gt;  27. Обратите внимание, выражение (shift k (k something)) всегда будет&lt;br /&gt;  равносильно просто something, потому код в example 5 равносилен&lt;br /&gt;&lt;pre&gt;
(+ 10 17)
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
;; example 6

  (let ([xs (reset
             (+ 1 (shift k
                         (list (k 10)
                               (k 20)
                               (k 30)))))]) ;; (11 21 31)
    (for-each (lambda (x) (display (format "~a\n" x))) xs))
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;В примере 6 мы видим, что захваченный контекст можно использовать как&lt;br /&gt;обычную функцию, которую можно вызывать несколько раз. Контекст&lt;br /&gt;выражения (shift k (list (k 10) (k 20) (k 30))) до reset выглядит так:&lt;br /&gt;&lt;pre&gt;
(+ 1 [*])
&lt;/pre&gt;&lt;br /&gt;k принимает значение (lambda (x) (+ 1 x)), результатом вычисления&lt;br /&gt;reset-выражения становится список (11 21 31), который затем присваивается&lt;br /&gt;переменной xs и элементы которого печатаются в консоли.&lt;br /&gt;&lt;br /&gt;При работе с shift/reset полезно думать о двух видах&lt;br /&gt;контекстов. Во-первых, контекст вычисления reset-выражения, который в&lt;br /&gt;примере 6 выглядит так:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
(let ([xs [*]])
    (for-each (lambda (x) (display (format "~a\n" x))) xs))
&lt;/pre&gt;&lt;br /&gt;Из этого контекста видно, что переменная xs используется, как список -&lt;br /&gt;следовательно, reset-выражение при вычислении должно возвращать список.&lt;br /&gt;&lt;br /&gt;Тело shift-выражения (list (k 10) (k 20) (k 30)) тоже возвращает&lt;br /&gt;список - именно этот список становится значением всего&lt;br /&gt;reset-выражения.&lt;br /&gt;&lt;br /&gt;Во-вторых, контекст, который захватывается оператором shift, в данном&lt;br /&gt;случае это (+ 1 [*]). Чтобы из этого контекста получить осмысленное&lt;br /&gt;выражение, на месте "дырки" нужно подставить число. При каждом из&lt;br /&gt;вызовов (k 10), (k 20), (k 30) аргумент функции k подставляется на&lt;br /&gt;место "дырки", получается эффект многократных возвратов из shift-выражения.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Генерируем последовательности&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;  При помощи shift/reset легко определить операции, подобные оператору&lt;br /&gt;  yield в языке Python.&lt;br /&gt;&lt;br /&gt;  Рассмотрим выражение (reset null). Его значением будет, очевидно,&lt;br /&gt;  null - пустой список. Усложним:&lt;br /&gt;&lt;br /&gt;  &lt;pre&gt;
    ;; example 7
    (reset
        (begin
            (shift k (cons 1 (k (void)))) ;; (1)
            null))
  &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  Оператор shift на строке (1) захватывает текущий контекст k вплоть&lt;br /&gt;  до ближайшего reset. Захваченный контекст можно представить в виде выражения с дырой:&lt;br /&gt;  &lt;pre&gt;
    (begin
        [*]
        null)
  &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  Как  обычно при работе с delimited continuations, нужно определить:&lt;br /&gt;  1) что k принимает на вход&lt;br /&gt;  2) что k возвращает&lt;br /&gt;  3) что станет значением всего reset-выражения&lt;br /&gt;&lt;br /&gt;  Если мы попробуем подставить произвольные выражения на место дыры в&lt;br /&gt;  контексте, мы увидим, что их значения игнорируются - в любом случае&lt;br /&gt;  получим null. Значит, continuation k игнорирует свой аргумент,&lt;br /&gt;  потому мы будем вызывать его с (void) в качестве аргумента.&lt;br /&gt;&lt;br /&gt;  Таким образом, k принимает (void) и возвращает список - в данном&lt;br /&gt;  случае null. Значением выражения (cons 1 (k (void))) будет список&lt;br /&gt;  из одного элемента: (list 1). Т.к. тело оператора shift определяет&lt;br /&gt;  значение всего reset-выражения, значением всего выражения в примере 7 &lt;br /&gt;  будет тоже (list 1).&lt;br /&gt;&lt;br /&gt;  Еще раз усложним исходный пример:&lt;br /&gt;  &lt;pre&gt;
    ;; example 8
    (reset
        (begin
            (shift k (cons 1 (k (void)))) ;; (1)
            (shift k (cons 2 (k (void)))) ;; (2)
            null))
  &lt;/pre&gt;&lt;br /&gt;  Если закомментировать строку (1), мы получим выражение, процесс вычисления&lt;br /&gt;  которого мы только что разобрали - возвращаемым значением будет&lt;br /&gt;  (list 2). Потому example 8 можно переписать:&lt;br /&gt;  &lt;pre&gt;
    (reset
        (begin
            (shift k (cons 1 (k (void)))) ;; (1)
            (list 2)))
  &lt;/pre&gt;&lt;br /&gt;  Форма полученного выражения нам уже знакома. Повторяя рассуждения,&lt;br /&gt;  проделанные для example 7, получим значение example 8: (list 1 2)&lt;br /&gt;&lt;br /&gt;  Теперь мы можем определить оператор для построения списков:&lt;br /&gt;  &lt;pre&gt;
  (define (yield x) (shift k (cons x (k (void)))))
  &lt;/pre&gt;&lt;br /&gt;  В контексте выражения, возвращающего список, yield x добавляет x в&lt;br /&gt;  голову этого списка. Пример:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
 ;; example 9
  (reset (begin
           (yield 1)
           (yield 2)
           (yield 3)
           null))    ;; (list 1 2 3)
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  Пользуясь yield и for-each, мы можем написать свою версию функции&lt;br /&gt;  map:&lt;br /&gt;&lt;pre&gt;
 ;; example 10

 (define (my-map f xs)
  (reset (begin
           (for-each (lambda (x) (yield (f x))) xs)
           null)))

(define (test)
  (my-map 1+ (list 1 2 3)))  ;; (list 2 3 4)
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  Если в определении yield заменить cons на stream-cons, мы сможем&lt;br /&gt;  генерировать ленивые потоки:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
;; example 11

(define (stream-yield x) (shift k (stream-cons x (k (void)))))

(define example3
  (reset (begin
           (stream-yield 1)
           (stream-yield 2)
           (stream-yield 3)
           stream-null)))
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;small&gt;&lt;br /&gt;Примечание: в MzScheme библиотека потоков, в которой определены&lt;br /&gt;stream-cons и stream-null, импортируется строчкой&lt;br /&gt;&lt;pre&gt;
(require (lib "40.ss" "srfi"))
&lt;/pre&gt;&lt;br /&gt;&lt;/small&gt;&lt;br /&gt;&lt;br /&gt;  Теперь можно определить функцию, преобразующую список в поток:&lt;br /&gt;&lt;pre&gt;
;; example 12

(define (list-&amp;gt;stream xs)
  (reset (begin
           (for-each stream-yield xs)
           stream-null)))
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  Обход дерева и получение списка/потока узлов остается в качестве&lt;br /&gt;  упражнения читателю.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Ссылки&lt;/h2&gt;&lt;br /&gt;&lt;a href="http://www.cs.rutgers.edu/~ccshan/zipper/context2007.pdf"&gt;&lt;br /&gt;Delimited continuations in operating systems&lt;/a&gt;, Oleg Kiselyov,&lt;br /&gt;Chung-chieh Shan&lt;br /&gt;&lt;a href="http://www.cs.rutgers.edu/~ccshan/recur/recur-hosc-final.pdf"&gt;&lt;br /&gt;A static simulation of dynamic delimited control&lt;/a&gt;, Chung-chieh Shan&lt;br /&gt;&lt;a href="http://community.schemewiki.org/?call-with-current-continuation"&gt;&lt;br /&gt;A short introduction to call-with-current-continuation&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://community.schemewiki.org/?composable-continuations-tutorial"&gt;&lt;br /&gt;Composable continuations tutorial&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;To be continued&lt;/h2&gt;&lt;br /&gt;Не исключено, что продолжение следует. В следующих частях: RAII своими&lt;br /&gt;руками, True Inversion of Control, недетерминированные конечные&lt;br /&gt;автоматы.&lt;br /&gt;&lt;br /&gt;Спасибо за внимание.&lt;br /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:12045</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/12045.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=12045"/>
    <title>хорошо быть буддой</title>
    <published>2007-10-22T16:49:27Z</published>
    <updated>2007-10-27T00:40:07Z</updated>
    <category term="lytdybr"/>
    <category term="continuations"/>
    <content type="html">В неустанной борьбе с research papers, в стремлении понять наконец-то, о чем же пишет Олег Киселев и компания, достигнута важная веха: я понял, как работают операторы shift/reset, получил смутное представление о delimited (они же partial, composable, sub-) continuations вообще, и о том, что можно делать с их помощью. Например, как можно реализовать "зеленые" потоки, обмен сообщениями в духе Эрланга, Питоно-подобные генераторы и изменяемые переменные. Возможно, если соберусь с духом и кому-то будет интересно, напишу мини-туториал.&lt;br /&gt;&lt;br /&gt;Update. Спасибо всем за проявленный интерес, попробую оправдать ожидания&lt;br /&gt;&lt;br /&gt;Update 2. Товарищ верь, придет она. Я об обещаниях не забыл, план и примеры кода готовы, текст в процессе.</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:11790</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/11790.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=11790"/>
    <title>Geek humor</title>
    <published>2007-09-27T08:34:49Z</published>
    <updated>2007-09-27T08:34:49Z</updated>
    <content type="html">Из хаскелл-кафе:&lt;br /&gt;&lt;q&gt;&lt;br /&gt;&amp;gt; Salary  will be  within the  range 25,134  - 32,796  pounds  per year,&lt;br /&gt;&amp;gt; depending  on qualifications  and experience.   The post  is available&lt;br /&gt;&amp;gt; immediately, and will be offered on a fixed-term contract for 3 years.&lt;br /&gt;&lt;br /&gt;I don't mean to diminish the seriousness of your message, but why is&lt;br /&gt;the salary range so exact? Couldn't you have just rounded the upper&lt;br /&gt;bound to 32,768 for the sake of readability?&lt;br /&gt;&lt;/q&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:11669</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/11669.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=11669"/>
    <title>Хозяйке на заметку</title>
    <published>2007-08-31T13:35:09Z</published>
    <updated>2007-09-03T12:49:15Z</updated>
    <category term="tips"/>
    <category term="haskell"/>
    <content type="html">ghci иногда печатает трудночитаемую кашу:&lt;br /&gt;&lt;pre&gt;
Prelude&amp;gt; :m +Data.List
Prelude Data.List&amp;gt; tails $ tails [0..5]
[[[0,1,2,3,4,5],[1,2,3,4,5],[2,3,4,5],[3,4,5],[4,5],[5],[]],[[1
,2,3,4,5],[2,3,4,5],[3,4,5],[4,5],[5],[]],[[2,3,4,5],[3,4,5],[4,
5],[5],[]],[[3,4,5],[4,5],[5],[]],[[4,5],[5],[]],[[5],[]],[[]],[]]
&lt;/pre&gt;&lt;br /&gt;&lt;a name="cutid1"&gt;&lt;/a&gt;&lt;br /&gt;По-моему, гораздо лучше читается это:&lt;br /&gt;&lt;pre&gt;
Prelude Data.List&amp;gt; :m + IPPrint
Prelude Data.List IPPrint&amp;gt; pprint $ tails $ tails [0..5]
    [[[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [2, 3, 4, 5], [3, 4, 5],
      [4, 5], [5], []],
     [[1, 2, 3, 4, 5], [2, 3, 4, 5], [3, 4, 5], [4, 5], [5], []],
     [[2, 3, 4, 5], [3, 4, 5], [4, 5], [5], []],
     [[3, 4, 5], [4, 5], [5], []], [[4, 5], [5], []], [[5], []], [[]],
     []]
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Вот еще более убедительный пример:&lt;br /&gt;&lt;pre&gt;
Prelude IPPrint Language.Haskell.Parser&amp;gt; parseModule "x=x"
ParseOk (HsModule (SrcLoc {srcFilename = "&lt;unknown&gt;", srcLine = 1, srcColumn = 1
}) (Module "Main") (Just [HsEVar (UnQual (HsIdent "main"))]) [] [HsPatBind (SrcL
oc {srcFilename = "&lt;unknown&gt;", srcLine = 1, srcColumn = 1}) (HsPVar (HsIdent "x"
)) (HsUnGuardedRhs (HsVar (UnQual (HsIdent "x")))) []])
&lt;/pre&gt;&lt;br /&gt;vs&lt;br /&gt;&lt;pre&gt;
Prelude IPPrint Language.Haskell.Parser&amp;gt; pprint $ parseModule "x=x"
    ParseOk
      (HsModule
         (SrcLoc{srcFilename = "&lt;unknown&gt;", srcLine = 1, srcColumn = 1})
         (Module "Main")
         (Just [HsEVar (UnQual (HsIdent "main"))])
         []
         [HsPatBind
            (SrcLoc{srcFilename = "&lt;unknown&gt;", srcLine = 1, srcColumn = 1})
            (HsPVar (HsIdent "x"))
            (HsUnGuardedRhs (HsVar (UnQual (HsIdent "x"))))
            []])
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Граждане, &lt;strike&gt; которые приобретут Visual Studio Team System и Team Foundation Server в предложенных типовых минимальных конфигурациях (или аналогичных по цене)&lt;/strike&gt; которые скачают файлик [1] и установят обычной процедурой "runhaskell Setup.hs configure &amp;&amp; runhaskell Setup.hs build &amp;&amp; runhaskell Setup.hs install" смогут pprint'ить что душе угодно (есть ограничение - выхлоп функции show должен быть синтаксически корректным Haskell-выражением).&lt;br /&gt;&lt;br /&gt;[1]&lt;a href="http://files.rsdn.ru/11829/ipprint-0.2.tar.gz"&gt;ipprint-0.2.tar.gz&lt;/a&gt;&lt;br /&gt;Update: благодаря Spenser'у Janssen'у (которому, собственно, принадлежит идея) ipprint теперь на Hackage:&lt;br /&gt;&lt;a href="http://hackage.haskell.org/cgi-bin/hackage-scripts/package/ipprint"&gt;http://hackage.haskell.org/cgi-bin/hackage-scripts/package/ipprint&lt;/a&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:11370</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/11370.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=11370"/>
    <title>ICFP contest 2006</title>
    <published>2007-08-24T10:46:28Z</published>
    <updated>2007-08-24T10:46:28Z</updated>
    <category term="icfp"/>
    <category term="ml"/>
    <category term="src"/>
    <content type="html">&lt;span class='ljuser' lj:user='_adept_' style='white-space: nowrap;'&gt;&lt;a href='http://users.livejournal.com/_adept_/profile'&gt;&lt;img src='http://p-stat.livejournal.com/img/userinfo.gif' alt='[info]' width='17' height='17' style='vertical-align: bottom; border: 0; padding-right: 1px;' /&gt;&lt;/a&gt;&lt;a href='http://users.livejournal.com/_adept_/'&gt;&lt;b&gt;_adept_&lt;/b&gt;&lt;/a&gt;&lt;/span&gt; недавно &lt;a href="http://users.livejournal.com/_adept_/70578.html"&gt;писал&lt;/a&gt; о новых задачках в стиле ICFP contest 2006, написанных Алексеем Щепиным. А все ли в курсе, что организаторы ICFP contest 2006 опубликовали &lt;a href="http://www.boundvariable.org/code.shtml"&gt;исходники&lt;/a&gt; - компилятор ML в UM, генераторы головоломок и т.д.?</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:11031</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/11031.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=11031"/>
    <title>ГЭБ</title>
    <published>2007-08-13T12:10:17Z</published>
    <updated>2007-08-13T12:10:17Z</updated>
    <category term="geb"/>
    <category term="book"/>
    <content type="html">Одолел за время отпуска &lt;a href="http://en.wikipedia.org/wiki/G%C3%B6del,_Escher,_Bach"&gt;"Гориллы, эму, бабуины - эти буйные гости"&lt;/a&gt; Д.Хофштадтера. &lt;a name="cutid1"&gt;&lt;/a&gt;Книга в целом очень понравилась. Хорошо раскрыты идеи, лежащие в основе доказательства теорем Геделя, и сопутствующий материал - формальные системы, формальная арифметика, диагонализация; интересен экскурс в генетику. Лирические отступления на тему музыки Баха, картин Эшера и дзен-буддизма гармонично вплетаются в ткань книги. Диалоги Ахилла, Черепахи и других написаны с юмором, массой сюрпризов и скрытых смысловых слоев; порадовало пасхальное яйцо, спрятанное в библиографии. Раздел о перспективах ИИ показался слабее остальных - по понятным причинам. Русский перевод не без недостатков - хоть переводчица тесно сотрудничала с автором и проделала титанический труд с целью сохранить игру слов и запутанные связи формы и содержания, бросаются в глаза ошибки в терминологии из области CS.&lt;br /&gt;&lt;br /&gt;Если вы перевариваете научно-популярную литературу с философским уклоном, если интересуетесь логикой или ИИ (а также музыкой, живописью и биологией) - рекомендую.&lt;br /&gt;&lt;br /&gt;з.ы. Идея о том, что Странные Петли - запутанных иерархии со смешением уровней - должны лежать в основе интеллекта, мне кажется, подтверждается - плохо спроектированные программы глючат наиболее творчески.&lt;br /&gt;&lt;br /&gt;з.з.ы. Кто-нибудь знает, где достать "I Am A Strange Loop"?&lt;br /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:10896</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/10896.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=10896"/>
    <title>К вопросу об эффективности композиции</title>
    <published>2007-07-06T10:01:45Z</published>
    <updated>2007-07-06T10:01:45Z</updated>
    <category term="continuations"/>
    <category term="ocaml"/>
    <category term="haskell"/>
    <content type="html">Хотелось бы написать о чем-то возвышенном - например, &lt;a href="http://caml.inria.fr/pub/ml-archives/caml-list/2007/07/7a34650001bf6876b71c7b1060ac501f.en.html"&gt;о delimited continuations и инверсии парсеров&lt;/a&gt;, а еще &lt;a href="http://caml.inria.fr/pub/ml-archives/caml-list/2007/07/9858139a356468fa638746aacf111682.en.html"&gt;раскритиковать трансформеры монад&lt;/a&gt; по ходу дела. Но, к сожалению, я пока мало в этом разбираюсь, потому напишу об обычных списках и функциях.&lt;br /&gt;&lt;br /&gt;Как известно, добавлять элементы в конец списка в Haskell и других функциональных языках неэффективно. Поэтому, если эту операцию требуется делать в цикле, применяются различные трюки - накапливать в обратном порядке, а затем разворачивать, или более элегантно - &lt;a name="cutid1"&gt;&lt;/a&gt; представлять недостроенные списки в виде функций.&lt;br /&gt;&lt;pre&gt;
type PartialList a = [a]-&amp;gt; [a]
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Подход известный, используется в стандартной библиотеке (см. тип ShowS и связанные с ним функции) и не ограничивается списками - Conal Elliot недавно &lt;a href="http://conal-elliott.blogspot.com/2007/07/implementing-type-for-partial-values.html"&gt;писал&lt;/a&gt; об общем случае.&lt;br /&gt;&lt;br /&gt;Конкатенация частичных списков - это просто композиция функций:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
emptyPartialList = id

addElem :: a -&amp;gt; PartialList a
addElem x = (x:)

toList :: PartialList a -&amp;gt; [a]
toList p = p []

-- test = [1,2,3]
test = toList $ emptyPartialList . addElem 1 . addElem 2 . addElem 3 
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Возникает вопрос о границах применимости данного подхода. Если формировать во внутреннем цикле длинные частичные списки - скажем, 20000 элементов - они будут представлены композицией 20000 крошечных функций. Насколько такое представление (не-)эффективно? Я измерил и был удивлен - значительно эффективнее, чем можно было ожидать. Приведенная ниже реализация функции inits разрывает библиотечную реализацию в тряпки:&lt;br /&gt;&lt;pre&gt;
myInits xs = loop xs emptyPartialList
    where loop [] prefix = [toList prefix]
          loop (x:xs) prefix = (toList prefix) : loop xs (prefix . addElem x)
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Код теста:&lt;br /&gt;&lt;pre&gt;
test :: ([Int]-&amp;gt;[[Int]]) -&amp;gt; Int -&amp;gt; Int
test initsf n = sum $ map sum $ initsf $ take n $ cycle [1,-1]

measure expr = do
  t0 &amp;lt;- getClockTime
  r  &amp;lt;- return $! expr
  t1 &amp;lt;- getClockTime
  return (r, diffClockTimes t1 t0)

tests initsf = do
  putStrLn "n\t\tresult\t\ttime"
  putStrLn "============================================"
  mapM_ printTiming [2000, 5000, 10000, 15000, 20000, 25000, 30000]
    where printTiming n = do
            (r, td) &amp;lt;- measure (test initsf n)
            printf "%d\t\t%d\t\t%s\n" n r (timeDiffToString td)

main = do
  putStrLn "Data.List.inits:"
  tests inits
  putStrLn "myInits"
  tests myInits
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Результаты:&lt;br /&gt;&lt;pre&gt;
Data.List.inits:
n		result		time
============================================
2000		1000		1 sec
5000		2500		1 sec
10000		5000		6 secs
15000		7500		32 secs
20000		10000		74 secs
25000		12500		129 secs
30000		15000		196 secs

myInits
n		result		time
============================================
2000		1000		
5000		2500		
10000		5000		1 sec
15000		7500		2 secs
20000		10000		4 secs
25000		12500		6 secs
30000		15000		9 secs

&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Для полноты картины проверил, насколько хорошо Окамл справляется с десятками тысяч замыканий - оказалось, значительно хуже, чем Haskell:&lt;br /&gt;&lt;pre&gt;
n               result          time
============================================
2000            1000            0.046000 sec(s)
5000            2500            0.500000 sec(s)
10000           5000            3.125000 sec(s)
15000           7500            8.781000 sec(s)
20000           10000           18.641000 sec(s)
25000           12500           32.905000 sec(s)
30000           15000           52.906000 sec(s)
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Полный код теста на Окамле:&lt;br /&gt;&lt;pre&gt;
type 'a partial_list = 'a list -&amp;gt; 'a list

let empty_partial_list = fun x -&amp;gt; x

let append prefix x = fun xs -&amp;gt; prefix (x::xs)

let to_list p = p []

let iter_inits f xs = 
  let rec loop lst prefix = match lst with
    | [] -&amp;gt; f (to_list prefix)
    | x::xs -&amp;gt; begin f (to_list prefix); loop xs (append prefix x) end
  in
    loop xs empty_partial_list

let rec cycle = 1::-1::cycle

let sum = List.fold_left (+) 0

let rec take n lst = match (n, lst) with
  | (0, _)     -&amp;gt; []
  | (_, [])    -&amp;gt; []
  | (n, x::xs) -&amp;gt; x :: take (n-1) xs

let test n = 
  let ret = ref 0 in
  let process lst = ret := !ret + sum lst
  in (iter_inits process (take n cycle); !ret)

let measure f = 
  let t0 = Sys.time () in
  let r  = f () in
  let t1 = Sys.time () in
    (r, t1 -. t0)

let main () =
  let print_timing n = 
    let (r, td) = measure (fun () -&amp;gt; test n) in
      begin
        Printf.printf "%d\t\t%d\t\t%f sec(s)\n" n r td;
        flush stdout
      end
  in 
    begin
      print_endline "n\t\tresult\t\ttime";
      print_endline "============================================";
      List.iter print_timing [2000; 5000; 10000; 15000; 20000; 25000; 30000]
    end

let _ = main ()
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;На сегодня все. Надо поработать и почитать &lt;a href="http://citeseer.ist.psu.edu/filinski89declarative.html"&gt;диссертацию&lt;/a&gt; Анджея Филински "Declarative Continuations and Categorical Duality" - глядишь, будет чего написать и по более интересным вопросам.&lt;br /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:10618</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/10618.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=10618"/>
    <title>Занимательная энтомология</title>
    <published>2007-06-01T11:43:57Z</published>
    <updated>2007-06-01T13:33:58Z</updated>
    <category term="bugs"/>
    <category term="rant"/>
    <category term="programming"/>
    <content type="html">Нашел &lt;a href="http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_thread/thread/8923a5eeb521d038/f705762c4ded6857#f705762c4ded6857"&gt;баг&lt;/a&gt; в Visual C# 2005.  По крайней мере, народ, знающий C# лучше меня, склоняется к тому, что это таки баг. Если лень ходить по ссылке - поведение программы может зависеть от порядка объявлений перегруженных методов в интерфейсе. Что характерно, баг, похоже, в спецификации языка - никто не смог найти конкретный абзац, объясняющий, как должна интерпретироваться данная программа. Мне кажется, что проблема в отсутствии хоть какого-нибудь подобия формального семантики. Эти жуткие документы - стандарт C++ и спецификация C# - напоминают творение адвокатов, а не инженеров, и сочетают в себе худшее из двух миров: пугающие объемы текста, нечитабельный, непонятный язык и масса возможных неоднозначностей и разночтений.&lt;br /&gt;&lt;br /&gt;Когда мы придем к власти, миром будут править Карри и его друг Говард.</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:10353</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/10353.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=10353"/>
    <title>A Banda Brasil</title>
    <published>2007-05-17T15:12:14Z</published>
    <updated>2007-05-17T15:12:14Z</updated>
    <category term="music"/>
    <content type="html">Замечательная киевская группа Brasil (&lt;span class='ljuser' lj:user='brasil_brasil' style='white-space: nowrap;'&gt;&lt;a href='http://brasil-brasil.livejournal.com/profile'&gt;&lt;img src='http://p-stat.livejournal.com/img/userinfo.gif' alt='[info]' width='17' height='17' style='vertical-align: bottom; border: 0; padding-right: 1px;' /&gt;&lt;/a&gt;&lt;a href='http://brasil-brasil.livejournal.com/'&gt;&lt;b&gt;brasil_brasil&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;), которая лучше всех на наших просторах исполняет Samba &amp; Bossa Nova, выложила свою &lt;a href="http://www.realmusic.ru/brasil"&gt;демку&lt;/a&gt;.</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:10219</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/10219.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=10219"/>
    <title>Djinn mode for Emacs</title>
    <published>2007-05-17T11:02:41Z</published>
    <updated>2007-05-17T12:32:59Z</updated>
    <category term="djinn"/>
    <category term="emacs"/>
    <category term="haskell"/>
    <content type="html">Как известно, &lt;a href="http://lambda-the-ultimate.org/node/1178"&gt;Djinn&lt;/a&gt; - theorem prover для Haskell, который может выводить определения функций из типов, используя изоморфизм Карри-Говарда.&lt;br /&gt;&lt;br /&gt;Теоретически, он должен помогать при написании злых комбинаторов ну очень высокого порядка, тип которых записать легко, а определение - труднее. На практике мне еще не приходилось прибегать к помощи Джинна, но почему-то захотелось иметь поддержку Джинна в Емаксе. Поиск в гугле показал, что в своем желании я &lt;a href="http://programming.reddit.com/info/167fv/comments/c16cx1"&gt;не одинок&lt;/a&gt;:&lt;br /&gt;&lt;i&gt;And now I greatly desire an Emacs haskell-mode with Djinn built in, so I can type "M-x write-program-at-point RET".&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Тем не менее, готового djinn-mode.el не нашлось. Значит, надо делать самому. Emacs-lisp я совсем не знаю, но это не препятствие - есть inf-haskell.el, из которого можно почти все содрать (да здравствует open-source!).&lt;br /&gt;Итого, в настоящий момент имеются функции &lt;br /&gt;M-x inferior-djinn-show - выпускает джинна из бутылки в емаксовский буфер, и &lt;br /&gt;M-x inferior-djinn-define - спрашивает имя и тип, вставляет полученное от джинна определение в текущий буфер.&lt;br /&gt;Хорошо бы добавить функцию, которая будет сканировать определения типов в текущем буфере и отправлять их джинну.&lt;br /&gt;Если это показалось кому-то интересным - &lt;a name="cutid1"&gt;&lt;/a&gt; вот код:&lt;br /&gt;&lt;pre&gt;
;;; djinn-mode.el --- Interaction with Djinn in Emacs buffer

;; Copyright (C) 2007  Free Software Foundation, Inc.

;; Author: Gleb Alexeyev gleb.alexeev@gmail.com
;; Almost all code is copy-pasted shamelessly from 
;; inf-haskell.el written 
;; by Stefan Monnier &amp;lt;monnier@iro.umontreal.ca&amp;gt;
;; Keywords: Haskell, Djinn
;; Version: 0.01

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 
;; This file is NOT part of GNU Emacs.
;;
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;;
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; To find out more about the GNU General Public License you can visit
;; Free Software Foundation's website http://www.fsf.org/.  Or, write
;; to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;; Floor, Boston, MA 02110-1301, USA.


(require 'comint)

;;(define-derived-mode inferior-djinn-mode comint-mode "Inferior Djinn"
;;  "Major mode for interacting with an inferior Djinn process"
;;  (set (make-local-variable 'comint-prompt-regexp) "Djinn&amp;gt; ")
;;  (set (make-local-variable 'comint-input-autoexpand) t))

(defconst inferior-djinn-program-name "djinn")

;;;###autoload
(defun inferior-djinn-show (&amp;optional arg)
  "Show the inferior-djinn buffer.  Start the process if needed."
  (interactive "P")
  (let ((proc (inferior-djinn-process arg)))
    (pop-to-buffer (process-buffer proc))))

(defun inferior-djinn-string-to-strings (string &amp;optional separator)
  "Split the STRING into a list of strings.
The SEPARATOR regexp defaults to \"\\s-+\"."
  (let ((sep (or separator "\\s-+"))
	(i (string-match "[\"]" string)))
    (if (null i) (split-string string sep)	; no quoting:  easy
      (append (unless (eq i 0) (split-string (substring string 0 i) sep))
	      (let ((rfs (read-from-string string i)))
		(cons (car rfs)
		      (inferior-djinn-string-to-strings
		       (substring string (cdr rfs)) sep)))))))

(defun inferior-djinn-command (arg)
  (inferior-djinn-string-to-strings
   (if (null arg) inferior-djinn-program-name
     (read-string "Command to run Djinn: " inferior-djinn-program-name))))

(defvar inferior-djinn-buffer nil
  "The buffer in which the inferior Djinn process is running.")

(defun inferior-djinn-start-process (command)
  "Start an inferior djinn process.
With universal prefix \\[universal-argument], prompts for a command,
otherwise uses `inferior-djinn-program-name'.
It runs the hook `inferior-djinn-hook' after starting the process and
setting up the inferior-djinn buffer."
  (interactive (list (inferior-djinn-command current-prefix-arg)))
  (setq inferior-djinn-buffer
	(apply 'make-comint "djinn" (car command) nil (cdr command)))
  (with-current-buffer inferior-djinn-buffer
    ;;(inferior-djinn-mode)
    (run-hooks 'inferior-djinn-hook)))

(defun inferior-djinn-process (&amp;optional arg)
  (or (if (buffer-live-p inferior-djinn-buffer)
	  (get-buffer-process inferior-djinn-buffer))
      (progn
	(let ((current-prefix-arg arg))
	  (call-interactively 'inferior-djinn-start-process))
	;; Try again.
	(inferior-djinn-process arg))))

(defun inferior-djinn-wait-for-prompt (proc)
  "Wait until PROC sends us a prompt.
The process PROC should be associated to a comint buffer."
  (with-current-buffer (process-buffer proc)
    (while (progn
             (goto-char comint-last-input-end)
             (and (not (re-search-forward "Djinn&amp;gt;" nil t))
                  (accept-process-output proc))))))

(defun inferior-djinn-send-command (proc str)
  (setq str (concat str "\n"))
  (with-current-buffer (process-buffer proc)
    (inferior-djinn-wait-for-prompt proc)
    (goto-char (process-mark proc))
    (insert-before-markers str)
    (move-marker comint-last-input-end (point))
    (comint-send-string proc str)))

(defun inferior-djinn-execute-cmd (cmd)
  "Execute arbitrary Djinn command"
  (interactive "s Enter a command: ")
  (let ((proc (inferior-djinn-process)))
    (with-current-buffer (process-buffer proc)
      (let ((parsing-end                ; Remember previous spot.
             (marker-position (process-mark proc))))
        (inferior-djinn-send-command proc cmd)
        ;; Find new point.
        (goto-char (point-max))
        (inferior-djinn-wait-for-prompt proc)
        ;; Move to previous end-of-line
        (end-of-line 0)
        (let ((result
               (buffer-substring-no-properties
                (save-excursion (goto-char parsing-end)
                                (line-beginning-position 2))
                (point))))
          ;; Move back to end of process buffer
          (goto-char (point-max))
          (if (interactive-p) (message "%s" result))
          result)))))

(defun inferior-djinn-define (name type)
  "Infer definition and insert into current buffer"
  (interactive "s Name: \ns Type: ")
  (let ((def (inferior-djinn-execute-cmd (concat name " ? " type))))
    (if (string-match ".* cannot be realized" def)
        (progn
          (insert (concat name " :: " type "\n" name " = undefined\n"))
          (message "Djinn failed to deduce definition"))
      (insert (concat def "\n")))))
&lt;/pre&gt;&lt;br /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:9761</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/9761.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=9761"/>
    <title>Генуин</title>
    <published>2007-04-23T06:04:34Z</published>
    <updated>2007-04-23T06:04:34Z</updated>
    <category term="words"/>
    <content type="html">"Выпей генуину!" - сказал виндоус юзеру, пожелавшему скачать апдейты.</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:9473</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/9473.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=9473"/>
    <title>И опять об умственном чтиве</title>
    <published>2007-04-20T12:58:49Z</published>
    <updated>2007-04-20T12:58:49Z</updated>
    <category term="plt"/>
    <category term="tapl"/>
    <category term="cs"/>
    <content type="html">В тот момент, пока я это пишу, на заглавной странице LtU висит ссылка на статью Д. Тернера &lt;a href="http://lambda-the-ultimate.org/node/2204"&gt;Church’s Thesis and Functional Programming&lt;/a&gt;.&lt;br /&gt;Пролистал, понял от силы процентов двадцать.  Но у статьи есть несомненное достоинство - при своем скромном объеме в 21 страницу она может служить отличной картой PLT. Если ее распечатать в виде плаката и повесить на стену, можно будет при прочтении практически любой работы в области языков программирования воткнуть флажок "You are here".</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:9257</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/9257.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=9257"/>
    <title>Lytdybr</title>
    <published>2007-04-19T14:38:55Z</published>
    <updated>2007-04-19T14:38:55Z</updated>
    <category term="work"/>
    <category term="lytdybr"/>
    <category term="haskell"/>
    <content type="html">Потихоньку сбывается мечта идиота - применяю Haskell в реальной работе. Не так, конечно, как Lennart Augustsson в Credit Suisse, скромнее: прототипирую на Хаскеле, переписываю на чем попало (C#, например). Данных для серьезной статистики пока маловато, но на последнем написанном куске соотношение объемов кода C#/Haskell при одинаковой функциональности  приблизительно равно 10.&lt;br /&gt;До чего же скучно переписывать, доложу я вам...</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:9010</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/9010.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=9010"/>
    <title>palm_mute @ 2007-04-12T23:07:00</title>
    <published>2007-04-12T19:24:54Z</published>
    <updated>2007-04-12T19:26:08Z</updated>
    <content type="html">Автобус, которого дожидался Малаки Констант, в то утро опоздал на два часа - по причине снегопада. А когда автобус подошел, было уже поздно - Малаки Констант был мертв.</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:8734</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/8734.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=8734"/>
    <title>Mutable variables eliminated from .NET</title>
    <published>2007-04-01T18:36:43Z</published>
    <updated>2007-04-01T18:36:43Z</updated>
    <content type="html">Приз за самую лучшую первоапрельскую шутку в моей френд-ленте присуждается lambda-the-ultimate.org:&lt;br /&gt;&lt;br /&gt;&lt;a name="cutid1"&gt;&lt;/a&gt;&lt;br /&gt;&lt;h1&gt;Mutable variables eliminated from .NET&lt;/h1&gt;&lt;br /&gt;Redmond, WA: At an unusual press conference held this Sunday morning, Bill Taylor, Microsoft's General Manager of Platform Strategy, announced that after much research into the causes of security holes and instabilities, Microsoft will eliminate mutable variables from the .NET platform and its languages, including C# and VB.NET. "One of our top researchers found that mutable variables were the major root cause preventing us from achieving the great user experience we always strive to deliver," said Taylor. "Once we realized that, eliminating them from .NET was a no-brainer."&lt;br /&gt;&lt;br /&gt;Given that this announcement was made on a Sunday, reactions have been limited so far, but one prominent VB.NET developer commented that "Compared to the switch from VB6 to VB.NET, this ought to be a breeze." A C# developer was heard to say, "After anonymous delegates, monads shouldn't be a problem."&lt;br /&gt;&lt;br /&gt;To ensure wide penetration of this significant update, Microsoft will be issuing updated Windows CDs to all licensed customers, free of charge. The new CDs can be identified by the distinctive holographic "Haskell Inside" logo, featuring a holographic version of this portrait of Simon Peyton-Jones, grinning from ear to ear.&lt;br /&gt;&lt;br /&gt;LtU readers are encouraged to share any inside info they may have about this move!&lt;br /&gt;&lt;br /&gt;from &lt;a href="http://lambda-the-ultimate.org/node/2164"&gt;http://lambda-the-ultimate.org/node/2164&lt;/a&gt;&lt;br /&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:palm_mute:8648</id>
    <link rel="alternate" type="text/html" href="http://palm-mute.livejournal.com/8648.html"/>
    <link rel="self" type="text/xml" href="http://palm-mute.livejournal.com/data/atom/?itemid=8648"/>
    <title>PLAI</title>
    <published>2007-03-20T10:29:19Z</published>
    <updated>2007-03-20T10:29:19Z</updated>
    <category term="plt"/>
    <category term="book"/>
    <category term="fun"/>
    <content type="html">Нашел в сети книгу о языках программирования (бесплатную, кстати):&lt;br /&gt;&lt;a href="http://www.cs.brown.edu/~sk/Publications/Books/ProgLangs/"&gt;Programming Languages: Application and Interpretation by Shriram Krishnamurthi&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;На первой же странице автор выдвигает идею о второстепенности синтаксиса и приводит такой пример:&lt;br /&gt;&lt;q&gt;&lt;br /&gt;For instance, consider the following three code fragments:&lt;br /&gt;&lt;br /&gt;1. a [25] + 5&lt;br /&gt;2. (+ (vector-ref a 25) 5)&lt;br /&gt;3. a [25] + 5&lt;br /&gt;&lt;br /&gt;Which of these two is most like each other? The first and second, obviously! Why? Because the first is in Java and the second is in Scheme, both of which signal an error if the vector associated with a has fewer than 25 entries; the third, in C, blithely ignores the vector’s size, leading to unspecified behavior, even though its syntax is exactly the same as that of the Java code.&lt;br /&gt;&lt;/q&gt;&lt;br /&gt;&lt;br /&gt;Книга мне уже определенно нравится :).</content>
  </entry>
</feed>
