<?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:geniepro</id>
  <title>The Little Haskeller</title>
  <subtitle>to iterate is human; to recure - divine!</subtitle>
  <author>
    <name>geniepro</name>
  </author>
  <link rel="alternate" type="text/html" href="http://geniepro.livejournal.com/"/>
  <link rel="self" type="text/xml" href="http://geniepro.livejournal.com/data/atom"/>
  <updated>2008-01-28T18:27:09Z</updated>
  <lj:journal username="geniepro" type="personal"/>
  <link rel="service.feed" type="application/x.atom+xml" href="http://geniepro.livejournal.com/data/atom" title="The Little Haskeller"/>
  <entry>
    <id>urn:lj:livejournal.com:atom1:geniepro:3473</id>
    <link rel="alternate" type="text/html" href="http://geniepro.livejournal.com/3473.html"/>
    <link rel="self" type="text/xml" href="http://geniepro.livejournal.com/data/atom/?itemid=3473"/>
    <title>Занятные ЖЖ</title>
    <published>2008-01-28T18:27:09Z</published>
    <updated>2008-01-28T18:27:09Z</updated>
    <category term="must+read"/>
    <content type="html">Просто не могу не пропиарить два ЖЖ, на которые я наткнулся недавно:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://corpuscula.livejournal.com/"&gt;Культовый Журнал&lt;/a&gt; некоей Корпускулы (Насти)&lt;br /&gt;и&lt;br /&gt;&lt;a href="http://ab-pokoj.livejournal.com/"&gt;ЖЖ Истинного Учителя Истины&lt;/a&gt; Авраама Болеслава Покоя.&lt;br /&gt;&lt;br /&gt;Несмотря на такие странные названия эти выдающиеся ЖЖ просто must read! :о)</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:geniepro:2840</id>
    <link rel="alternate" type="text/html" href="http://geniepro.livejournal.com/2840.html"/>
    <link rel="self" type="text/xml" href="http://geniepro.livejournal.com/data/atom/?itemid=2840"/>
    <title>Побег от Зурга</title>
    <published>2007-11-26T18:21:49Z</published>
    <updated>2008-01-20T20:13:45Z</updated>
    <category term="haskell"/>
    <category term="zurg"/>
    <content type="html">Я тут как-то на досуге перевёл статью Мартина Эрвига "Побег от Зурга". В этой статье показывается, как на Хаскелле решаются типичные прологовские задачи поиска с возвратом, и рассказывается, что Хаскелл гораздо проще для студентов, чем Пролог...&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;Побег от Зурга&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Упражнение в логическом программировании&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Мартин ЭРВИГ&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;School of EECS, Oregon State University, Corvallis, Oregon 97331, USA&lt;br /&gt;(e-mail: erwig@cs.orst.edu)&lt;br /&gt;&lt;br /&gt;Оригинал статьи: &lt;a href="http://web.engr.oregonstate.edu/~erwig/papers/Zurg_JFP04.pdf"&gt;http://web.engr.oregonstate.edu/~erwig/papers/Zurg_JFP04.pdf&lt;/a&gt;&lt;br /&gt;&lt;/center&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;center&gt;Аннотация&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;В этой статье мы покажем, как современные функциональные языки, например, Хаскелл, могут эффективно использоваться для решения поисковых задач, вопреки широко распространённому мнению, что для подобных задач лучше подходит Пролог.&lt;br /&gt;&lt;br /&gt;&lt;a name="cutid1"&gt;&lt;/a&gt;&lt;br /&gt;&lt;center&gt;&lt;a name="#chapter1"&gt;1. Введение&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Принято считать, что Пролог - наиболее подходящий язык для решения поисковых задач. Одна из сильных черт Пролога - его встроенный поиск с возвратами (бэктрекинг), который может значительно сократить работу в поисковых задачах. С другой стороны, Хаскелл (Peyton Johnes, 2003) предоставляет мощную систему типов, функции высшего порядка и отложенные (ленивые) вычисления. Мы хотим показать в этой статье, что эти свойства, взятые вместе, позволяют выражать и решать поисковые задачи на Хаскелле так же легко, как и на Прологе (и, возможно, даже легче). Например, отложенные вычисления облегчают краткое описание пространства поиска, поскольку спецификация бесконечной структуры данных - дерева перебора - может быть записана без зацикливания, так как вычисляется только конечная её часть. Эта идея не нова, она была описана раньше Филом Вадлером (Wadler, 1985). Тем не менее, переписывание кода в каждой поисковой задаче из-за малейшей мелочи - скучно, ненадёжно, и может отвлекать от самой реализуемой поисковой задачи. Концепция классов типов (далее просто классов) в Хаскелле предлагает простой способ сформулировать решение один раз и повторно использовать его в разных случаях. К тому же, типы данных Хаскелла позволяют (и в некоторой степени заставляют) формулировать задачу в адекватной форме. &lt;br /&gt;&lt;br /&gt;Альтернативный подход - встраивание Пролого-подобного языка в функциональный язык. Это было продемонстрировано для Хаскелла (Seres &amp; Spivey, 1999; Claessen &amp; LjunglЁo, 2000) и Scheme (Haynes, 1987). Однако, наша цель - выразить поисковые задачи функционально, без применения мультипарадигмального подхода.&lt;br /&gt;&lt;br /&gt;Пример, который мы рассмотрим - это домашнее задание, которое мы даём в аспирантском курсе языков программирования (Erwig, Fall 2001). Эта задача была одним из нескольких упражнений по практикуму программирования на Прологе. После наблюдений того, как многие студенты испытывают сложности в манипулировании структурами термов в Прологе (уже после изучения использования типов данных в Хаскелле) и тратят много времени на отладку, возник вопрос, насколько сложно разработать решение этой задачи на Хаскелле. Это программистское упражнение получилось успешным, о чём мы и мы сообщаем в этой статье.&lt;br /&gt;&lt;br /&gt;В оставшейся части статьи мы опишем требования к обучению программированию поисковых задач на Хаскелле в &lt;a href="#chapter2"&gt;главе 2&lt;/a&gt;. В &lt;a href="#chapter3"&gt;главе 3&lt;/a&gt; описан пример задачи. В &lt;a href="#chapter4"&gt;главе 4&lt;/a&gt; мы покажем решение задачи на Прологе. &lt;a href="#chapter5"&gt;Глава 5&lt;/a&gt; представляет решение задачи Хаскелле. Завершают статью выводы, данные в &lt;a href="#chapter6"&gt;разделе 6&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;center&gt;&lt;a name="#chapter2"&gt;2. Обучение поисковому программированию на Хаскелле&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Что бы изучать поисковое программирование на Хаскелле, как это показано здесь, студенты должны хорошо понимать основные концепции функционального программирования, такие как рекурсия, списки и функции высшего порядка. Также, студенты должны понимать концепции классов, типов данных и отложенных вычислений, поскольку они используются для создания модульного решения.&lt;br /&gt;&lt;br /&gt;Во-первых, классы используются для разделения общего описания поисковых задач от частной задачи. В частности, мы используем мультипараметрические классы для параметризации поисковой задачи типом состояний и типом ходов. Нет необходимости углублённо знать мультипараметрические классы. Фактически, класс SearchProblem может служить мотивационным примером для введения в мультипараметрические классы. Сам класс может быть разработан поэтапно. В начале может быть определена версия с одним параметром (переменной типа), которая параметризуется только типом состояний поиска. Затем, обнаружив, что для некоторых поисковых задач, как, для той, например, что обсуждается здесь, состояния решений не так интересны, как предшествовавшие им ходы, может быть произведено обобщение до двух параметров - переменных типов.&lt;br /&gt;&lt;br /&gt;Во-вторых, в выбранном примере типы данных используются для создания модели приложения. Типы предоставляют высокоуровневые средства для моделирования приложения, в отличии от кодирования кусочков информации плоскими списками и кортежами. Также, инкапсуляция общего поискового процесса в класс помогает полностью сфокусироваться на моделировании задачи, так как мы не возимся с поиском. Это похоже на Пролог, в котором процедура поиска встроена в язык. Тем не менее, по сравнению с термами Пролога типы данных Хаскелла дают типизированное представление с непосредственным указанием о неправильных комбинациях ходов и состояний, которые иначе, при использовании нетипизированного представления, вызывают множество усилий по отладке.&lt;br /&gt;&lt;br /&gt;В-третьих, знание отложенных вычислений необходимо для понимания того, как в Хаскелле может быть представлено потенциально бесконечное пространство поиска. Простой поиск в ширину реализуется созданием списка состояний путём повторяющегося добавления последующих состояний. В зависимости от желания и наличия свободного времени для работы с поисковым программированием, можно изучить этот аспект глубже. Например, относительно просто обобщить класс, параметризуя создание пространства поиска поисковой стратегией. Также, поскольку поисковая задача изолирована в класс, это изменение не затрагивает модель приложения.&lt;br /&gt;&lt;br /&gt;Реализация поисковых задач обсуждалась всего лишь в нескольких книгах по ML и Хаскеллу. Например, Паульсон описал реализацию поискового программирования на ML для доказательства теорем (Paulson, 1996). Раби и Лапальм описывали, как реализовать алгоритмы бектрекинга на Хаскелле (Rabhi &amp; Lapalme, 1999). Они использовали явно определённый алгоритм поиска в глубину и не использовали классы для отделения класса задачи от приложений. В частности, они не выделяли отдельный тип для ходов, который может описать подход независимо от примера задачи, обсуждающейся здесь. Фелляйсен и др. описывали в своей книге (Felleisen et al., 2001) похожий пример, задачу о трёх миссионерах и каннибалах, пересекающих реку. Этот пример был дан как упражнение по программирования с использованием рекурсии и накопительных параметров (аккумуляторов), которые очень подробно обсуждаются как средство хранения контекстной информации в рекурсивных функциях.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;center&gt;&lt;a name="#chapter3"&gt;3. Пример задачи&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Задача, которая будет решаться, называется "Побег от Зурга" и сформулирована так:&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Базз, Вуди, Рекс и Хэмм убегают от Зурга&lt;a href="#rem1"&gt;*&lt;/a&gt;. Им осталось только перейти через последний мост, и они будут свободны. Однако, мост очень ветхий и сможет одновременно выдержать только двоих из них. Также, что бы перейти мост и не попасть в ловушки и ямы в нём, нужен фонарик. Проблема в том, что у наших четырёх друзей всего один фонарик и заряда батареи в нём осталось всего лишь на 60 (шестьдесят) минут. Игрушки могут перейти мост в одну сторону за различное время:&lt;br /&gt;&lt;pre&gt;
Игрушка      Время
Базз        5 минут
Вуди       10 минут
Рекс       20 минут
Хэмм       25 минут
&lt;/pre&gt;&lt;br /&gt;Так как одновременно на мосту могут находиться только две игрушки, они не могут перейти мост сразу все вместе. Так как им нужен фонарик для перехода через мост, кому-то из двоих, перешедших через мост, нужно будет вернуться к оставшимся игрушкам, что бы отдать им фонарик.&lt;br /&gt;&lt;br /&gt;Итак, задача такова: в каком порядке эти четыре игрушки должны пересечь мост за время не более 60 минут, что бы спастись от Зурга?&lt;br /&gt;&lt;br /&gt;Попробуйте решить задачку на своём любимом языке программирования.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;a name="#rem1"&gt;*&lt;/a&gt; Это персонажи из мультфильма "Игрушечная история 2" (Toy Story 2)&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;center&gt;&lt;a name="#chapter4"&gt;4. Решение на Прологе&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Написание на Прологе программы для решения загадки - это, в принципе, простая задача - хотя бы раз было показано, как представлять задачу. Как оказалось, это было главной причиной того, что довольно мало студентов имели проблемы с этим заданием. Самой сложной для студентов частью было определение подходящего представления термов для состояний поисковой задачи, в данном случае - положения игрушек на той или другой стороне моста и положение фонарика. В частности, две основные ошибки заключались в использовании слишком сложных структур термов или предикатов и в использовании несовместимых термов, или даже в некоторых случаях в смешивании предикатов и термов. Некоторые программы зацикливались. Образец решения показан во врезке 1 для сравнения с решением на Хаскелле, которое будет разработано в следующей главе.&lt;br /&gt;&lt;hr&gt;&lt;pre&gt;&lt;font face="Lucida Console"&gt;
&lt;font color="#000000"&gt;time(buzz,  &lt;/font&gt;&lt;font color="#800080"&gt;5&lt;/font&gt;&lt;font color="#000000"&gt;).&lt;/font&gt;
&lt;font color="#000000"&gt;time(woody,&lt;/font&gt;&lt;font color="#800080"&gt;10&lt;/font&gt;&lt;font color="#000000"&gt;).&lt;/font&gt;
&lt;font color="#000000"&gt;time(rex,  &lt;/font&gt;&lt;font color="#800080"&gt;20&lt;/font&gt;&lt;font color="#000000"&gt;).&lt;/font&gt;
&lt;font color="#000000"&gt;time(hamm, &lt;/font&gt;&lt;font color="#800080"&gt;25&lt;/font&gt;&lt;font color="#000000"&gt;).&lt;/font&gt;

