<?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:blogger='http://schemas.google.com/blogger/2008' 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-5733819446652035433</id><updated>2024-09-27T15:26:11.346+03:00</updated><category term="FRP"/><category term="haskell"/><category term="reactive-banana"/><category term="stumpwm"/><category term="en"/><category term="jabber"/><title type='text'>tymmym&#39;s blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tymmym.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733819446652035433/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://tymmym.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5733819446652035433.post-2365892306146766758</id><published>2011-11-21T20:30:00.000+04:00</published><updated>2012-08-08T18:20:35.771+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="en"/><category scheme="http://www.blogger.com/atom/ns#" term="FRP"/><category scheme="http://www.blogger.com/atom/ns#" term="haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="reactive-banana"/><title type='text'>Introduction to Functional Reactive Programming with reactive-banana</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
1. &lt;a href=&quot;https://docs.google.com/open?id=0B_VCco8PaKXoamhJWTdGeTFwbWM&quot;&gt;PDF&lt;/a&gt; of the article&lt;br /&gt;
2. literate Haskell &lt;a href=&quot;https://docs.google.com/open?id=0B_VCco8PaKXoRXJLQjg1M25mT2c&quot;&gt;source code&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tymmym.blogspot.com/feeds/2365892306146766758/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tymmym.blogspot.com/2011/11/reactive-banana-en.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733819446652035433/posts/default/2365892306146766758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733819446652035433/posts/default/2365892306146766758'/><link rel='alternate' type='text/html' href='http://tymmym.blogspot.com/2011/11/reactive-banana-en.html' title='Introduction to Functional Reactive Programming with reactive-banana'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733819446652035433.post-7585348601415910837</id><published>2011-11-11T00:04:00.005+04:00</published><updated>2011-11-11T17:21:50.558+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="FRP"/><category scheme="http://www.blogger.com/atom/ns#" term="haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="reactive-banana"/><title type='text'>Введение в функциональное реактивное программирование с помощью reactive-banana</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
Функциональное реактивное программирование (ФРП) - это метод&amp;nbsp;моделирования реактивного (т.е. зависящего от времени и внешних&amp;nbsp;воздействий) поведения в чистых функциональных языках. ФРП позволяет&amp;nbsp;моделировать системы, реагирующие на изменяющиеся входные воздействия,&amp;nbsp;в простом декларативном стиле[1].&lt;/div&gt;
&lt;br /&gt;
Цель данного поста показать, как можно писать GUI на Haskell в&amp;nbsp;декларативном стиле. С помощью библиотеки reactive-banana мы напишем&amp;nbsp;простой счётчик, который будет управляться двумя кнопками.&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;Теория&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Основными концепциями ФРП являются поведения (behaviors) и события&amp;nbsp;(events).&lt;br /&gt;
&lt;br /&gt;
Поведение - это меняющееся со временем значение. Его можно представить&amp;nbsp;как:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;type Behavior a = Time -&amp;gt; a&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Событие - это поток происшествий в порядке их появления. Событие&amp;nbsp;можно представить в виде бесконечного списка значений привязанных ко&amp;nbsp;времени их появления:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;type Event a = [(Time, a)]&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Для написания программы необходимо:&lt;br /&gt;
&lt;br /&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;получить входные поведения и события;&lt;/li&gt;
&lt;li&gt;преобразовать входные поведения и события к нужным выходным,&amp;nbsp;т.е.описать логику работы;&lt;/li&gt;
&lt;li&gt;получить результаты от выходных событий.&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
Функции модуля &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;Reactive.Banana.Implementation&lt;/b&gt;&lt;/span&gt; позволяют получать&amp;nbsp;входные события и поведения от внешних источников. Например,&amp;nbsp;последовательность нажатий на кнопку мыши можно представить как&amp;nbsp;событие, а строку в поле ввода как значение зависящее от времени,&amp;nbsp;т.е. поведение.&lt;br /&gt;
&lt;br /&gt;
Функции модуля &lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Reactive.Banana.Model&lt;/span&gt;&lt;/b&gt; позволяют описывать новые&amp;nbsp;события на основе входных событий. Это описание называется графом&amp;nbsp;событий. Граф событий - это своего рода описание логики работы,&amp;nbsp;требуемая функциональность достигается путём комбинирования&amp;nbsp;существующих событий и поведений.&lt;br /&gt;
&lt;br /&gt;
Полученные путём использованием комбинаторов события выводятся с&amp;nbsp;помощью функций модуля &lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Reactive.Banana.Implementation&lt;/span&gt;&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Сеть событий - это граф событий вместе с входами и выходами. Для&amp;nbsp;описания сети событий необходимо описать входы, выходы и граф событий&amp;nbsp;в монаде &lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;NetworkDescription&lt;/span&gt;&lt;/b&gt;, а затем использовать функцию &lt;i&gt;compile&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Для активации сети событий нужно использовать функцию&amp;nbsp;&lt;i&gt;actuate&lt;/i&gt;. Процесс активации заключается в регистрации входных событий&amp;nbsp;и начале формирования результатов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;Практика&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Начнём с импорта необходимых библиотек. Нам понадобятся:&lt;br /&gt;
&lt;br /&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;wxHaskell для GUI,&lt;/li&gt;
&lt;li&gt;reactive-banana для ФРП,&lt;/li&gt;
&lt;li&gt;reactive-banana-wx для связывания wxHaskell с reactive-banana.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;import Control.Monad&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;import Graphics.UI.WX hiding (Event)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;import Reactive.Banana&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;import Reactive.Banana.WX&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Начнём писать функцию &lt;i&gt;main&lt;/i&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;main = start $ do&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;f &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;- frame [text := &quot;Counter&quot;]&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bup &amp;nbsp; &amp;nbsp;&amp;lt;- button f [text := &quot;Up&quot;]&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bdown &amp;nbsp;&amp;lt;- button f [text := &quot;Down&quot;]&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;output &amp;lt;- staticText f []&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;set f [layout := margin 10 $&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;column 5 [widget bup, widget bdown, widget output]]&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы создали основное окно с двумя кнопками (одна - для увеличения&amp;nbsp;значения счётчика, другая - для уменьшения) и одним текстовым полем (для&amp;nbsp;вывода значения счетчика).&lt;br /&gt;
&lt;br /&gt;
Следующий шаг - описание сети и её компиляция для получения сети&amp;nbsp;событий:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;network &amp;lt;- compile $ do&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Описание сети начинаем с определения её входов:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; eup &amp;nbsp; &amp;nbsp;&amp;lt;- event0 bup &amp;nbsp; command&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; edown &amp;nbsp;&amp;lt;- event0 bdown command&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы использовали функцию &lt;i&gt;event0&lt;/i&gt;&amp;nbsp;для получения событий от&amp;nbsp;нажатий на кнопки. Функция |event0| предоставляется модулем&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;b&gt;Reactive.Banana.WX&lt;/b&gt;&lt;/span&gt; и служит для получения событий из wxHaskell.&amp;nbsp;Т.о., если мы нажимаем на кнопки &quot;Up&quot; и &quot;Down&quot; поочереди, то мы&amp;nbsp;генерируем два потока происшествий, которые можно представить как:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;eup &amp;nbsp; &amp;nbsp;= [(time1,bupCommand),(time3,bupCommand)..]&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;edown &amp;nbsp;= [(time2,bdownCommand),(time4,bdownCommand)..]&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Следующий шаг --- описание графа событий.&lt;br /&gt;
&lt;br /&gt;
Сначала мы формируем новое событие на основе входного. Используем&amp;nbsp;комбинатор, который заменяет все происшествия с нажатием на кнопку на&amp;nbsp;функцию |(+1)|:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; let&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; einc :: Event (Int -&amp;gt; Int)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; einc = (+1) &amp;lt;$ eup&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Функция &lt;i&gt;(&amp;lt;$) :: a -&amp;gt; f b -&amp;gt; f a&lt;/i&gt;&amp;nbsp;заменяет все входные происшествия&amp;nbsp;одинаковым значением. Результат её работы можно представить так:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;(+1) &amp;lt;$ [(time1,bupCommand),(time3,bupCommand)..] =&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;[(time1,(+1)),(time3,(+1))..]&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Такую же операцию проводим с событием &lt;i&gt;edown&lt;/i&gt;, но здесь используем&amp;nbsp;другую функцию - &lt;i&gt;(subtract 1)&lt;/i&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; edec :: Event (Int -&amp;gt; Int)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; edec = subtract 1 &amp;lt;$ edown&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Объединим эти два события в одно:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ecount :: Event (Int -&amp;gt; Int)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ecount = einc `union` edec&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Функция &lt;i&gt;union&lt;/i&gt;&amp;nbsp;объединяет два потока происшествий одинакового типа:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;[(time1,(+1)),(time3,(+1))] `union` [(time2,subtract 1),(time4,subtract 1)] =&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; [(time1,(+1)),(time2,subtract 1),(time3,(+1)),(time4,subtract 1)]&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Наконец, мы используем функцию &lt;i&gt;accumD&lt;/i&gt;&amp;nbsp;для получения меняющегося&amp;nbsp;значения счётчика из события:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; counter :: Discrete Int&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; counter = accumD 0 ecount&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Полученный счётчик обладает типом &lt;i&gt;Discrete&lt;/i&gt;, который почти идентичен&amp;nbsp;типу Behavior (за описанием отличий можно обратиться &lt;a href=&quot;http://hackage.haskell.org/packages/archive/reactive-banana/latest/doc/html/Reactive-Banana-Incremental.html&quot;&gt;документации&amp;nbsp;на reactive-banana&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
Функция &lt;i&gt;accumD&lt;/i&gt;&amp;nbsp;аналогична функции &lt;i&gt;foldl&#39;&lt;/i&gt;, её можно представить как:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;accumD 0 [(time1,(+1)),(time2,subtract 1),(time3,(+1))..] =&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; stepperD 0 [(time1,1),(time2,0),(time3,1)..]&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
где &lt;i&gt;stepperD&lt;/i&gt;&amp;nbsp;- возвращает функцию от времени, получая начальное&amp;nbsp;значение и поток новых значений:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;stepperD x0 ex = \time -&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; last (x0 : [x | (timeX,x) &amp;lt;- ex, timeX &amp;lt; time])&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Следующий шаг - получение результатов. Сначала мы применяем&amp;nbsp;функцию &lt;i&gt;show&lt;/i&gt;&amp;nbsp;для преобразования изменяющегося значения с типом Int к&amp;nbsp;типу String:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; counterStr :: Discrete String&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; counterStr = show &amp;lt;$&amp;gt; counter&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Затем используем функцию &lt;i&gt;sink&lt;/i&gt;&amp;nbsp;для отображения результатов:&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; sink output [text :== counterStr]&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;sink&lt;/i&gt; - вспомогательная функция с типом &lt;i&gt;w -&amp;gt; [Prop&#39; w] -&amp;gt;&amp;nbsp;&lt;/i&gt;&lt;i&gt;NetworkDescription ()&lt;/i&gt;&amp;nbsp;из модуля &lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;Reactive.Banana.WX&lt;/span&gt;&lt;/b&gt;. Она получает&amp;nbsp;виджет и список элементов с типом &lt;i&gt;Prop&#39;&lt;/i&gt;, где &lt;i&gt;Prop&#39;&lt;/i&gt; - это атрибут&amp;nbsp;wxHaskell ассоциированный с изменяющимся значением. Ассоциация&amp;nbsp;выполняется с помощью оператора &lt;i&gt;(:==)&lt;/i&gt;, имеющего тип &lt;i&gt;Attr w a -&amp;gt;&amp;nbsp;Discrete a -&amp;gt; Prop&#39; w&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Заклютельный шаг - активация сети событий. Сеть регистрирует входные&amp;nbsp;обработчики событий и начинает формировать результаты.&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;actuate network&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Всё, мы написали простой счётчик в декларативном стиле.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: large;&quot;&gt;Ссылки&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Edward Amsden, A Survey of Functional Reactive Programming, 2011.&lt;/li&gt;
&lt;li&gt;Heinrich Apfelmus, Reactive-banana API reference,&amp;nbsp;&lt;a href=&quot;http://hackage.haskell.org/package/reactive-banana&quot;&gt;http://hackage.haskell.org/package/reactive-banana&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Исходный код&amp;nbsp;&lt;a href=&quot;https://docs.google.com/open?id=0B_VCco8PaKXoOGExMjA2MmYtZjYyZi00MTM4LWI0YzgtYjIwMzkyYjdlNWUw&quot;&gt;Counter.lhs&lt;/a&gt;&amp;nbsp;и &lt;a href=&quot;https://docs.google.com/open?id=0B_VCco8PaKXoMmMxZThlMDktYWE4Yy00YjAzLWI0M2QtZDhlYjE2NWQyY2My&quot;&gt;PDF&lt;/a&gt;&amp;nbsp;статьи.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div style=&quot;font-size: x-large;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tymmym.blogspot.com/feeds/7585348601415910837/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tymmym.blogspot.com/2011/11/reactive-banana.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733819446652035433/posts/default/7585348601415910837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733819446652035433/posts/default/7585348601415910837'/><link rel='alternate' type='text/html' href='http://tymmym.blogspot.com/2011/11/reactive-banana.html' title='Введение в функциональное реактивное программирование с помощью reactive-banana'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733819446652035433.post-3406746816786432343</id><published>2009-06-29T14:49:00.013+04:00</published><updated>2009-06-30T21:53:23.255+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jabber"/><category scheme="http://www.blogger.com/atom/ns#" term="stumpwm"/><title type='text'>StumpWM + Jabber.el</title><content type='html'>Захотел получать оповещения о приходе в &lt;a href=&quot;http://emacs-jabber.sourceforge.net/&quot;&gt;Jabber.el&lt;/a&gt; сообщений.Для этого сначала добавил в Jabber.el возможность отправки сообщений в StumpWM.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Создал в директории с Jabber.el файл &lt;span style=&quot;font-style: italic;&quot;&gt;jabber-stumpwm.el&lt;/span&gt; следующего содержания:&lt;br /&gt;&lt;pre&gt;(eval-when-compile (require &#39;jabber-alert))&lt;br /&gt;&lt;br /&gt;(defun jabber-stumpwm-message (msg)&lt;br /&gt;&quot;Show MSG in StumpWM&quot;&lt;br /&gt;;; Possible errors include not finding the stumpish (STUMPwm Interactive SHell).&lt;br /&gt;(condition-case e&lt;br /&gt; (let ((process-connection-type))&lt;br /&gt;(call-process &quot;stumpish&quot; nil 0 nil &quot;notifications-add&quot; msg))&lt;br /&gt;(error nil)))&lt;br /&gt;&lt;br /&gt;(define-jabber-alert stumpwm &quot;Show a message through the StumpWM window manager&quot;&lt;br /&gt;&#39;jabber-stumpwm-message)&lt;/pre&gt;Данный файл - копия &lt;span style=&quot;font-style: italic;&quot;&gt;jabber-ratpoison.el&lt;/span&gt; с небольшими изменениями для StumpWM. Для отправки оповещения используется STUMPwm Interactive SHell, которой в качестве аргументов передаем имя фукции оповещения и сообщение.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Добавил &lt;span style=&quot;font-style: italic;&quot;&gt;(require &#39;jabber-stumpwm)&lt;/span&gt; в секцию &lt;span style=&quot;font-style: italic;&quot;&gt;External notifiers&lt;/span&gt; в файле &lt;span style=&quot;font-style: italic;&quot;&gt;jabber.el&lt;/span&gt;.&lt;/li&gt;&lt;/ol&gt;Функции оповещения предоставляются модулем &lt;span style=&quot;font-style: italic;&quot;&gt;notifications&lt;/span&gt;. Для его подключения в файл &lt;span style=&quot;font-style: italic;&quot;&gt;~/.stumpwmrc&lt;/span&gt; прописываем следующее:&lt;pre&gt;(load-module &quot;notifications&quot;)&lt;br /&gt;(define-key *root-map* (kbd &quot;N&quot;) &#39;*notifications-map*)&lt;br /&gt;&lt;/pre&gt;А к строке &lt;span style=&quot;font-style:italic;&quot;&gt;*screen-mode-line-format*&lt;/span&gt; добавляем &lt;span style=&quot;font-style:italic;&quot;&gt;%N&lt;/span&gt;.&lt;br /&gt;Результат:&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGaONlqKNkyi8hgaNHH-v6vjHjSnxu0Wn8Bm-9dsGAT-3e2O_0vWiAELLlYwkfZdoslL9jg-KyJEoltDJiwc448zG9UfUFx8HtNicrxx1LwzZ4wRPUOPD97VHbxIeS7GKu-poWNWHJJzH_/s1600-h/screen1.jpg&quot;&gt;&lt;img style=&quot;float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 38px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGaONlqKNkyi8hgaNHH-v6vjHjSnxu0Wn8Bm-9dsGAT-3e2O_0vWiAELLlYwkfZdoslL9jg-KyJEoltDJiwc448zG9UfUFx8HtNicrxx1LwzZ4wRPUOPD97VHbxIeS7GKu-poWNWHJJzH_/s400/screen1.jpg&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5353152060098003202&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Полученный результат меня до конца не устроил:&lt;br /&gt;- оповещения приходится удалять вручную;&lt;br /&gt;- оповещения захламляют и без того перегруженную mode-line.&lt;br /&gt;&lt;br /&gt;Пришлось внести небольшие изменения в модуль &lt;span style=&quot;font-style:italic;&quot;&gt;notifications&lt;/span&gt;, чтобы добиться желаемого:&lt;br /&gt;- добавлена возможность удаления оповещений по таймауту;&lt;br /&gt;- оповещения выводятся как стандартные сообщения StumpWM.&lt;pre&gt;*** notifications.lisp.old 2009-06-30 15:02:31.851810478 +0400&lt;br /&gt;--- notifications.lisp 2009-06-30 15:34:10.667560769 +0400&lt;br /&gt;***************&lt;br /&gt;*** 75,90 ****&lt;br /&gt;--- 75,107 ----&lt;br /&gt;(defvar notifications nil&lt;br /&gt;  &quot;A list of notification strings.&quot;)&lt;br /&gt;&lt;br /&gt;+ (defvar *notification-time* 20&lt;br /&gt;+   &quot;This variable controls how many seconds the notification will be&lt;br /&gt;+ stored in the list of notifications. Don&#39;t use timer for&lt;br /&gt;+ notification if the value is nil.&quot;)&lt;br /&gt;+&lt;br /&gt;+ (defvar *message-timeout* 1&lt;br /&gt;+   &quot;This variable controls how many seconds elapse between each update&lt;br /&gt;+ of the message.&quot;)&lt;br /&gt;+&lt;br /&gt;+ (defvar *message-timer* nil&lt;br /&gt;+   &quot;The timer that updates the message.&quot;)&lt;br /&gt;+&lt;br /&gt;(defcommand notifications-add (str)&lt;br /&gt;  ((:rest &quot;Notification: &quot;))&lt;br /&gt;  &quot;Add a notification string.&lt;br /&gt;If a notification is already included, it will be moved to the front instead of&lt;br /&gt;added anew.&quot;&lt;br /&gt;+   (when *notification-time*&lt;br /&gt;+     (run-notification-timer))&lt;br /&gt;  (when (not (string= (car notifications) str))&lt;br /&gt;    (when (member str notifications :test #&#39;string=)&lt;br /&gt;      (setf notifications (delete str notifications :test #&#39;string=)))&lt;br /&gt;    (push str notifications)))&lt;br /&gt;&lt;br /&gt;+ (defun run-notification-timer ()&lt;br /&gt;+   (run-with-timer *notification-time* nil #&#39;notifications-delete-last))&lt;br /&gt;+&lt;br /&gt;(defcommand notifications-reset ()&lt;br /&gt;  ()&lt;br /&gt;  &quot;Clear all notifications.&quot;&lt;br /&gt;***************&lt;br /&gt;*** 105,110 ****&lt;br /&gt;--- 122,142 ----&lt;br /&gt;  &quot;Delete the first notification.&quot;&lt;br /&gt;  (setf notifications (nreverse (cdr (nreverse notifications)))))&lt;br /&gt;&lt;br /&gt;+ (defcommand notifications-start-messages ()&lt;br /&gt;+     ()&lt;br /&gt;+   &quot;Start showing messages with notifications.&quot;&lt;br /&gt;+   (setf *message-timer*&lt;br /&gt;+  (run-with-timer 0&lt;br /&gt;+    *message-timeout*&lt;br /&gt;+    (lambda ()&lt;br /&gt;+      (when notifications&lt;br /&gt;+        (message-no-timeout (format nil &quot;~{~a~^~%~}&quot; notifications)))))))&lt;br /&gt;+&lt;br /&gt;+ (defcommand notifications-stop-messages ()&lt;br /&gt;+     ()&lt;br /&gt;+   &quot;Stop showing messages with notifications.&quot;&lt;br /&gt;+   (cancel-timer *message-timer*))&lt;br /&gt;+&lt;br /&gt;(defun notifications-as-string (&amp;amp;rest r)&lt;br /&gt;  (declare (ignore r))&lt;br /&gt;  (if notifications&lt;br /&gt;***************&lt;br /&gt;*** 126,131 ****&lt;br /&gt;--- 158,165 ----&lt;br /&gt;    (define-key m (kbd &quot;d&quot;)     &quot;notifications-delete-first&quot;)&lt;br /&gt;    (define-key m (kbd &quot;D&quot;)     &quot;notifications-delete-last&quot;)&lt;br /&gt;    (define-key m (kbd &quot;s&quot;)     &quot;notifications-show&quot;)&lt;br /&gt;+     (define-key m (kbd &quot;m&quot;)     &quot;notifications-start-messages&quot;)&lt;br /&gt;+     (define-key m (kbd &quot;M&quot;)     &quot;notifications-stop-messages&quot;)&lt;br /&gt;    m))&lt;br /&gt;&lt;br /&gt;;; Local Variables:&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;После выполнения функции &lt;span style=&quot;font-style:italic;&quot;&gt;notifications-start-messages&lt;/span&gt; при получении сообщений получаем следующее:&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPItqA_fPZxIPtmNCl-Fk1VULR7eDbGFyMQE3ZBKG4WU7xyRKbsFdeVcHtiAWP4EbInJotVqOFCZOK4o_cAqTGosN5jPh77J5yeMs9jbsLUWk_VHRW5EYHj7lDxuJxfPLLXaXz6XxqJ6jE/s1600-h/screen2.jpg&quot;&gt;&lt;img style=&quot;float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 38px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPItqA_fPZxIPtmNCl-Fk1VULR7eDbGFyMQE3ZBKG4WU7xyRKbsFdeVcHtiAWP4EbInJotVqOFCZOK4o_cAqTGosN5jPh77J5yeMs9jbsLUWk_VHRW5EYHj7lDxuJxfPLLXaXz6XxqJ6jE/s400/screen2.jpg&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5353172039356152722&quot; /&gt;&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://tymmym.blogspot.com/feeds/3406746816786432343/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tymmym.blogspot.com/2009/06/stumpwm-jabberel.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733819446652035433/posts/default/3406746816786432343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733819446652035433/posts/default/3406746816786432343'/><link rel='alternate' type='text/html' href='http://tymmym.blogspot.com/2009/06/stumpwm-jabberel.html' title='StumpWM + Jabber.el'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGaONlqKNkyi8hgaNHH-v6vjHjSnxu0Wn8Bm-9dsGAT-3e2O_0vWiAELLlYwkfZdoslL9jg-KyJEoltDJiwc448zG9UfUFx8HtNicrxx1LwzZ4wRPUOPD97VHbxIeS7GKu-poWNWHJJzH_/s72-c/screen1.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733819446652035433.post-324328158718632423</id><published>2009-05-15T12:31:00.024+04:00</published><updated>2009-06-29T15:55:37.547+04:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="stumpwm"/><title type='text'>StumpWM</title><content type='html'>Установил и начал настраивать под себя &lt;a href=&quot;http://www.nongnu.org/stumpwm/&quot;&gt;StumpWM&lt;/a&gt;  - &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%A4%D1%80%D0%B5%D0%B9%D0%BC%D0%BE%D0%B2%D1%8B%D0%B9_%D0%BE%D0%BA%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D0%BD%D0%B5%D0%B4%D0%B6%D0%B5%D1%80_X_Window_System&quot;&gt;фреймовый оконный менеджер&lt;/a&gt;, написанный на Common Lisp. Чтобы ознакомиться с некоторыми его возможностями, можно посмотреть &lt;a href=&quot;http://www.archive.org/details/TheStumpWMExperience&quot;&gt;видео ролик&lt;/a&gt;.&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;br /&gt;Установка&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Зависимости:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;реализация Common Lisp (поддерживаются clisp и SBCL)&lt;/li&gt;&lt;li&gt;clx&lt;/li&gt;&lt;li&gt;cl-ppcre&lt;/li&gt;&lt;li&gt;autoconf&lt;/li&gt;&lt;li&gt;texinfo&lt;/li&gt;&lt;/ol&gt;Я использовал SBCL 1.0.19, пакеты clx и cl-ppcre установливал с помощью &lt;a href=&quot;http://common-lisp.net/project/clbuild&quot;&gt;clbuild&lt;/a&gt;:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ &lt;span style=&quot;font-weight: bold;&quot;&gt;darcs get http://common-lisp.net/project/clbuild/clbuild&lt;/span&gt;&lt;br /&gt;$ &lt;span style=&quot;font-weight: bold;&quot;&gt;cd clbuild&lt;/span&gt;&lt;br /&gt;clbuild$ &lt;span style=&quot;font-weight: bold;&quot;&gt;chmod +x clbuild&lt;/span&gt;&lt;br /&gt;clbuild$ &lt;span style=&quot;font-weight: bold;&quot;&gt;./clbuild install clx cl-ppcre&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Чтобы asdf видел пакеты, установленные с помощью, clbuild добавим следующую строку в &lt;span style=&quot;font-style: italic;&quot;&gt;~/.sbclrc&lt;/span&gt;:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;(push #p&quot;/path/to/clbuild/systems/&quot; asdf:*central-registry*)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Устанавливаем последнюю версию StumpWM из репозитория:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ &lt;span style=&quot;font-weight: bold;&quot;&gt;git clone git://git.savannah.nongnu.org/stumpwm.git&lt;/span&gt;&lt;br /&gt;$ &lt;span style=&quot;font-weight: bold;&quot;&gt;cd stumpwm&lt;/span&gt;&lt;br /&gt;stumpwm$ &lt;span style=&quot;font-weight: bold;&quot;&gt;autoconf&lt;/span&gt;&lt;br /&gt;stumpwm$ &lt;span style=&quot;font-weight: bold;&quot;&gt;./configure &amp;amp;&amp;amp; make&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;В текущей директории появился файл stumpwm, который нужно указать в &lt;span style=&quot;font-style: italic;&quot;&gt;~/.xinitrc&lt;/span&gt;:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ &lt;span style=&quot;font-weight: bold;&quot;&gt;echo &quot;exec /path/to/stumpwm&quot; &gt; ~/.xinitrc&lt;/span&gt;&lt;br /&gt;$ &lt;span style=&quot;font-weight: bold;&quot;&gt;startx&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Настройка&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;При запуске StumpWM использует файл &lt;span style=&quot;font-style: italic;&quot;&gt;~/.stumpwmrc&lt;/span&gt;. Например, поместив следущие инструкции в &lt;span style=&quot;font-style: italic;&quot;&gt;~/.stumpwmrc&lt;/span&gt; мы определим функцию, которая вызывается при нажатии &lt;span style=&quot;font-weight: bold;&quot;&gt;C-t f&lt;/span&gt;. Она запускает Firefox, если он ещё не был запущен, в противном случае - переходит к ранее запущенному.&lt;br /&gt;&lt;pre&gt;(defcommand firefox () ()&lt;br /&gt;&quot;Start/Switchto Firefox.&quot;&lt;br /&gt;(run-or-raise &quot;firefox&quot; &#39;(:class &quot;Firefox&quot;)))&lt;br /&gt;&lt;br /&gt;(define-key *root-map* (kbd &quot;f&quot;) &quot;firefox&quot;)&lt;/pre&gt;&lt;br /&gt;В качестве примера можно использовать файл &lt;span style=&quot;font-style: italic;&quot;&gt;sample-stumpwmrc.lisp&lt;/span&gt;, можно посмотреть на файлы  &lt;a href=&quot;http://stumpwm.antidesktop.net/wiki/Customize&quot;&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;.stumpwmrc &lt;/span&gt;других пользователей&lt;/a&gt;, также много инересного можно узнать из &lt;a href=&quot;http://www.nongnu.org/stumpwm/manual/stumpwm.html&quot;&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;stumpwm.info&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Полностью поменять поведение StumpWM можно уже в процессе работы. Для этого можно:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;внести изменения в &lt;span style=&quot;font-style: italic;&quot;&gt;~/.stumpwmrc&lt;/span&gt; и выполнить команду &lt;span style=&quot;font-weight: bold;&quot;&gt;С-t ; loadrc&lt;/span&gt;&lt;/li&gt;&lt;li&gt;использовать emacs и &lt;span style=&quot;font-style: italic;&quot;&gt;stumpwm-mode.el&lt;/span&gt;&lt;/li&gt;&lt;li&gt;использовать stumpish (STUMPwm Interactive SHell)&lt;/li&gt;&lt;li&gt;использовать &lt;a href=&quot;http://common-lisp.net/project/slime&quot;&gt;SLIME&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Использование SLIME для настройки StumpWM&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Установим SLIME и создадим сивольную ссылку на &lt;span style=&quot;font-style: italic;&quot;&gt;stumpwm.asd&lt;/span&gt; для clbuild:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ &lt;span style=&quot;font-weight: bold;&quot;&gt;cd /path/to/clbuild&lt;/span&gt;&lt;br /&gt;clbuild$ &lt;span style=&quot;font-weight: bold;&quot;&gt;./clbuild install slime&lt;/span&gt;&lt;br /&gt;clbuild$ &lt;span style=&quot;font-weight: bold;&quot;&gt;ln -s /path/to/stumpwm.asd systems/stumpwm.asd&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Для запуска SLIME необходимо добавить в &lt;span style=&quot;font-style: italic;&quot;&gt;.emacs&lt;/span&gt; следующие строки, полученные при выполнении команды &lt;span style=&quot;font-weight: bold;&quot;&gt;$ ./clbuild slime-configuration&lt;/span&gt;:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;(setq load-path (cons &quot;/path/to/clbuild/source/slime&quot; load-path))&lt;br /&gt;(setq load-path (cons &quot;/path/to/clbuild/source/slime/contrib&quot; load-path))&lt;br /&gt;(setq slime-backend &quot;/path/to/clbuild/.swank-loader.lisp&quot;)&lt;br /&gt;(setq inhibit-splash-screen t)&lt;br /&gt;(load &quot;/path/to/clbuild/source/slime/slime&quot;)&lt;br /&gt;(setq inferior-lisp-program&quot;/path/to/clbuild/clbuild --implementation sbcl lisp&quot;)&lt;br /&gt;(setq slime-use-autodoc-mode nil)&lt;br /&gt;(slime-setup &#39;(slime-fancy slime-tramp slime-asdf))&lt;br /&gt;(slime-require :swank-listener-hooks)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Создадим файл &lt;span style=&quot;font-style: italic;&quot;&gt;startstump&lt;/span&gt; для запуска StumpWM и swank:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;;; -*-lisp-*-&lt;br /&gt;(require :stumpwm)&lt;br /&gt;(require :swank)&lt;br /&gt;(swank-loader::setup)&lt;br /&gt;(swank:create-server :dont-close t)&lt;br /&gt;(stumpwm:stumpwm)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Таким образом теперь для запуска не используетсся собранный с помощью make файл stumpwm, что исключает необходимость повторных сборок при обновлении stumpwm.&lt;br /&gt;&lt;br /&gt;Изменим &lt;span style=&quot;font-style: italic;&quot;&gt;~/.xinitrc&lt;/span&gt;:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;exec /path/to/clbuild/clbuild lisp --load /path/to/startstump&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;clbuild запускает реализацию Common Lisp и загружает созданный нами файл.&lt;br /&gt;&lt;br /&gt;Выполнив &lt;span style=&quot;font-weight: bold;&quot;&gt;startx&lt;/span&gt; и открыв emacs, можно выполнить команду &lt;span style=&quot;font-weight: bold;&quot;&gt;M-x&lt;/span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt; slime-connect&lt;/span&gt; и использовать REPL для внесения измененний. Например, следующие команды сделают стандартную mode-line более информативной:&lt;br /&gt;&lt;pre&gt;; SLIME 2009-05-16&lt;br /&gt;CL-USER&gt; &lt;span style=&quot;font-weight: bold;&quot;&gt;(in-package :stumpwm)&lt;/span&gt;&lt;br /&gt;STUMPWM&gt; &lt;span style=&quot;font-weight: bold;&quot;&gt;(load-module &quot;battery-portable&quot;)&lt;/span&gt;&lt;br /&gt;T&lt;br /&gt;STUMPWM&gt; &lt;span style=&quot;font-weight: bold;&quot;&gt;(load-module &quot;cpu&quot;)&lt;/span&gt;&lt;br /&gt;T&lt;br /&gt;STUMPWM&gt; &lt;span style=&quot;font-weight: bold;&quot;&gt;(load-module &quot;mem&quot;)&lt;/span&gt;&lt;br /&gt;T&lt;br /&gt;STUMPWM&gt; &lt;span style=&quot;font-weight: bold;&quot;&gt;(load-module &quot;net&quot;)&lt;/span&gt;&lt;br /&gt;T&lt;br /&gt;STUMPWM&gt; &lt;span style=&quot;font-weight: bold;&quot;&gt;(setf stumpwm:*screen-mode-line-format*&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;            (list &quot;%n | &quot;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;                  &#39;(:eval (run-shell-command &quot;date +&#39;%a %d %b %H:%M:%S&#39; | tr -d [:cntrl:]&quot; t))&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;                  &quot; | %l| %c| %M| %B | %W&quot;))&lt;/span&gt;&lt;br /&gt;(&quot;%n | &quot;&lt;br /&gt;(:EVAL (RUN-SHELL-COMMAND &quot;date +&#39;%a %d %b %H:%M:%S&#39; | tr -d [:cntrl:]&quot; T))&lt;br /&gt;&quot; | %l| %c| %M| %B | %W&quot;)&lt;br /&gt;STUMPWM&gt; &lt;span style=&quot;font-weight: bold;&quot;&gt;(mode-line)&lt;/span&gt;&lt;br /&gt;NIL&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://tymmym.blogspot.com/feeds/324328158718632423/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://tymmym.blogspot.com/2009/05/stumpwm.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733819446652035433/posts/default/324328158718632423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733819446652035433/posts/default/324328158718632423'/><link rel='alternate' type='text/html' href='http://tymmym.blogspot.com/2009/05/stumpwm.html' title='StumpWM'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>