&lt;font color="#000000"&gt;toys([buzz,hamm,rex,woody]).&lt;/font&gt;

&lt;font color="#000000"&gt;cost([],&lt;/font&gt;&lt;font color="#800080"&gt;0&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#008000"&gt;- &lt;/font&gt;&lt;font color="#000000"&gt;!.&lt;/font&gt;
&lt;font color="#000000"&gt;cost([X|L],C) &lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#008000"&gt;-&lt;/font&gt;
     &lt;font color="#000000"&gt;time(X,S),&lt;/font&gt;
     &lt;font color="#000000"&gt;cost(L,D),&lt;/font&gt;
     &lt;font color="#000000"&gt;C is &lt;/font&gt;&lt;font color="#008000"&gt;max&lt;/font&gt;&lt;font color="#000000"&gt;(S,D).&lt;/font&gt;

&lt;font color="#000000"&gt;split(L,[X,Y],M) &lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#008000"&gt;-&lt;/font&gt;
     &lt;font color="#000000"&gt;member(X,L),&lt;/font&gt;
     &lt;font color="#000000"&gt;member(Y,L),&lt;/font&gt;
     &lt;font color="#008000"&gt;compare&lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#000000"&gt;,X,Y),&lt;/font&gt;
     &lt;font color="#008000"&gt;subtract&lt;/font&gt;&lt;font color="#000000"&gt;(L,[X,Y],M).&lt;/font&gt;

&lt;font color="#000000"&gt;move(st(l,L1),st(r,L2),r(M),D) &lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#008000"&gt;-&lt;/font&gt;
     &lt;font color="#000000"&gt;split(L1,M,L2),&lt;/font&gt;
     &lt;font color="#000000"&gt;cost(M,D).&lt;/font&gt;

&lt;font color="#000000"&gt;move(st(r,L1),st(l,L2),l(X),D) &lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#008000"&gt;-&lt;/font&gt;
     &lt;font color="#000000"&gt;toys(T),&lt;/font&gt;
     &lt;font color="#008000"&gt;subtract&lt;/font&gt;&lt;font color="#000000"&gt;(T,L1,R),&lt;/font&gt;
     &lt;font color="#000000"&gt;member(X,R),&lt;/font&gt;
     &lt;font color="#000000"&gt;merge_set([X],L1,L2),&lt;/font&gt;
     &lt;font color="#000000"&gt;time(X,D).&lt;/font&gt;

&lt;font color="#000000"&gt;trans(st(r,[]),st(r,[]),[],&lt;/font&gt;&lt;font color="#800080"&gt;0&lt;/font&gt;&lt;font color="#000000"&gt;).&lt;/font&gt;
&lt;font color="#000000"&gt;trans(S,U,L,D) &lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#008000"&gt;-&lt;/font&gt;
     &lt;font color="#000000"&gt;move(S,T,M,X),&lt;/font&gt;
     &lt;font color="#000000"&gt;trans(T,U,N,Y),&lt;/font&gt;
     &lt;font color="#000000"&gt;append([M],N,L),&lt;/font&gt;
     &lt;font color="#000000"&gt;D is X &lt;/font&gt;&lt;font color="#008000"&gt;+ &lt;/font&gt;&lt;font color="#000000"&gt;Y.&lt;/font&gt;

&lt;font color="#000000"&gt;cross(M,D) &lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#008000"&gt;-&lt;/font&gt;
     &lt;font color="#000000"&gt;toys(T),&lt;/font&gt;
     &lt;font color="#000000"&gt;trans(st(l,T),st(r,[]),M,D0),&lt;/font&gt;
     &lt;font color="#000000"&gt;D0&lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#000000"&gt;D.&lt;/font&gt;

&lt;font color="#000000"&gt;solution(M) &lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#008000"&gt;- &lt;/font&gt;&lt;font color="#000000"&gt;cross(M,&lt;/font&gt;&lt;font color="#800080"&gt;60&lt;/font&gt;&lt;font color="#000000"&gt;).&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;&lt;br /&gt;Врезка 1. Решение головоломки Зурга на Прологе.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;Идея программы на Прологе заключается в представлении промежуточных состояний переходов через мост фактами вида &lt;b&gt;st(P,L)&lt;/b&gt;, где &lt;b&gt;L&lt;/b&gt; - список игрушек, находящихся в данный момент на левой стороне моста, а &lt;b&gt;P&lt;/b&gt; - признак, показывающий положение фонарика (левая или правая сторона)&lt;a href="#rem2"&gt;**&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Предикат &lt;b&gt;move/4&lt;/b&gt; генерирует ходы в своём третьем аргументе; переход направо генерируется в случае, если фонарик находится на левой стороне, и наоборот; ход также связывает старое состояние (первый аргумент) с полученным новым состоянием (второй аргумент). Последний аргумент выдаёт время, необходимое для хода.&lt;br /&gt;&lt;br /&gt;В случае перехода направо время определяется дополнительным предикатом &lt;b&gt;cost/2&lt;/b&gt;, вычисляющим максимальное время, необходимое группе игрушек. Каждая допустимая группа игрушек, двигающаяся направо, вычисляется предикатом &lt;b&gt;split/3&lt;/b&gt;, выдающий списки длины 2, которые отсортированы для избежания избыточности, полученной представлением групп игрушек в списках.&lt;br /&gt;&lt;br /&gt;При переходе налево есть смысл посылать назад только одну игрушку. Поэтому определение хода в этом случае использует предопределённый предикат &lt;b&gt;member/2&lt;/b&gt; и вычисляет время, просто просматривая таблицу &lt;b&gt;time/2&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Наконец, предикат &lt;b&gt;trans/4&lt;/b&gt; в основном генерирует все возможные переходы через мост вместе с требуемым временем, тогда как предикат &lt;b&gt;cross/2&lt;/b&gt; формулирует поисковую задачу, задавая начальную и конечную конфигурации пространства поиска.&lt;br /&gt;&lt;hr&gt;&lt;a name="#rem2"&gt;**&lt;/a&gt; Фактически, наиболее общим в студенческих решениях был подход, представляющий две группы игрушек по обе стороны моста, но мы находим, что, хотя эта избыточность может помочь в обдумывании задачи, попытка сохранения инварианта была главным источником ошибок.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;center&gt;&lt;a name="chapter5"&gt;5. Решение на Хаскелле&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Решение на Хаскелле мы получаем в два этапа. Во-первых, мы извлекаем общую структуру поисковой задачи и храним её в определении класса. Во-вторых, мы представляем программу решения головоломки как экземпляр этого класса.&lt;br /&gt;&lt;br /&gt;Главные элементы задачи - это состояния (представляющие промежуточные стадии переходов через мост) и ходы (представляющие переходы между состояниями, в данном случае - пересечения моста). Поэтому мы определили класс &lt;b&gt;SearchProblem&lt;/b&gt; с двумя переменными-типами &lt;b&gt;s&lt;/b&gt; и &lt;b&gt;m&lt;/b&gt;. Далее, мы обдумаем, какие методы нужны классу &lt;b&gt;SearchProblem&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Для построения полного поискового пространства, начинающегося с некоторого (начального) состояния &lt;b&gt;s&lt;/b&gt;, нужна функция, определяющая, какие могут новые состояния быть получены из &lt;b&gt;s&lt;/b&gt;. В общем, это не только конечное состояние, что нас интересует (фактически, в данном примере мы уже знаем это состояние, а именно, все игрушки на другой стороне). Скорее, нам нужна последовательность ходов, ведущая к этому состоянию.&lt;br /&gt;&lt;br /&gt;Поэтому, мы добавили в класс функцию, вычисляющую для состояния список допустимых ходов и новых состояний, к которым они ведут:&lt;br /&gt;&lt;pre&gt;&lt;font face="Lucida Console"&gt;
&lt;font color="#000000"&gt;trans &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;[(m,s)]&lt;/font&gt;
&lt;/font&gt;&lt;/pre&gt;&lt;br /&gt;Повторяющимся применением функции &lt;b&gt;trans&lt;/b&gt; к листьям дерева перебора может быть построено полное пространство поиска. Это пространство поиска представлено элементами типа &lt;b&gt;Space m s&lt;/b&gt; и построено функцией &lt;b&gt;space&lt;/b&gt;, которая отображает состояние в список всех узлов пространства поиска. Каждый узел образует пару со списком ходов, ведущих к нему.&lt;br /&gt;&lt;br /&gt;Так как пространство поиска полностью представляется начальным состоянием и функцией &lt;b&gt;trans&lt;/b&gt;, функция &lt;b&gt;space&lt;/b&gt; является производным методом класса &lt;b&gt;SearchProblem&lt;/b&gt;. Описание &lt;b&gt;space&lt;/b&gt; показывает важность использования отложенных вычислений: &lt;b&gt;space&lt;/b&gt; ссылается на себя (косвенно через expand) без условия завершения; при строгом вычислении это определение будет, в общем, зацикливающимся. В данном примере это означает, что достаточно учесть всего два случая в определении функции &lt;b&gt;trans&lt;/b&gt; (см. врезку 3); дополнительное определение&lt;br /&gt;&lt;pre&gt;&lt;font face="Lucida Console"&gt;&lt;font color="#000000"&gt;trans (R,[]) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[]&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;&lt;br /&gt;не нужно, хотя это условие необходимо в программе на Прологе (сравните первое предложение в предикате &lt;b&gt;trans&lt;/b&gt;).&lt;br /&gt;&lt;br /&gt;В общем, решения поисковой задачи даны подмножеством её состояний. Выбор решения производится предикатом от состояний и генерируемых ими ходов:&lt;br /&gt;&lt;pre&gt;&lt;font face="Lucida Console"&gt;&lt;font color="#000000"&gt;isSolution &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;([m],s) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Bool&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;&lt;br /&gt;С этим предикатом может быть определён другой метод - &lt;b&gt;solutions&lt;/b&gt;, который имеет тот же тип, что и &lt;b&gt;space&lt;/b&gt;, и который просто выдаёт подмножество состояний, удовлетворяющих условию предиката &lt;b&gt;isSolution&lt;/b&gt;. Определение класса &lt;b&gt;SearchProblem&lt;/b&gt; полностью приведено во врезке 2.&lt;br /&gt;&lt;hr&gt;&lt;pre&gt;&lt;font face="Lucida Console"&gt;&lt;font color="#0000e6"&gt;type &lt;/font&gt;&lt;font color="#000000"&gt;Space m s &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[([m],s)]&lt;/font&gt;

&lt;font color="#0000e6"&gt;class &lt;/font&gt;&lt;font color="#000000"&gt;SearchProblem s m &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;

    &lt;font color="#000000"&gt;trans &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;[(m,s)]&lt;/font&gt;
    &lt;font color="#000000"&gt;isSolution &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;([m],s) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Bool&lt;/font&gt;
    &lt;font color="#000000"&gt;space, solutions &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Space m s&lt;/font&gt;

    &lt;font color="#000000"&gt;space s &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;step &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#000000"&gt;expand step&lt;/font&gt;
      &lt;font color="#0000e6"&gt;where &lt;/font&gt;&lt;font color="#000000"&gt;step &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[ ([m],t) | (m,t) &lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;- &lt;/font&gt;&lt;font color="#000000"&gt;trans s ]&lt;/font&gt;
            &lt;font color="#000000"&gt;expand ss &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[ (ms&lt;/font&gt;&lt;font color="#008000"&gt;++&lt;/font&gt;&lt;font color="#000000"&gt;ns,t) | (ms,s) &lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;- &lt;/font&gt;&lt;font color="#000000"&gt;ss,&lt;/font&gt;
                                       &lt;font color="#000000"&gt;(ns,t) &lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;- &lt;/font&gt;&lt;font color="#000000"&gt;space s ]&lt;/font&gt;

    &lt;font color="#000000"&gt;solutions &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;filter &lt;/font&gt;&lt;font color="#000000"&gt;isSolution . space&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;&lt;br /&gt;Врезка 2. Класс SearchProblem.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;Имея определение схемы решения, программа для решения загадки на Хаскелле нуждается только в моделировании задачи. Самые важные проектные решения - это определения типов &lt;b&gt;BridgePos&lt;/b&gt; и &lt;b&gt;Move&lt;/b&gt;, так как они определяют экземпляр класса &lt;b&gt;SearchProblem&lt;/b&gt;. В &lt;b&gt;BridgePos&lt;/b&gt; мы представляем положение фонарика конструкторами &lt;b&gt;L&lt;/b&gt; или &lt;b&gt;R&lt;/b&gt; и список игрушек, которые находятся на левой стороне моста, точно так же, как и в реализации на Прологе. &lt;br /&gt;&lt;br /&gt;Ход - это или переход группы из двух игрушек слева направо, или обратный переход всего одной игрушки справа налево. Оба вида ходов указаны типом &lt;b&gt;Move&lt;/b&gt;, который определён через тип данных &lt;b&gt;Either&lt;/b&gt;, являющийся предопределённым в Хаскелле, и имеющий конструкторы &lt;b&gt;Left&lt;/b&gt; и &lt;b&gt;Right&lt;/b&gt; для представления несовместимых комбинаций типов.&lt;br /&gt;&lt;hr&gt;&lt;pre&gt;&lt;font face="Lucida Console"&gt;&lt;font color="#0000e6"&gt;data &lt;/font&gt;&lt;font color="#000000"&gt;Toy &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;Buzz | Hamm | Rex | Woody &lt;/font&gt;&lt;font color="#0000e6"&gt;deriving &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Eq&lt;/font&gt;&lt;font color="#000000"&gt;,&lt;/font&gt;&lt;font color="#d200d2"&gt;Ord&lt;/font&gt;&lt;font color="#000000"&gt;,&lt;/font&gt;&lt;font color="#d200d2"&gt;Show&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;
&lt;font color="#0000e6"&gt;data &lt;/font&gt;&lt;font color="#000000"&gt;Pos &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;L | R &lt;/font&gt;&lt;font color="#0000e6"&gt;deriving &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Eq&lt;/font&gt;&lt;font color="#000000"&gt;,&lt;/font&gt;&lt;font color="#d200d2"&gt;Show&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;
&lt;font color="#0000e6"&gt;type &lt;/font&gt;&lt;font color="#000000"&gt;Group &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[Toy]&lt;/font&gt;
&lt;font color="#0000e6"&gt;type &lt;/font&gt;&lt;font color="#000000"&gt;BridgePos &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;(Pos,Group)&lt;/font&gt;
&lt;font color="#0000e6"&gt;type &lt;/font&gt;&lt;font color="#000000"&gt;Move &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#d200d2"&gt;Either &lt;/font&gt;&lt;font color="#000000"&gt;Toy Group&lt;/font&gt;

&lt;font color="#000000"&gt;toys &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;[Toy]&lt;/font&gt;
&lt;font color="#000000"&gt;toys &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[Buzz,Hamm,Rex,Woody]&lt;/font&gt;

&lt;font color="#000000"&gt;time &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;Toy &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Int&lt;/font&gt;
&lt;font color="#000000"&gt;time Buzz  &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#800080"&gt;5&lt;/font&gt;
&lt;font color="#000000"&gt;time Woody &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#800080"&gt;10&lt;/font&gt;
&lt;font color="#000000"&gt;time Rex   &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#800080"&gt;20&lt;/font&gt;
&lt;font color="#000000"&gt;time Hamm  &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#800080"&gt;25&lt;/font&gt;

&lt;font color="#000000"&gt;duration &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;[Move] &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Int&lt;/font&gt;
&lt;font color="#000000"&gt;duration &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;sum &lt;/font&gt;&lt;font color="#000000"&gt;. &lt;/font&gt;&lt;font color="#008000"&gt;map &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#008000"&gt;either &lt;/font&gt;&lt;font color="#000000"&gt;time (&lt;/font&gt;&lt;font color="#008000"&gt;maximum &lt;/font&gt;&lt;font color="#000000"&gt;. &lt;/font&gt;&lt;font color="#008000"&gt;map &lt;/font&gt;&lt;font color="#000000"&gt;time))&lt;/font&gt;

&lt;font color="#000000"&gt;backw &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;Group &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;[(Move,BridgePos)]&lt;/font&gt;
&lt;font color="#000000"&gt;backw xs &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[(&lt;/font&gt;&lt;font color="#d200d2"&gt;Left &lt;/font&gt;&lt;font color="#000000"&gt;x, (L, sort (x&lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#000000"&gt;(toys \\ xs)))) | x &lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;- &lt;/font&gt;&lt;font color="#000000"&gt;xs]&lt;/font&gt;

&lt;font color="#000000"&gt;forw &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;Group &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;[(Move,BridgePos)]&lt;/font&gt;
&lt;font color="#000000"&gt;forw xs &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[(&lt;/font&gt;&lt;font color="#d200d2"&gt;Right &lt;/font&gt;&lt;font color="#000000"&gt;[x,y], (R, delete y ys)) |&lt;/font&gt;
              &lt;font color="#000000"&gt;x &lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;- &lt;/font&gt;&lt;font color="#000000"&gt;xs, &lt;/font&gt;&lt;font color="#0000e6"&gt;let &lt;/font&gt;&lt;font color="#000000"&gt;ys&lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#000000"&gt;delete x xs, y &lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;- &lt;/font&gt;&lt;font color="#000000"&gt;ys, x &lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt; &lt;/font&gt;&lt;font color="#000000"&gt;y]&lt;/font&gt;

&lt;font color="#0000e6"&gt;instance &lt;/font&gt;&lt;font color="#000000"&gt;SearchProblem BridgePos Move &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;

    &lt;font color="#000000"&gt;trans (L,l) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;forw l&lt;/font&gt;
    &lt;font color="#000000"&gt;trans (R,l) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;backw (toys \\ l)&lt;/font&gt;

    &lt;font color="#000000"&gt;isSolution (ms,s) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#0000e6"&gt;== &lt;/font&gt;&lt;font color="#000000"&gt;(R,[]) &amp;amp;&amp;amp; duration ms &lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#800080"&gt;60&lt;/font&gt;

&lt;font color="#000000"&gt;solution &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;Space Move BridgePos&lt;/font&gt;
&lt;font color="#000000"&gt;solution &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;solutions (L,toys)&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;&lt;br /&gt;Врезка 3. Решение головоломки Зурга на Хаскелле.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;Кроме определения типов для представления объектов в программе, важная часть -- это определение экземпляра класса &lt;b&gt;SearchProblem&lt;/b&gt;, который предназначен для того, что бы дать определения функций &lt;b&gt;trans&lt;/b&gt; и &lt;b&gt;isSolution&lt;/b&gt;. И наконец, мы определили три вспомогательные функции: &lt;b&gt;forw&lt;/b&gt; и &lt;b&gt;backw&lt;/b&gt; для вычисления ходов игрушек и &lt;b&gt;duration&lt;/b&gt; для вычисления общего времени перехода, в данном случае, для последовательности ходов. Напомним, что функция &lt;b&gt;(\\)&lt;/b&gt; вычисляет разность двух списков. Определение предиката &lt;b&gt;isSolution&lt;/b&gt; очевидно. Полный текст решения задачи на Хаскелле приведено во врезке 3.&lt;br /&gt;&lt;br /&gt;Мы уже упоминали, что класс &lt;b&gt;SearchProblem&lt;/b&gt; во врезке 2 реализует простой поиск в ширину. Можно получить обобщение абстрагированием операции добавления сгенерированных новых состояний в список состояний; для этого мы вводим в определения &lt;b&gt;space&lt;/b&gt; и &lt;b&gt;solutions&lt;/b&gt; параметр-функцию, контролирующую добавление новых состояний в пространство поиска. Возможная реализация показана во врезке 4.&lt;br /&gt;&lt;hr&gt;&lt;pre&gt;&lt;font face="Lucida Console"&gt;&lt;font color="#0000e6"&gt;type &lt;/font&gt;&lt;font color="#000000"&gt;Space m s &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[([m],s)]&lt;/font&gt;
&lt;font color="#0000e6"&gt;type &lt;/font&gt;&lt;font color="#000000"&gt;Strategy m s &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;Space m s &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Space m s &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Space m s&lt;/font&gt;

&lt;font color="#0000e6"&gt;class &lt;/font&gt;&lt;font color="#000000"&gt;SearchProblem s m &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;

  &lt;font color="#000000"&gt;trans &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;[(m,s)]&lt;/font&gt;
  &lt;font color="#000000"&gt;isSolution &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;([m],s) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Bool&lt;/font&gt;
  &lt;font color="#000000"&gt;space, solutions &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;Strategy m s &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Space m s&lt;/font&gt;

  &lt;font color="#000000"&gt;space f s &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;expand f (step ([],s))&lt;/font&gt;
    &lt;font color="#0000e6"&gt;where &lt;/font&gt;&lt;font color="#000000"&gt;expand f [] &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[]&lt;/font&gt;
          &lt;font color="#000000"&gt;expand f (s&lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#000000"&gt;ss) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#000000"&gt;expand f (f (step s) ss)&lt;/font&gt;
          &lt;font color="#000000"&gt;step (ms,s) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[(ms&lt;/font&gt;&lt;font color="#008000"&gt;++&lt;/font&gt;&lt;font color="#000000"&gt;[m],t) | (m,t) &lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;- &lt;/font&gt;&lt;font color="#000000"&gt;trans s]&lt;/font&gt;

  &lt;font color="#000000"&gt;solutions f &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;filter &lt;/font&gt;&lt;font color="#000000"&gt;isSolution . space f&lt;/font&gt;

&lt;font color="#000000"&gt;dfs &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#008000"&gt;++&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;
&lt;font color="#000000"&gt;bfs &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;flip &lt;/font&gt;&lt;font color="#000000"&gt;dfs&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;&lt;br /&gt;Врезка 4. Обобщённый класс SearchProblem.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;br /&gt;Что бы использовать обобщённый класс в нашем примере, нам нужно всего лишь передать экземпляру класса соответствующую поисковую стратегию функции &lt;b&gt;solutions:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;font face="Lucida Console"&gt;&lt;font color="#000000"&gt;solution &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;solutions bfs (L,toys)&lt;/font&gt;
&lt;/font&gt;&lt;/pre&gt;&lt;br /&gt;Для этого примера задачи поисковая стратегия не влияет на решение, но для других поисковых задач завершение поиска при использовании &lt;b&gt;bfs&lt;/b&gt; более вероятно, чем при использовании &lt;b&gt;dfs&lt;/b&gt;.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;em&gt;Примечание от переводчика:&lt;br /&gt;&lt;br /&gt;Так как мультипараметрические классы типов являются расширением стандарта Haskell 98, для выполнения этой программы на GHC или GHCi следует задать в командной строке опцию &lt;b&gt;-fglasgow-exts&lt;/b&gt;, а в HUGS – опцию &lt;b&gt;-98&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Так же неплохо бы указать импорт модуля &lt;b&gt;List&lt;/b&gt;, который содержит определения нужных программе функций &lt;b&gt;(\\)&lt;/b&gt; и &lt;b&gt;sort&lt;/b&gt;.&lt;/em&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;center&gt;&lt;a name="#chapter6"&gt;6. Выводы&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Давайте сначала просуммируем наш опыт, полученный с приведённым упражнением. Большинство студентов любят задания в виде головоломок, хотя довольно много студентов имеют проблемы при их решении и тратят значительное время на отладку программ. Часть проблем была вызвана неправильным использованием термов, что приводило интерпретатор только к ответу No. Другой ошибкой было смешивание термов и предикатов. В некоторой степени за эту ошибку, возможно, ответственны совершенно разные лексические соглашения в Хаскелле и Прологе: имена переменных начинаются с прописной буквы в Прологе и со строчной в Хаскелле, тогда как имена конструкторов термов начинаются со строчной буквы в Прологе и с прописной - в Хаскелле.&lt;br /&gt;&lt;br /&gt;Некоторые студенты пытались обойти свои проблемы, кодируя знание о решении в их программах, например, зафиксировав количество ходов вперёд и назад в постановке задачи. Некоторые решения, полученные студентами, были близки к показанному во врезке 1, отличаясь в основном в выбранном представлении термов и в том, как был определён предикат перехода. Неправильное представление термов было главной неприятностью с этими программами, которые не запускались вообще или выдавали неверные результаты.&lt;br /&gt;&lt;br /&gt;Для получения обратной связи с подходом на Хаскелле, нескольких выпускников попросили решить задачу также на Хаскелле. Все они выдали нам определение класса SearchProblem. Те студенты, которые уже получили верные решения на Прологе, сообщили, что было легко получить соответствующее решение на Хаскелле. Другие, имевшие неидеальные решения на Прологе, почувствовали, насколько легче было написать программу на Хаскелле, чем на Прологе. Они также сообщили, что система типов помогла в разработке решения и отладке программы.&lt;br /&gt;&lt;br /&gt;Из нашего опыта решения примера задачи на обоих языках мы убедились, что система типов Хаскелла в конце концов делает реализацию поисковых задач на Хаскелле легче, чем на прологе. Наиболее важная особенность Хаскелла, поддерживающая это впечатление, это наличие мультипараметрические классов, поскольку мы можем абстрагировать общую схему решения в класс и повторно использовать его в других задачах.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;center&gt;Благодарности&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Автор благодарит Маттиаса Фелляйсена за его ценные советы и замечания, которые помогли улучшить эту статью. Также большое спасибо студентам кафедры языков программирования, сообщившим о своём опыте с Хаскеллом, Прологом, типами и т.д.&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;center&gt;Ссылки&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Claessen, K., &amp; LjunglЁo, P. (2000). Typed Logical Variables in Haskell. Haskell Workshop. Electronic Notes in Theoretical Computer Science, Vol. 41, No. 1.&lt;br /&gt;&lt;br /&gt;Erwig, M. (Fall 2001). CS 581: Programming Languages. Graduate Course. Department of Computer Science, Oregon State University. &lt;a href="http://www.cs.orst.edu/~erwig/old/cs581.f01"&gt;http://www.cs.orst.edu/~erwig/old/cs581.f01&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Felleisen, M., Findler, R. B., Flatt, M., &amp; Krishnamurthi, S. (2001). How to Design Programs—An Introduction to Programming and Computing. Cambridge, MA: MIT Press.&lt;br /&gt;&lt;br /&gt;Haynes, C. T. (1987). Logic Continuations. The Journal of Logic Programming, 4, 157–176.&lt;br /&gt;&lt;br /&gt;Paulson, L. C. (1996). ML for the Working Programmer (2nd ed.). Cambridge, NY: Cambridge University Press.&lt;br /&gt;&lt;br /&gt;Peyton Jones, S. (2003). Haskell 98 Language and Libraries. Cambridge, UK: Cambridge University Press.&lt;br /&gt;&lt;br /&gt;Rabhi, F., &amp; Lapalme, G. (1999). Algorithms: A Functional Programming Approach. Harlow, England: Addison-Wesley.&lt;br /&gt;&lt;br /&gt;Seres, S., &amp; Spivey, M. (1999). Embedding Prolog in Haskell. Haskell Workshop. Technical Report UU-CS-1999-28, Universiteit Utrecht.&lt;br /&gt;&lt;br /&gt;Wadler, P. (1985). How to Replace Failure by a List of Successes. Pages 113–128 of: Conf. on Functional Programming and Computer Architecture. LNCS 201.</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:geniepro:2722</id>
    <link rel="alternate" type="text/html" href="http://geniepro.livejournal.com/2722.html"/>
    <link rel="self" type="text/xml" href="http://geniepro.livejournal.com/data/atom/?itemid=2722"/>
    <title>Ещё одно решение "Проблемы К" на Хаскелле</title>
    <published>2007-11-11T21:08:14Z</published>
    <updated>2007-11-16T19:07:13Z</updated>
    <category term="haskell"/>
    <category term="problem k"/>
    <content type="html">Я тоже не смог удержаться, и вслед за &lt;a href="http://thesz.livejournal.com/281937.html"&gt;Сергеем Зефировым&lt;/a&gt; и &lt;a href="http://www.haskell.org/haskellwiki/Ru/Problem_K"&gt;Булатом Зиганьшиным&lt;/a&gt; тоже сделал своё решение &lt;a href="http://thesz.livejournal.com/280784.html"&gt;этой задачки&lt;/a&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; - Строки-выражения, которые начинаются с символа '=' и могут содержать неотрицательные целые числа, ссылки на ячейки и простые арифметические выражения. Скобки запрещены, у всех операций одинаковый приоритет. Ссылки на ячейки состоят из одной латинской буквы и следующей за ней цифры.&lt;br /&gt;&lt;a href="http://thesz.livejournal.com/280784.html"&gt;Читать описание полностью...&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Автор задачи, ЖЖ-юзер &lt;span class='ljuser' lj:user='gaperton' style='white-space: nowrap;'&gt;&lt;a href='http://gaperton.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://gaperton.livejournal.com/'&gt;&lt;b&gt;gaperton&lt;/b&gt;&lt;/a&gt;&lt;/span&gt;, опубликовал предысторию этой задачи: &lt;a href="http://gaperton.livejournal.com/6050.html"&gt;"О дизайне и ФП"&lt;/a&gt;, а также &lt;a href="http://www.rsdn.ru/forum/message/2720396.all.aspx"&gt;поделился своим решением задачи на RSDN.ru&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Также стало доступно &lt;a href="http://nggu.livejournal.com/663.html"&gt;модуляризованное решение на Хаскелле&lt;/a&gt; (чего так хотел увидеть Гапертон) от NGGU...&lt;br /&gt;&lt;br /&gt;А вот и моё решение:&lt;hr&gt;&lt;pre&gt;&lt;font face="Lucida Console"&gt;
&lt;font color="#0000e6"&gt;module &lt;/font&gt;&lt;font color="#000000"&gt;Main &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;

&lt;font color="#0000e6"&gt;import &lt;/font&gt;&lt;font color="#d200d2"&gt;Char &lt;/font&gt;&lt;font color="#000000"&gt;(isAlpha, isAlphaNum, isDigit)&lt;/font&gt;
&lt;font color="#0000e6"&gt;import &lt;/font&gt;&lt;font color="#000000"&gt;List (nub, groupBy, sort, (\\), union, intersect)&lt;/font&gt;
&lt;font color="#0000e6"&gt;import &lt;/font&gt;&lt;font color="#000000"&gt;Data.Graph (SCC(CyclicSCC), stronglyConnComp, flattenSCCs)&lt;/font&gt;

&lt;font color="#808080"&gt;--------------------------------------------------------------------------------&lt;/font&gt;
&lt;font color="#808080"&gt;-- | Главная функция: считать со stdin таблицу, вычислить и распечатать в stdout&lt;/font&gt;

&lt;font color="#000000"&gt;main &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;print &lt;/font&gt;&lt;font color="#000000"&gt;. calculate &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;&amp;lt; &lt;/font&gt;&lt;font color="#000000"&gt;getSheet&lt;/font&gt;

&lt;font color="#808080"&gt;--------------------------------------------------------------------------------&lt;/font&gt;
&lt;font color="#808080"&gt;-- Вспомогательные функции&lt;/font&gt;

&lt;font color="#808080"&gt;--------------------------------------------------------------------------------&lt;/font&gt;
&lt;font color="#808080"&gt;-- | Перевёрнутый оператор $&lt;/font&gt;

&lt;font color="#000000"&gt;x |&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;f &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;f x; &lt;/font&gt;&lt;font color="#0000e6"&gt;infixl &lt;/font&gt;&lt;font color="#800080"&gt;0 &lt;/font&gt;&lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt;&lt;/font&gt;

&lt;font color="#808080"&gt;--------------------------------------------------------------------------------&lt;/font&gt;
&lt;font color="#808080"&gt;-- | Считать со stdin таблицу в список табличных строк,&lt;/font&gt;
&lt;font color="#808080"&gt;--   каждая из которых в виде списка столбцов (в строковом представлении)&lt;/font&gt;

&lt;font color="#000000"&gt;getSheet &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#d200d2"&gt;IO &lt;/font&gt;&lt;font color="#000000"&gt;(Sheet &lt;/font&gt;&lt;font color="#d200d2"&gt;Integer&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;
&lt;font color="#000000"&gt;getSheet &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;getIntegralSheet&lt;/font&gt;


&lt;font color="#000000"&gt;getIntegralSheet &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Integral &lt;/font&gt;&lt;font color="#000000"&gt;a, &lt;/font&gt;&lt;font color="#d200d2"&gt;Read &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;IO &lt;/font&gt;&lt;font color="#000000"&gt;(Sheet a)&lt;/font&gt;
&lt;font color="#000000"&gt;getIntegralSheet &lt;/font&gt;&lt;font color="#0000e6"&gt;= do&lt;/font&gt;
    &lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;- getLine&lt;/font&gt;
    &lt;font color="#0000e6"&gt;let &lt;/font&gt;&lt;font color="#000000"&gt;(r&lt;/font&gt;&lt;font color="#0000e6"&gt;:_&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;words &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;
        &lt;font color="#000000"&gt;rows  &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;read &lt;/font&gt;&lt;font color="#000000"&gt;r&lt;/font&gt;
    &lt;font color="#000000"&gt;ss &lt;/font&gt;&lt;font color="#008000"&gt;&amp;lt;- sequence $ replicate &lt;/font&gt;&lt;font color="#000000"&gt;rows &lt;/font&gt;&lt;font color="#008000"&gt;$ getLine&lt;/font&gt;
    &lt;font color="#008000"&gt;return $ read $ &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#800080"&gt;"\n" &lt;/font&gt;&lt;font color="#008000"&gt;++ unlines &lt;/font&gt;&lt;font color="#000000"&gt;ss&lt;/font&gt;
  &lt;font color="#000000"&gt;`&lt;/font&gt;&lt;font color="#008000"&gt;catch&lt;/font&gt;&lt;font color="#000000"&gt;` \_ &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#0000e6"&gt;do&lt;/font&gt;
    &lt;font color="#008000"&gt;return $ read &lt;/font&gt;&lt;font color="#800080"&gt;"1\t1\n'#Error: no data"&lt;/font&gt;

&lt;font color="#808080"&gt;--------------------------------------------------------------------------------&lt;/font&gt;
&lt;font color="#808080"&gt;-- Типы данных&lt;/font&gt;

&lt;font color="#808080"&gt;--------------------------------------------------------------------------------&lt;/font&gt;
&lt;font color="#808080"&gt;-- | Класс типов вычислимых объектов&lt;/font&gt;

&lt;font color="#0000e6"&gt;class &lt;/font&gt;&lt;font color="#000000"&gt;Calculable a &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;
    &lt;font color="#000000"&gt;calculate &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;a &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;a&lt;/font&gt;

&lt;font color="#808080"&gt;--------------------------------------------------------------------------------&lt;/font&gt;
&lt;font color="#808080"&gt;-- | Бинарные операции&lt;/font&gt;

&lt;font color="#0000e6"&gt;type &lt;/font&gt;&lt;font color="#000000"&gt;BinOp a &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;a &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;a &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;a&lt;/font&gt;
&lt;font color="#0000e6"&gt;type &lt;/font&gt;&lt;font color="#000000"&gt;StrOp   &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;BinOp &lt;/font&gt;&lt;font color="#d200d2"&gt;String&lt;/font&gt;

&lt;font color="#808080"&gt;--------------------------------------------------------------------------------&lt;/font&gt;
&lt;font color="#808080"&gt;-- | Результат запроса на вычисление функции Func&lt;/font&gt;

&lt;font color="#0000e6"&gt;data &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Num &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;FResult a&lt;/font&gt;
    &lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;FRErr &lt;/font&gt;&lt;font color="#d200d2"&gt;String                  &lt;/font&gt;&lt;font color="#808080"&gt;-- Ошибка при вычислении&lt;/font&gt;
    &lt;font color="#000000"&gt;| FRNum a                       &lt;/font&gt;&lt;font color="#808080"&gt;-- Результат: число&lt;/font&gt;
    &lt;font color="#000000"&gt;| FRStr &lt;/font&gt;&lt;font color="#d200d2"&gt;String                  &lt;/font&gt;&lt;font color="#808080"&gt;-- Результат: строка&lt;/font&gt;


&lt;font color="#0000e6"&gt;instance &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Show &lt;/font&gt;&lt;font color="#000000"&gt;a, &lt;/font&gt;&lt;font color="#d200d2"&gt;Num &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Show &lt;/font&gt;&lt;font color="#000000"&gt;(FResult a) &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(FRErr s) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#800080"&gt;"#" &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(FRNum n) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;n&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(FRStr s) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;

&lt;font color="#808080"&gt;--------------------------------------------------------------------------------&lt;/font&gt;
&lt;font color="#808080"&gt;-- | Бинарные операции&lt;/font&gt;

&lt;font color="#0000e6"&gt;data &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Num &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Func a&lt;/font&gt;
    &lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;FNum &lt;/font&gt;&lt;font color="#d200d2"&gt;String &lt;/font&gt;&lt;font color="#000000"&gt;(BinOp a)         &lt;/font&gt;&lt;font color="#808080"&gt;-- Арифметическая функция&lt;/font&gt;
    &lt;font color="#000000"&gt;| FStr &lt;/font&gt;&lt;font color="#d200d2"&gt;String &lt;/font&gt;&lt;font color="#000000"&gt;StrOp             &lt;/font&gt;&lt;font color="#808080"&gt;-- Строковая функция&lt;/font&gt;
    &lt;font color="#000000"&gt;| FErr &lt;/font&gt;&lt;font color="#d200d2"&gt;String                   &lt;/font&gt;&lt;font color="#808080"&gt;-- Недопустимая функция&lt;/font&gt;
    &lt;font color="#000000"&gt;| FQrN (Func a) a a             &lt;/font&gt;&lt;font color="#808080"&gt;-- Запрос на вычисление арифмет. функции&lt;/font&gt;
    &lt;font color="#000000"&gt;| FQrS (Func a) &lt;/font&gt;&lt;font color="#d200d2"&gt;String String   &lt;/font&gt;&lt;font color="#808080"&gt;-- Запрос на вычисление строковой функции&lt;/font&gt;
    &lt;font color="#000000"&gt;| FRes (FResult a)              &lt;/font&gt;&lt;font color="#808080"&gt;-- И результат вычисление&lt;/font&gt;


&lt;font color="#0000e6"&gt;instance &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Show &lt;/font&gt;&lt;font color="#000000"&gt;a, &lt;/font&gt;&lt;font color="#d200d2"&gt;Num &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Show &lt;/font&gt;&lt;font color="#000000"&gt;(Func a) &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(FNum s &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;)            &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(FStr s &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;)            &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(FQrN (FNum s &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;) a b) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;a &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#008000"&gt;++ show &lt;/font&gt;&lt;font color="#000000"&gt;b&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(FQrS (FStr s &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;) a b) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;a &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#008000"&gt;++ show &lt;/font&gt;&lt;font color="#000000"&gt;b&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(FRes r)              &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;r&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#0000e6"&gt;_                     = &lt;/font&gt;&lt;font color="#800080"&gt;"_?_"&lt;/font&gt;


&lt;font color="#0000e6"&gt;instance &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Integral &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Read &lt;/font&gt;&lt;font color="#000000"&gt;(Func a) &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;
    &lt;font color="#008000"&gt;readsPrec &lt;/font&gt;&lt;font color="#0000e6"&gt;_ &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[(&lt;/font&gt;&lt;font color="#0000e6"&gt;case &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#0000e6"&gt;of&lt;/font&gt;
                        &lt;font color="#800080"&gt;"+"  &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;FNum s (&lt;/font&gt;&lt;font color="#008000"&gt;+&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;
                        &lt;font color="#800080"&gt;"-"  &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;FNum s (&lt;/font&gt;&lt;font color="#008000"&gt;-&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;
                        &lt;font color="#800080"&gt;"*"  &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;FNum s (*)&lt;/font&gt;
                        &lt;font color="#800080"&gt;"/"  &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;FNum s &lt;/font&gt;&lt;font color="#008000"&gt;div&lt;/font&gt;
                        &lt;font color="#800080"&gt;"^"  &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;FNum s (&lt;/font&gt;&lt;font color="#008000"&gt;^&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;
                        &lt;font color="#800080"&gt;"++" &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;FStr s (&lt;/font&gt;&lt;font color="#008000"&gt;++&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;
                        &lt;font color="#800080"&gt;"--" &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;FStr s (\\)&lt;/font&gt;
                        &lt;font color="#800080"&gt;"**" &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;FStr s union&lt;/font&gt;
                        &lt;font color="#800080"&gt;"//" &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;FStr s intersect&lt;/font&gt;
                        &lt;font color="#000000"&gt;s    &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;FErr s&lt;/font&gt;
                    &lt;font color="#000000"&gt;, &lt;/font&gt;&lt;font color="#800080"&gt;""&lt;/font&gt;&lt;font color="#000000"&gt;)]&lt;/font&gt;


&lt;font color="#0000e6"&gt;instance &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Num &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Calculable (Func a) &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;
    &lt;font color="#808080"&gt;----------------------------------------------------------------------------&lt;/font&gt;
    &lt;font color="#808080"&gt;-- Безопасное вычисление арифметической операции&lt;/font&gt;

    &lt;font color="#000000"&gt;calculate (FQrN (FErr s)     &lt;/font&gt;&lt;font color="#0000e6"&gt;_ _&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;FRes &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;FRErr &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#800080"&gt;"Op:" &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;
    &lt;font color="#000000"&gt;calculate (FQrS (FErr s)     &lt;/font&gt;&lt;font color="#0000e6"&gt;_ _&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;FRes &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;FRErr &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#800080"&gt;"Op:" &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;
    &lt;font color="#000000"&gt;calculate (FQrN (FNum &lt;/font&gt;&lt;font color="#800080"&gt;"/" &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;) a &lt;/font&gt;&lt;font color="#800080"&gt;0&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;FRes &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;FRErr &lt;/font&gt;&lt;font color="#800080"&gt;"Inf"&lt;/font&gt;
    &lt;font color="#000000"&gt;calculate (FQrN (FNum  &lt;/font&gt;&lt;font color="#0000e6"&gt;_  &lt;/font&gt;&lt;font color="#000000"&gt;f) a b) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;FRes &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;FRNum &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;a `f` b&lt;/font&gt;
    &lt;font color="#000000"&gt;calculate (FQrN (FStr  &lt;/font&gt;&lt;font color="#0000e6"&gt;_  _&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;_ _&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;FRes &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;FRErr &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#800080"&gt;"StrOp on Numbers"&lt;/font&gt;
    &lt;font color="#000000"&gt;calculate (FQrS (FStr  &lt;/font&gt;&lt;font color="#0000e6"&gt;_  &lt;/font&gt;&lt;font color="#000000"&gt;f) a b) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;FRes &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;FRStr &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;a `f` b&lt;/font&gt;
    &lt;font color="#000000"&gt;calculate (FQrS (FNum  &lt;/font&gt;&lt;font color="#0000e6"&gt;_  _&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;_ _&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;FRes &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;FRErr &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#800080"&gt;"NumOp on Strings"&lt;/font&gt;
    &lt;font color="#000000"&gt;calculate &lt;/font&gt;&lt;font color="#0000e6"&gt;_                       = &lt;/font&gt;&lt;font color="#000000"&gt;FRes &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;FRErr &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#800080"&gt;"Query"&lt;/font&gt;

&lt;font color="#808080"&gt;--------------------------------------------------------------------------------&lt;/font&gt;
&lt;font color="#808080"&gt;-- | Содержимое ячейки таблицы&lt;/font&gt;

&lt;font color="#0000e6"&gt;type &lt;/font&gt;&lt;font color="#000000"&gt;IdCell a &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;String&lt;/font&gt;&lt;font color="#000000"&gt;, Cell a)&lt;/font&gt;

&lt;font color="#0000e6"&gt;data &lt;/font&gt;&lt;font color="#000000"&gt;Cell a&lt;/font&gt;
    &lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;CNull                               &lt;/font&gt;&lt;font color="#808080"&gt;-- Пустая ячейка&lt;/font&gt;
    &lt;font color="#000000"&gt;| CNum a                              &lt;/font&gt;&lt;font color="#808080"&gt;-- Целочисленная константа&lt;/font&gt;
    &lt;font color="#000000"&gt;| CRef &lt;/font&gt;&lt;font color="#d200d2"&gt;String                         &lt;/font&gt;&lt;font color="#808080"&gt;-- Ссылка на ячейку&lt;/font&gt;
    &lt;font color="#000000"&gt;| CStr &lt;/font&gt;&lt;font color="#d200d2"&gt;String                         &lt;/font&gt;&lt;font color="#808080"&gt;-- Строковая константа&lt;/font&gt;
    &lt;font color="#000000"&gt;| CErr &lt;/font&gt;&lt;font color="#d200d2"&gt;String                         &lt;/font&gt;&lt;font color="#808080"&gt;-- Ячейка с какой-то ошибкой&lt;/font&gt;
    &lt;font color="#000000"&gt;| CFun (Func   a) (Cell  a) (Cell a)  &lt;/font&gt;&lt;font color="#808080"&gt;-- Формула&lt;/font&gt;
    &lt;font color="#000000"&gt;| CQry (IdCell a) (Sheet a)           &lt;/font&gt;&lt;font color="#808080"&gt;-- Запрос на вычисление ячейки в контексте таблицы&lt;/font&gt;


&lt;font color="#0000e6"&gt;instance &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Show &lt;/font&gt;&lt;font color="#000000"&gt;a, &lt;/font&gt;&lt;font color="#d200d2"&gt;Integral &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Show &lt;/font&gt;&lt;font color="#000000"&gt;(Cell a) &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;
    &lt;font color="#008000"&gt;show  &lt;/font&gt;&lt;font color="#000000"&gt;CNull       &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#800080"&gt;" "&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(CNum n)     &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;n&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(CRef s)     &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(CStr s)     &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(CErr s)     &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#800080"&gt;"#" &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(CFun f x y) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;x &lt;/font&gt;&lt;font color="#008000"&gt;++ show &lt;/font&gt;&lt;font color="#000000"&gt;f &lt;/font&gt;&lt;font color="#008000"&gt;++ show &lt;/font&gt;&lt;font color="#000000"&gt;y&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(CQry c sh)  &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;c &lt;/font&gt;&lt;font color="#008000"&gt;++ show &lt;/font&gt;&lt;font color="#000000"&gt;sh&lt;/font&gt;


&lt;font color="#0000e6"&gt;instance &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Read &lt;/font&gt;&lt;font color="#000000"&gt;a, &lt;/font&gt;&lt;font color="#d200d2"&gt;Integral &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Read &lt;/font&gt;&lt;font color="#000000"&gt;(Cell a) &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;
    &lt;font color="#008000"&gt;readsPrec &lt;/font&gt;&lt;font color="#0000e6"&gt;_ &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[(parse s, &lt;/font&gt;&lt;font color="#800080"&gt;""&lt;/font&gt;&lt;font color="#000000"&gt;)]&lt;/font&gt;
      &lt;font color="#0000e6"&gt;where&lt;/font&gt;
        &lt;font color="#808080"&gt;-- Разбор ячейки из строкового вида&lt;/font&gt;
        &lt;font color="#000000"&gt;parse &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;( &lt;/font&gt;&lt;font color="#d200d2"&gt;Read &lt;/font&gt;&lt;font color="#000000"&gt;a, &lt;/font&gt;&lt;font color="#d200d2"&gt;Integral &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;String &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Cell a&lt;/font&gt;
        &lt;font color="#000000"&gt;parse &lt;/font&gt;&lt;font color="#800080"&gt;""                     &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;CNull                             &lt;/font&gt;&lt;font color="#808080"&gt;-- Пустая ячейка&lt;/font&gt;
        &lt;font color="#000000"&gt;parse str@(s&lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#000000"&gt;ss) | isDigit s &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;readNumb str                      &lt;/font&gt;&lt;font color="#808080"&gt;-- Целочисленная константа&lt;/font&gt;
                         &lt;font color="#000000"&gt;| s &lt;/font&gt;&lt;font color="#0000e6"&gt;== &lt;/font&gt;&lt;font color="#000000"&gt;'\'' &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;CStr ss                           &lt;/font&gt;&lt;font color="#808080"&gt;-- Строковая константа&lt;/font&gt;
                         &lt;font color="#000000"&gt;| s &lt;/font&gt;&lt;font color="#0000e6"&gt;== &lt;/font&gt;&lt;font color="#000000"&gt;'&lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#000000"&gt;'  &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;pars &lt;/font&gt;&lt;font color="#008000"&gt;$ reverse $ lines $ &lt;/font&gt;&lt;font color="#000000"&gt;items ss &lt;/font&gt;&lt;font color="#808080"&gt;-- Формула&lt;/font&gt;
                         &lt;font color="#000000"&gt;| &lt;/font&gt;&lt;font color="#008000"&gt;otherwise &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;CErr &lt;/font&gt;&lt;font color="#800080"&gt;"Parse"                      &lt;/font&gt;&lt;font color="#808080"&gt;-- Что-то не то...&lt;/font&gt;

        &lt;font color="#808080"&gt;-- Вставить перенос строки между элементами формулы&lt;/font&gt;
        &lt;font color="#000000"&gt;items &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#d200d2"&gt;String &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;String&lt;/font&gt;
        &lt;font color="#000000"&gt;items s &lt;/font&gt;&lt;font color="#0000e6"&gt;= case &lt;/font&gt;&lt;font color="#008000"&gt;span &lt;/font&gt;&lt;font color="#000000"&gt;isAlphaNum s &lt;/font&gt;&lt;font color="#0000e6"&gt;of&lt;/font&gt;
                    &lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#800080"&gt;""&lt;/font&gt;&lt;font color="#000000"&gt;,   &lt;/font&gt;&lt;font color="#800080"&gt;""&lt;/font&gt;&lt;font color="#000000"&gt;)       &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#800080"&gt;""&lt;/font&gt;
                    &lt;font color="#000000"&gt;(left, &lt;/font&gt;&lt;font color="#800080"&gt;""&lt;/font&gt;&lt;font color="#000000"&gt;)       &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;left&lt;/font&gt;
                    &lt;font color="#000000"&gt;(left, op'right) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;left &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#800080"&gt;"\n" &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#000000"&gt;op &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#800080"&gt;"\n" &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#000000"&gt;items right&lt;/font&gt;
                        &lt;font color="#0000e6"&gt;where &lt;/font&gt;&lt;font color="#000000"&gt;(op, right) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;break &lt;/font&gt;&lt;font color="#000000"&gt;isAlphaNum op'right&lt;/font&gt;

        &lt;font color="#808080"&gt;-- Преобразовать перевёрнутый список элементов формулы в саму формулу&lt;/font&gt;
        &lt;font color="#000000"&gt;pars &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Read &lt;/font&gt;&lt;font color="#000000"&gt;a, &lt;/font&gt;&lt;font color="#d200d2"&gt;Integral &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;[&lt;/font&gt;&lt;font color="#d200d2"&gt;String&lt;/font&gt;&lt;font color="#000000"&gt;] &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Cell a&lt;/font&gt;
        &lt;font color="#000000"&gt;pars [x]      &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;pars' x                           &lt;/font&gt;&lt;font color="#808080"&gt;-- Число или ссылка на ячейку&lt;/font&gt;
        &lt;font color="#000000"&gt;pars (r&lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#000000"&gt;o&lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#000000"&gt;xs) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;CFun (&lt;/font&gt;&lt;font color="#008000"&gt;read &lt;/font&gt;&lt;font color="#000000"&gt;o) (pars xs) (pars' r) &lt;/font&gt;&lt;font color="#808080"&gt;-- Операция над двумя элементами&lt;/font&gt;
        &lt;font color="#000000"&gt;pars xs       &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;CErr &lt;/font&gt;&lt;font color="#800080"&gt;"Expr"                       &lt;/font&gt;&lt;font color="#808080"&gt;-- Какая-то ошибка в формуле&lt;/font&gt;

        &lt;font color="#000000"&gt;pars' s@(x&lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#000000"&gt;xs) | isDigit x &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;readNumb s&lt;/font&gt;
                       &lt;font color="#000000"&gt;| isAlpha x &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;CRef s&lt;/font&gt;
        &lt;font color="#000000"&gt;pars' s                    &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;CErr s&lt;/font&gt;

        &lt;font color="#808080"&gt;-- Попытаться прочесть целое число из строки&lt;/font&gt;
        &lt;font color="#000000"&gt;readNumb s | &lt;/font&gt;&lt;font color="#008000"&gt;all &lt;/font&gt;&lt;font color="#000000"&gt;isDigit s &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;CNum &lt;/font&gt;&lt;font color="#008000"&gt;$ read &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;
                   &lt;font color="#000000"&gt;| &lt;/font&gt;&lt;font color="#008000"&gt;otherwise     &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;CErr &lt;/font&gt;&lt;font color="#800080"&gt;"NaN"           &lt;/font&gt;&lt;font color="#808080"&gt;-- Not a Number&lt;/font&gt;


&lt;font color="#0000e6"&gt;instance &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Integral &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Calculable (Cell a) &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;
    &lt;font color="#808080"&gt;----------------------------------------------------------------------------&lt;/font&gt;
    &lt;font color="#808080"&gt;-- Вычисление ячейки таблицы&lt;/font&gt;

    &lt;font color="#000000"&gt;calculate (CQry (cid, cell) (Sheet sh)) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;calc cell&lt;/font&gt;
      &lt;font color="#0000e6"&gt;where&lt;/font&gt;
        &lt;font color="#808080"&gt;-- Вычислить ячейку&lt;/font&gt;
        &lt;font color="#000000"&gt;calc (CFun f x y) &lt;/font&gt;&lt;font color="#0000e6"&gt;= case &lt;/font&gt;&lt;font color="#000000"&gt;(x, y) &lt;/font&gt;&lt;font color="#0000e6"&gt;of&lt;/font&gt;
                              &lt;font color="#000000"&gt;((CNum a), (CNum b)) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;res          &lt;/font&gt;&lt;font color="#808080"&gt;-- число с числом&lt;/font&gt;
                                &lt;font color="#0000e6"&gt;where&lt;/font&gt;
                                  &lt;font color="#000000"&gt;res &lt;/font&gt;&lt;font color="#0000e6"&gt;= case &lt;/font&gt;&lt;font color="#000000"&gt;calculate &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;FQrN f a b &lt;/font&gt;&lt;font color="#0000e6"&gt;of&lt;/font&gt;
                                           &lt;font color="#000000"&gt;(FRes (FRNum n)) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;CNum n&lt;/font&gt;
                                           &lt;font color="#000000"&gt;(FRes (FRErr s)) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;CErr s&lt;/font&gt;
                                           &lt;font color="#0000e6"&gt;_                &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;CErr &lt;/font&gt;&lt;font color="#800080"&gt;"Calc"&lt;/font&gt;

                              &lt;font color="#000000"&gt;((CStr a), (CStr b)) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;res         &lt;/font&gt;&lt;font color="#808080"&gt;-- строка со строкой&lt;/font&gt;
                                &lt;font color="#0000e6"&gt;where&lt;/font&gt;
                                  &lt;font color="#000000"&gt;res &lt;/font&gt;&lt;font color="#0000e6"&gt;= case &lt;/font&gt;&lt;font color="#000000"&gt;calculate &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;FQrS f a b &lt;/font&gt;&lt;font color="#0000e6"&gt;of&lt;/font&gt;
                                           &lt;font color="#000000"&gt;(FRes (FRStr n)) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;CStr n&lt;/font&gt;
                                           &lt;font color="#000000"&gt;(FRes (FRErr s)) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;CErr s&lt;/font&gt;
                                           &lt;font color="#0000e6"&gt;_                &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;CErr &lt;/font&gt;&lt;font color="#800080"&gt;"Calc"&lt;/font&gt;

                              &lt;font color="#000000"&gt;((CRef &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;), &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;)        &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;res         &lt;/font&gt;&lt;font color="#808080"&gt;-- что-то с ячейкой&lt;/font&gt;
                              &lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;,        (CRef &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;)) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;res&lt;/font&gt;
                              &lt;font color="#000000"&gt;((CFun &lt;/font&gt;&lt;font color="#0000e6"&gt;_ _ _&lt;/font&gt;&lt;font color="#000000"&gt;), &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;)    &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;res         &lt;/font&gt;&lt;font color="#808080"&gt;-- что-то с формулой&lt;/font&gt;
                              &lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;,    (CFun &lt;/font&gt;&lt;font color="#0000e6"&gt;_ _ _&lt;/font&gt;&lt;font color="#000000"&gt;)) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;res&lt;/font&gt;
                              &lt;font color="#000000"&gt;(err@(CErr &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;), &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;)    &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;err&lt;/font&gt;
                              &lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;, err@(CErr &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;))    &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;err&lt;/font&gt;
                              &lt;font color="#008000"&gt;otherwise            -&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;CErr &lt;/font&gt;&lt;font color="#800080"&gt;"Expr" &lt;/font&gt;&lt;font color="#808080"&gt;-- ошибка в формуле&lt;/font&gt;
                            &lt;font color="#0000e6"&gt;where&lt;/font&gt;
                              &lt;font color="#000000"&gt;res &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;calc &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;CFun f (calc x) (calc y)&lt;/font&gt;

        &lt;font color="#000000"&gt;calc (CRef x)     &lt;/font&gt;&lt;font color="#0000e6"&gt;= case &lt;/font&gt;&lt;font color="#008000"&gt;lookup &lt;/font&gt;&lt;font color="#000000"&gt;x sh &lt;/font&gt;&lt;font color="#0000e6"&gt;of&lt;/font&gt;
                               &lt;font color="#ff0000"&gt;Just &lt;/font&gt;&lt;font color="#000000"&gt;z &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;calc z                   &lt;/font&gt;&lt;font color="#808080"&gt;-- вычислим ячейку&lt;/font&gt;
                               &lt;font color="#0000e6"&gt;_      &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;CErr &lt;/font&gt;&lt;font color="#800080"&gt;"Cell"              &lt;/font&gt;&lt;font color="#808080"&gt;-- нет такой ячейки&lt;/font&gt;
        &lt;font color="#000000"&gt;calc x            &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;x&lt;/font&gt;

    &lt;font color="#000000"&gt;calculate c &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;calculate &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;CQry (&lt;/font&gt;&lt;font color="#800080"&gt;"A1"&lt;/font&gt;&lt;font color="#000000"&gt;, c) (Sheet [])&lt;/font&gt;

&lt;font color="#808080"&gt;--------------------------------------------------------------------------------&lt;/font&gt;
&lt;font color="#808080"&gt;-- | Электронная таблица в виде списка кортежей,&lt;/font&gt;
&lt;font color="#808080"&gt;--   первый элемент которых -- идентификатор ячейки (напр., "A1"),&lt;/font&gt;
&lt;font color="#808080"&gt;--   а второй -- содержимое ячейки (напр., "=B2*5") в распарсенном виде&lt;/font&gt;

&lt;font color="#0000e6"&gt;data &lt;/font&gt;&lt;font color="#000000"&gt;Sheet a &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;Sheet [IdCell a]&lt;/font&gt;


&lt;font color="#0000e6"&gt;instance &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Show &lt;/font&gt;&lt;font color="#000000"&gt;a, &lt;/font&gt;&lt;font color="#d200d2"&gt;Integral &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Show &lt;/font&gt;&lt;font color="#000000"&gt;(Sheet a) &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;
    &lt;font color="#008000"&gt;show &lt;/font&gt;&lt;font color="#000000"&gt;(Sheet s) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;s&lt;/font&gt;
                     &lt;font color="#808080"&gt;-- Разобьём на строки&lt;/font&gt;
                  &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;groupBy (\(&lt;/font&gt;&lt;font color="#0000e6"&gt;_:&lt;/font&gt;&lt;font color="#000000"&gt;a,&lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;) (&lt;/font&gt;&lt;font color="#0000e6"&gt;_:&lt;/font&gt;&lt;font color="#000000"&gt;b,&lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;a &lt;/font&gt;&lt;font color="#0000e6"&gt;== &lt;/font&gt;&lt;font color="#000000"&gt;b)&lt;/font&gt;

                     &lt;font color="#808080"&gt;-- Теперь сформируем столбцы табуляцией&lt;/font&gt;
                  &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; map &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#008000"&gt;map &lt;/font&gt;&lt;font color="#000000"&gt;(\(&lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;, x) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; show &lt;/font&gt;&lt;font color="#000000"&gt;x &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#800080"&gt;"\t"&lt;/font&gt;&lt;font color="#000000"&gt;))&lt;/font&gt;

                     &lt;font color="#808080"&gt;-- И превратим всё это в одну длинную строку&lt;/font&gt;
                  &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; map concat&lt;/font&gt;
                  &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; unlines&lt;/font&gt;


&lt;font color="#0000e6"&gt;instance &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Read &lt;/font&gt;&lt;font color="#000000"&gt;a, &lt;/font&gt;&lt;font color="#d200d2"&gt;Integral &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Read &lt;/font&gt;&lt;font color="#000000"&gt;(Sheet a) &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;
    &lt;font color="#008000"&gt;readsPrec &lt;/font&gt;&lt;font color="#0000e6"&gt;_ &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[(readSh s, &lt;/font&gt;&lt;font color="#800080"&gt;""&lt;/font&gt;&lt;font color="#000000"&gt;)]&lt;/font&gt;
      &lt;font color="#0000e6"&gt;where&lt;/font&gt;
        &lt;font color="#000000"&gt;readSh &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Integral &lt;/font&gt;&lt;font color="#000000"&gt;a, &lt;/font&gt;&lt;font color="#d200d2"&gt;Read &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;String &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Sheet a&lt;/font&gt;
        &lt;font color="#000000"&gt;readSh s  &lt;/font&gt;&lt;font color="#0000e6"&gt;=  &lt;/font&gt;&lt;font color="#000000"&gt;ss&lt;/font&gt;
                     &lt;font color="#808080"&gt;-- Разобъём строки таблицы на кучи ячеек&lt;/font&gt;
                  &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; map &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#008000"&gt;lines &lt;/font&gt;&lt;font color="#000000"&gt;. &lt;/font&gt;&lt;font color="#008000"&gt;map &lt;/font&gt;&lt;font color="#000000"&gt;(\c &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#0000e6"&gt;if &lt;/font&gt;&lt;font color="#000000"&gt;c &lt;/font&gt;&lt;font color="#0000e6"&gt;== &lt;/font&gt;&lt;font color="#000000"&gt;'\t' &lt;/font&gt;&lt;font color="#0000e6"&gt;then &lt;/font&gt;&lt;font color="#000000"&gt;'\n' &lt;/font&gt;&lt;font color="#0000e6"&gt;else &lt;/font&gt;&lt;font color="#000000"&gt;c))&lt;/font&gt;

                     &lt;font color="#808080"&gt;-- Если введено было меньше столбцов, чем нужно, то добавим пустые (Null)&lt;/font&gt;
                  &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; map &lt;/font&gt;&lt;font color="#000000"&gt;((&lt;/font&gt;&lt;font color="#008000"&gt;take &lt;/font&gt;&lt;font color="#000000"&gt;columns) . (&lt;/font&gt;&lt;font color="#008000"&gt;++ repeat &lt;/font&gt;&lt;font color="#800080"&gt;""&lt;/font&gt;&lt;font color="#000000"&gt;))&lt;/font&gt;

                     &lt;font color="#808080"&gt;-- Пронумеруем ячейки таблицы в виде "A1"&lt;/font&gt;
                  &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; map &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#008000"&gt;zip &lt;/font&gt;&lt;font color="#000000"&gt;(['A'..'Z'] &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#000000"&gt;['a'..'z']) . &lt;/font&gt;&lt;font color="#008000"&gt;map read&lt;/font&gt;&lt;font color="#000000"&gt;)&lt;/font&gt;
                  &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; zip &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#008000"&gt;map show &lt;/font&gt;&lt;font color="#000000"&gt;[&lt;/font&gt;&lt;font color="#800080"&gt;1&lt;/font&gt;&lt;font color="#000000"&gt;..])&lt;/font&gt;
                  &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; map &lt;/font&gt;&lt;font color="#000000"&gt;(\(n, s) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; map &lt;/font&gt;&lt;font color="#000000"&gt;(\(c, f) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;(c&lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#000000"&gt;n, f)) s)&lt;/font&gt;

                     &lt;font color="#808080"&gt;-- И превратим всё это в таблицу&lt;/font&gt;
                  &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; concat&lt;/font&gt;
                  &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Sheet&lt;/font&gt;
          &lt;font color="#0000e6"&gt;where&lt;/font&gt;
            &lt;font color="#000000"&gt;(rc&lt;/font&gt;&lt;font color="#0000e6"&gt;:&lt;/font&gt;&lt;font color="#000000"&gt;ss) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;lines &lt;/font&gt;&lt;font color="#000000"&gt;s &lt;/font&gt;&lt;font color="#808080"&gt;-- Разобьём входную строку на строки таблицы&lt;/font&gt;
            &lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#0000e6"&gt;_:&lt;/font&gt;&lt;font color="#000000"&gt;o&lt;/font&gt;&lt;font color="#0000e6"&gt;:_&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;words $ &lt;/font&gt;&lt;font color="#000000"&gt;rc &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#800080"&gt;" 0"&lt;/font&gt;
            &lt;font color="#000000"&gt;columns &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#008000"&gt;read  &lt;/font&gt;&lt;font color="#000000"&gt;o&lt;/font&gt;


&lt;font color="#0000e6"&gt;instance &lt;/font&gt;&lt;font color="#000000"&gt;(&lt;/font&gt;&lt;font color="#d200d2"&gt;Integral &lt;/font&gt;&lt;font color="#000000"&gt;a) &lt;/font&gt;&lt;font color="#0000e6"&gt;=&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;Calculable (Sheet a) &lt;/font&gt;&lt;font color="#0000e6"&gt;where&lt;/font&gt;
    &lt;font color="#808080"&gt;----------------------------------------------------------------------------&lt;/font&gt;
    &lt;font color="#808080"&gt;-- Вычисление всей таблицы&lt;/font&gt;

    &lt;font color="#000000"&gt;calculate (Sheet sh) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;Sheet sh'&lt;/font&gt;
      &lt;font color="#0000e6"&gt;where&lt;/font&gt;
        &lt;font color="#808080"&gt;-- Пройтись по всем элементам таблицы, пытаясь их вычислить&lt;/font&gt;
        &lt;font color="#000000"&gt;sh' &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;sh&lt;/font&gt;
              &lt;font color="#808080"&gt;-- Пометить зацикленные ячейки&lt;/font&gt;
           &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; map &lt;/font&gt;&lt;font color="#000000"&gt;(\c&lt;/font&gt;&lt;font color="#0000e6"&gt;@&lt;/font&gt;&lt;font color="#000000"&gt;(cid,&lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#0000e6"&gt;if &lt;/font&gt;&lt;font color="#000000"&gt;isCycled cid &lt;/font&gt;&lt;font color="#0000e6"&gt;then &lt;/font&gt;&lt;font color="#000000"&gt;(cid, CErr &lt;/font&gt;&lt;font color="#800080"&gt;"Cycle"&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;else &lt;/font&gt;&lt;font color="#000000"&gt;c)&lt;/font&gt;

              &lt;font color="#808080"&gt;-- Вычислить значения ячеек&lt;/font&gt;
           &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; map &lt;/font&gt;&lt;font color="#000000"&gt;(\c&lt;/font&gt;&lt;font color="#0000e6"&gt;@&lt;/font&gt;&lt;font color="#000000"&gt;(cid,&lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;(cid, calculate &lt;/font&gt;&lt;font color="#008000"&gt;$ &lt;/font&gt;&lt;font color="#000000"&gt;CQry c (Sheet sh')))&lt;/font&gt;

        &lt;font color="#808080"&gt;-- Определить, зациклена ли ячейка&lt;/font&gt;
        &lt;font color="#000000"&gt;isCycled &lt;/font&gt;&lt;font color="#0000e6"&gt;:: &lt;/font&gt;&lt;font color="#d200d2"&gt;String &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#d200d2"&gt;Bool&lt;/font&gt;
        &lt;font color="#000000"&gt;isCycled x &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;x `&lt;/font&gt;&lt;font color="#008000"&gt;elem&lt;/font&gt;&lt;font color="#000000"&gt;` crefs&lt;/font&gt;
          &lt;font color="#0000e6"&gt;where&lt;/font&gt;
            &lt;font color="#000000"&gt;crefs &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;sh&lt;/font&gt;
                 &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; map       &lt;/font&gt;&lt;font color="#000000"&gt;(\(cid, cell) &lt;/font&gt;&lt;font color="#008000"&gt;-&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;(cid, cid, cids cell))&lt;/font&gt;
                 &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;stronglyConnComp&lt;/font&gt;
                 &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; filter    &lt;/font&gt;&lt;font color="#000000"&gt;isCyclic&lt;/font&gt;
                 &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;flattenSCCs&lt;/font&gt;
                 &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;sort&lt;/font&gt;
                 &lt;font color="#000000"&gt;|&lt;/font&gt;&lt;font color="#008000"&gt;&amp;gt; &lt;/font&gt;&lt;font color="#000000"&gt;nub&lt;/font&gt;

            &lt;font color="#000000"&gt;cids (CFun &lt;/font&gt;&lt;font color="#0000e6"&gt;_ &lt;/font&gt;&lt;font color="#000000"&gt;a b) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;cids a &lt;/font&gt;&lt;font color="#008000"&gt;++ &lt;/font&gt;&lt;font color="#000000"&gt;cids b&lt;/font&gt;
            &lt;font color="#000000"&gt;cids (CRef cid)   &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#000000"&gt;[cid]&lt;/font&gt;
            &lt;font color="#000000"&gt;cids &lt;/font&gt;&lt;font color="#0000e6"&gt;_            = &lt;/font&gt;&lt;font color="#000000"&gt;[]&lt;/font&gt;

            &lt;font color="#000000"&gt;isCyclic (CyclicSCC &lt;/font&gt;&lt;font color="#0000e6"&gt;_&lt;/font&gt;&lt;font color="#000000"&gt;) &lt;/font&gt;&lt;font color="#0000e6"&gt;= &lt;/font&gt;&lt;font color="#ff0000"&gt;True&lt;/font&gt;
            &lt;font color="#000000"&gt;isCyclic &lt;/font&gt;&lt;font color="#0000e6"&gt;_             = &lt;/font&gt;&lt;font color="#ff0000"&gt;False&lt;/font&gt;
&lt;/font&gt;&lt;/pre&gt;&lt;hr&gt;У меня на это дело ушло где-то дня три-четыре. Чистого времени - больше суток...&lt;br /&gt;Ох и намучился я с поиском циклических ссылок в ячейках таблицы... &lt;s&gt;Зато обошёлся без библиотеки графов...&lt;/s&gt; :o)&lt;br /&gt;&lt;br /&gt;На тестовый набор данных:&lt;br /&gt;&lt;pre&gt;
8	4
12	=C2	3	'Sample
=A1+B1*C1/5	=A2*B1	=B3-C3	'Spread
'Test	=4-3	5	'Sheet
""	=A9	=1/0	=A5
=B5+1	=1+A5+1	=5A	=A1++C1
=1+	x	' 	=D1+D2
=D1++D2	=D1--D2	=D1**D2	=D1//D2
=D1++C6++D2++C6++D3
&lt;/pre&gt;&lt;br /&gt;программа выдаёт результат:&lt;br /&gt;&lt;pre&gt;
12	-4	3	Sample	
4	-16	-4	Spread	
Test	1	5	Sheet	
#Parse	#Cell	#Inf	#Cycle	
#Cycle	#Cycle	#NaN	#StrOp on Numbers	
#Expr	#Parse	 	#NumOp on Strings	
SampleSpread	ml	Samplerd	Sape	
Sample Spread Sheet	 	 	 	
&lt;/pre&gt;&lt;br /&gt;Update. С целью получения максимально идиоматического :о) хаскеллевского решения, радикально редизайнил программу, используя классы типов... ;о)&lt;br /&gt;Update. Расширил набор операций операциями над строками: конкатенация, разность, объединение и пересечение (вообще-то это операции над множествами, но и для строк пойдут)&lt;br /&gt;Update. Таки переделал алгоритм поиска зацикленных ячеек таблицы на графы...</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:geniepro:2487</id>
    <link rel="alternate" type="text/html" href="http://geniepro.livejournal.com/2487.html"/>
    <link rel="self" type="text/xml" href="http://geniepro.livejournal.com/data/atom/?itemid=2487"/>
    <title>Галерея художника Armodey Moro</title>
    <published>2007-09-15T16:54:29Z</published>
    <updated>2007-09-15T17:06:59Z</updated>
    <content type="html">Не могу не пропиарить &lt;a href="http://armodey.ho.com.ua/"&gt;галерею&lt;/a&gt; брата моего друга.&lt;br /&gt;&lt;a href="http://armodey.ho.com.ua/"&gt;Armodey Moro (Артём Плужников)&lt;/a&gt; - художник-авангардист, пишет весьма интересные картины, например:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://armodey.ho.com.ua/e107_images/splash2.jpg"&gt;&lt;br /&gt;&lt;br /&gt;Ну и т.д... :о) Вопщем, их там много... Обязательно посетите!</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:geniepro:2066</id>
    <link rel="alternate" type="text/html" href="http://geniepro.livejournal.com/2066.html"/>
    <link rel="self" type="text/xml" href="http://geniepro.livejournal.com/data/atom/?itemid=2066"/>
    <title>Задачки из SICP</title>
    <published>2007-09-13T20:08:45Z</published>
    <updated>2007-09-13T20:08:45Z</updated>
    <content type="html">Группа энтузиастов (пока из двух человек: IvanVeselov aka &lt;a href="http://www.livejournal.com/users/dying_sphynx/"&gt;dying_sphynx&lt;/a&gt; и я) решили открыть свой &lt;a href="http://histoma.com/sicp/FrontPage"&gt;вики-сайтик&lt;/a&gt;, посвящённый решению задачек из культового учебника по программированию "Структура и интерпретация компьютерных программ" (SICP).&lt;br /&gt;Решения задач будут на языках Scheme, Haskell, Oberon/Component Pascal, возможно ещё на каких-нибудь...&lt;br /&gt;&lt;a href="http://histoma.com/sicp/FrontPage"&gt;Приглашаем всех желающих!&lt;/a&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:geniepro:1901</id>
    <link rel="alternate" type="text/html" href="http://geniepro.livejournal.com/1901.html"/>
    <link rel="self" type="text/xml" href="http://geniepro.livejournal.com/data/atom/?itemid=1901"/>
    <title>Арифметика с IORef</title>
    <published>2007-08-24T16:57:06Z</published>
    <updated>2007-08-24T16:57:06Z</updated>
    <category term="Хаскелл"/>
    <content type="html">Пытаюсь с помощью мультипараметрических классов типов смоделировать арифметические операции стандартных императивных языков, в которых могут свободно смешиваться константы и мутабельные переменные. &lt;br /&gt;Получилось не совсем так, как я хотел бы, а именно так:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://community.livejournal.com/ru_declarative/55404.html"&gt;Продолжение в ru_declarative&lt;/a&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:geniepro:1769</id>
    <link rel="alternate" type="text/html" href="http://geniepro.livejournal.com/1769.html"/>
    <link rel="self" type="text/xml" href="http://geniepro.livejournal.com/data/atom/?itemid=1769"/>
    <title>Флешмоб на www.chirchik.ru</title>
    <published>2007-06-29T16:28:20Z</published>
    <updated>2007-06-29T16:28:20Z</updated>
    <category term="книга рекордов Гинесса"/>
    <category term="флеш-моб"/>
    <category term="рекорд"/>
    <content type="html">Только что поучаствовал на флешмобе на &lt;a href="http://www.chirchik.ru/"&gt;сайте&lt;/a&gt;, посвящённому городу, где я живу. Сам сайт российский, но создатели - выходцы из Чирчика, что рядом с Ташкентом, столицей Узбекистана. Веб-мастер сайта - Димка Ковригин - мой бывший сотрудник.&lt;br /&gt;&lt;br /&gt;Так это, собственно, акция - &lt;a href="http://www.chirchik.ru/modules/news/article.php?storyid=312"&gt;попытка попасть в книгу Рекордов Гинесса&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Оказывается, до сих пор ещё нет рекорда по одновременному посещению сайта... &lt;br /&gt;На момент фиксации рекорда (29 июня 2007 г., 20:07 по Москве) на сайте было около сорока человек, около тридцати зашли как пользователи...&lt;br /&gt;Очень мало, учитывая, что есть сайты, на которых одновременно тусуются более миллиона человек. И если рекорд будет таки зафиксирован, его тут же перебьют, причём многократно...&lt;br /&gt;&lt;br /&gt;Но тем не менее, если рекорд зафиксируют, то мы будем первыми!!! :-Р</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:geniepro:1424</id>
    <link rel="alternate" type="text/html" href="http://geniepro.livejournal.com/1424.html"/>
    <link rel="self" type="text/xml" href="http://geniepro.livejournal.com/data/atom/?itemid=1424"/>
    <title>Ой, лол-то какой... :о))</title>
    <published>2007-06-28T16:25:32Z</published>
    <updated>2007-11-23T22:47:31Z</updated>
    <content type="html">&lt;div style="border: 1px solid #cccccc; background-color: white; width: 115px; text-align: center; padding: 0 0 10px 0;"&gt;&lt;p style="margin: 0"&gt;&lt;img src="http://static.flickr.com/23/25822676_789bf55448_t.jpg" style="border:0;"&gt;&lt;br /&gt; 		&lt;span style="font-size: 11px;"&gt;My &lt;a href="http://geniepro.livejournal.com/"&gt;blog&lt;/a&gt; is worth &lt;b&gt;$0.00&lt;/b&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 10px;"&gt;&lt;a href="http://www.business-opportunities.biz/projects/how-much-is-your-blog-worth/"&gt;How much is your blog worth?&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.technorati.com/" style="border: 0px;"&gt;&lt;img src="http://technorati.com/pix/tech-logo-embed.gif" style="border: 0px;"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;__________________&lt;br /&gt;&lt;br /&gt;Update 24.11.2007 :о)&lt;br /&gt;&lt;div style="border: 1px solid #cccccc; background-color: white; width: 115px; text-align: center; padding: 0 0 10px 0;"&gt;&lt;p style="margin: 0"&gt;&lt;a href="http://www.business-opportunities.biz/"&gt;&lt;img src="http://images.business-opportunities.biz/blogworth/gw.jpg" style="border:0;"&gt;&lt;/a&gt;&lt;br /&gt; 		&lt;span style="font-size: 11px;"&gt;My &lt;a href="http://geniepro.livejournal.com/"&gt;blog&lt;/a&gt; is worth &lt;b&gt;$564.54&lt;/b&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 10px;"&gt;&lt;a href="http://www.business-opportunities.biz/projects/how-much-is-your-blog-worth/"&gt;How much is your blog worth?&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.technorati.com/" style="border: 0px;"&gt;&lt;img src="http://technorati.com/pix/tech-logo-embed.gif" style="border: 0px;"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</content>
  </entry>
  <entry>
    <id>urn:lj:livejournal.com:atom1:geniepro:1174</id>
    <link rel="alternate" type="text/html" href="http://geniepro.livejournal.com/1174.html"/>
    <link rel="self" type="text/xml" href="http://geniepro.livejournal.com/data/atom/?itemid=1174"/>
    <title>ACM ICPC 2007 Final: Problem A+. Consanguine Calculations</title>
    <published>2007-03-23T14:44:06Z</published>
    <updated>2007-04-06T20:21:03Z</updated>
    <category term="acm icpc 2007"/>
    <category term="haskell"/>
    <content type="html">По &lt;a href="http://www.delphikingdom.com/asp/talktopic.asp?ID=368&amp;amp;ref=msg&amp;amp;msg=3271#msg3271"&gt;предложению&lt;/a&gt; Руслана Богатырёва я провел "reverse engineering" (после маленького рефакторинга программы, так что примеры тут не совсем совпадают с &lt;a href="http://delphikingdom.com/asp/talktopic.asp?ID=366&amp;amp;ref=msg&amp;amp;msg=2095#msg2095"&gt;приведённой ранее программой&lt;/a&gt;) и попытался расписать, что, собственно, в программе делается. Так сказать, разбор полётов...&lt;br /&gt;&lt;br /&gt;Текст задачи доступен &lt;a href="http://icpc.baylor.edu/icpc/Finals/2007WorldFinalProblemSet.pdf"&gt;тут&lt;/a&gt; или в моём переводе &lt;a href="http://delphikingdom.com/asp/talktopic.asp?ID=366&amp;amp;ref=msg&amp;amp;msg=2093#msg2093"&gt;тут&lt;/a&gt;.&lt;br /&gt;&lt;a name="cutid1"&gt;&lt;/a&gt;&lt;br /&gt;Схему программы на самом абстрактном уровне можно представить так:&lt;br /&gt;&lt;br /&gt;1. Указание имени программы и списка используемых ею модулей.&lt;br /&gt;2. Описание главного потока управления в функции main.&lt;br /&gt;3. Открытие входного файла &lt;b&gt;"blood.in"&lt;/b&gt;&lt;br /&gt;4. Построчная обработка входного файла.&lt;br /&gt;5. Вывод результатов обработки входного файла.&lt;br /&gt;6. Закрытие входного файла.&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;1. Указание имени программы и списка используемых ею модулей.&lt;br /&gt;&lt;br /&gt;Имя программы в Хаскелле указывается просто:&lt;br /&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:blue"&gt;module&lt;/span&gt;&lt;/b&gt; &lt;span style="color:green"&gt;&lt;b&gt;Имя_Модуля&lt;/b&gt;&lt;/span&gt; &lt;b&gt;&lt;span style="color:blue"&gt;where&lt;/span&gt;&lt;/b&gt;&lt;/pre&gt;&lt;br /&gt;В простейших случаях, когда вся программа состоит лишь из одного модуля и не входит в состав более сложных программ, строку "&lt;b&gt;&lt;span style="color:blue"&gt;module&lt;/span&gt;&lt;/b&gt; &lt;span style="color:green"&gt;&lt;b&gt;Имя_Модуля&lt;/b&gt;&lt;/span&gt; &lt;b&gt;&lt;span style="color:blue"&gt;where&lt;/span&gt;&lt;/b&gt;" можно опускать, тогда будет принято имя по умолчанию "&lt;span style="color:green"&gt;&lt;b&gt;Main&lt;/b&gt;&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;Импорт других модулей можно указывать с разными уровнями уточнения режимов импорта:&lt;br /&gt;&lt;pre&gt;
&lt;b&gt;&lt;span style="color:blue"&gt;import&lt;/span&gt;&lt;/b&gt; &lt;span style="color:green"&gt;&lt;b&gt;IO&lt;/b&gt;&lt;/span&gt;          &lt;span style="color:brown"&gt;&lt;em&gt;-- Импорт всех сущностей, экспортируемых модулем IO&lt;/em&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style=