14 занимательных эссе о языке Haskell и функциональном программировании В книге представлено 14 статей автора, которые в разное время были опубликованы или подготовлены к публикации в научно-популярном журнале для школьников и учителей «Потенциал». Статьи расположены и связаны таким образом, чтобы они представляли собой логически последовательное повествование от начал к более сложным темам. Также в книге сделан упор на практические знания, предлагается решение многих прикладных задач при помощи языка функционального программирования Haskell. Книга будет интересна всем, кто живо интересуется функциональным программированием, студентам технических ВУЗов, преподавателям информатики. Кроме того, книга будет полезна всем желающим овладеть пониманием функционального программирования в целом и языка Haskell в частности. И в любом случае книга станет хорошим источником идей, задач и их решений для всех, кто интересуется функциональным программированием.
14 занимательных эссе о языке
Haskell
и функциональном программировании
Роман Викторович Душкин является автором первой книги на русском языке о функциональном программировании на языке Haskell, а также множества научных публикаций по темам нечеткой математики, искусственного интеллекта и функционального программирования в российских и зарубежных научных изданиях. Состоит в Российской Ассоциации Искусственного Интеллекта и участвовал во множестве национальных и международных научных конференциях, проводимых под ее эгидой. С 2001 года читал лекции по функциональному программированию в Московском инженерно-физическом институте (МИФИ). В настоящее время работает в области автоматизации промышленности и государственного управления,на практике используя все методы создания программных средств, применяющиеся в составе парадигм функционального и объектно-ориентированного программирования, а также искусственного интеллекта.
Internet-магазин: www.alians-kniga.ru Книга - почтой: Россия, 123242, Москва, а/я 20 e-mail:
[email protected] Оптовая продажа: “Альянс-книга“ (495)258-9194, 258-9195 e-mail:
[email protected]
Душкин Р. В.
Душкин Р. В.
14 занимательных эссе о языке Haskell и функциональном программировании
Москва, 2011
УДК ББК
Д86
004.4 32.973.26 018.2 Д86
Душкин Р. В. 14 занимательных эссе о языке Haskell и функциональном программировании. – М.: ДМК Пресс, 2011. – 140 с., ил.
ISBN 978 5 94074 691 1
В книге представлено 14 статей автора, которые в разное время были опубликованы или под$ готовлены к публикации в научно$популярном журнале для школьников и учителей «Потенци$ ал». Статьи расположены и связаны таким образом, чтобы они представляли собой логически последовательное повествование от начал к более сложным темам. Также в книге сделан упор на практические знания, предлагается решение многих прикладных задач при помощи языка фун$ кционального программирования Haskell. Книга будет интересна всем, кто живо интересуется функциональным программированием, студентам технических ВУЗов, преподавателям информатики.
УДК 004.4 ББК 32.973.26$018.2
Все права защищены. Любая часть этой книги не может быть воспроизведена в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Материал, изложенный в данной книге, многократно проверен. Но, поскольку вероятность технических ошибок все равно существует, издательство не может гарантировать абсолютную точность и правильность приводимых сведений. В связи с этим издательство не несет ответственности за возможные ошибки, связанные с использованием книги.
ISBN 978$5$94074$691$1
© Душкин Р. В., 2011 © Оформление ДМК Пресс, 2011
3
Ïðèíèìàþòñÿ áëàãîäàðíîñòè Âíèìàíèþ âñåõ ÷èòàòåëåé! Äàííàÿ êíèãà èçäàíà â ýëåêòðîííîì âèäå è ðàñïðîñòðàíÿåòñÿ àáñîëþòíî áåñïëàòíî. Âû ìîæåòå ñâîáîäíî èñïîëüçîâàòü å¼ äëÿ ÷òåíèÿ, êîïèðîâàòü å¼ äëÿ äðóçåé, ðàçìåùàòü â áèáëèîòåêàõ íà ñàéòàõ â ñåòè Èíòåðíåò, ðàññûëàòü ïî ýëåêòðîííîé ïî÷òå è ïðè ïîìîùè èíûõ ñðåäñòâ ïåðåäà÷è èíôîðìàöèè. Âû ìîæåòå èñïîëüçîâàòü òåêñò êíèãè ÷àñòè÷íî èëè ïîëíîñòüþ â ñâîèõ ðàáîòàõ ïðè óñëîâèè ðàçìåùåíèÿ ññûëîê íà îðèãèíàë è äîëæíîì öèòèðîâàíèè. Ïðè ýòîì àâòîð áóäåò íåñêàçàííî ðàä ïîëó÷èòü ÷èòàòåëüñêóþ áëàãîäàðíîñòü, êîòîðàÿ ïîçâîëèò êàê óëó÷øèòü òåêñò äàííîé êíèãè, òàê è áîëåå êà÷åñòâåííî ïîäîéòè ê ïîäãîòîâêå ñëåäóþùèõ êíèã. Áëàãîäàðíîñòè ïðèíèìàþòñÿ íà ñ÷¼ò ßíäåêñ.Äåíüãè, íà êîòîðûé ìîæíî ïåðå÷èñëèòü ìàëóþ ëåïòó, è ïðè ïîìîùè òåðìèíàëîâ:
4100137733052 Óáåäèòåëüíàÿ ïðîñüáà; ïðè ïåðå÷èñëåíèè áëàãîäàðíîñòè óêàçûâàòü â ïîÿñíåíèè ê ïåðåâîäó íàèìåíîâàíèå êíèãè èëè êàêîå-ëèáî èíîå óêàçàíèå íà òî, çà ÷òî èìåííî âûðàæàåòñÿ áëàãîäàðíîñòü.
Îãëàâëåíèå Îò àâòîðà
7
Òèïîâîé ïðîöåññ ðàçðàáîòêè ïðîãðàìì íà ÿçûêå Haskell
8
Èíñòðóìåíòàëüíûå ñðåäñòâà . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Îïèñàíèå ïðîöåññà ðàçðàáîòêè . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Ôóíêöèîíàëüíûé ïîäõîä â ïðîãðàììèðîâàíèè Ââåäåíèå . . . . . . . . . . . . . . . . . . . . . Îáùèå ñâîéñòâà ôóíêöèé â ôóíêöèîíàëüíûõ Ïðèìåðû îïðåäåëåíèÿ ôóíêöèé . . . . . . . . Çàêëþ÷åíèå . . . . . . . . . . . . . . . . . . .
15
. . . . . . . . . . . . . . . . . ÿçûêàõ ïðîãðàììèðîâàíèÿ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
Àëãåáðàè÷åñêèå òèïû äàííûõ â ÿçûêå Haskell Ââåäåíèå . . . . . . . . . . . . . . Ïðîñòûå ïåðå÷èñëåíèÿ . . . . . . Ïàðàìåòðèçàöèÿ . . . . . . . . . . Ïàðàìåòðè÷åñêèé ïîëèìîðôèçì . Çàêëþ÷åíèå . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
22 . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Îáúåêòíî-îðèåíòèðîâàííîå è ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå Ââåäåíèå . . . . . . . . . . . . . . Èìåíîâàííûå ïîëÿ è ñòðóêòóðû . Êëàññû òèïîâ . . . . . . . . . . . Ýêçåìïëÿðû êëàññîâ . . . . . . . Îêîí÷àòåëüíûå çàìå÷àíèÿ . . . . Çàêëþ÷åíèå . . . . . . . . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
30 31 34 35 37 39
40 . . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
Êîìáèíàòîðû? Ýòî ïðîñòî! Ââåäåíèå . . . . . . . . . . . . . . . . . . . . . Ôîðìàëüíàÿ òåîðèÿ . . . . . . . . . . . . . . . Ïðèìåðû ñëîæíûõ êîìáèíàòîðîâ . . . . . . . Ìîäóëü íà ÿçûêå Haskell äëÿ ïðåîáðàçîâàíèÿ
22 23 25 27 28
30
Ââåäåíèå â λ-èñ÷èñëåíèå äëÿ íà÷èíàþùèõ Ââåäåíèå . . . . . . . . . . . . . . . . . . . . Íåôîðìàëüíîå îïèñàíèå òåîðèè . . . . . . . Íåêîòîðûå äîïîëíåíèÿ . . . . . . . . . . . . Ðåäóêöèÿ êàê ñòðàòåãèÿ âû÷èñëåíèé . . . . Ïðèìåðû êîäèðîâàíèÿ äàííûõ è ôóíêöèé . Çàêëþ÷åíèå . . . . . . . . . . . . . . . . . .
15 16 17 21
40 41 43 43 46 51
52 . . . . . . . . . . . . . . . . . . . . . . . . . . . êîìáèíàòîðîâ
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
52 52 55 57
Îãëàâëåíèå
5
Ïðåäñòàâëåíèå äàííûõ è ôóíêöèé Áóëåâñêèå çíà÷åíèÿ . . . . . . Íóìåðàëû ×¼ð÷à . . . . . . . Óïîðÿäî÷åííûå ïàðû . . . . . Îáùèå çàìå÷àíèÿ . . . . . . . Çàêëþ÷åíèå . . . . . . . . . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . . . . . . . . . . . . ýêðàí . . . . . . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
Ââîä è âûâîä íà ÿçûêå Haskell
63
Ââåäåíèå . . . . . . . . . . . . . . . . . . . . . . . Îñíîâû ôóíêöèîíàëüíîãî ââîäà/âûâîäà . . . . . Ñòàíäàðòíûå ôóíêöèè ââîäà/âûâîäà . . . . . . . Ïðèìåðû ïðîãðàìì . . . . . . . . . . . . . . . . . Âûâîä ðåçóëüòàòîâ èñïîëíåíèÿ ôóíêöèè íà Àëüòåðíàòèâà: ýêðàí èëè ôàéë . . . . . . . Êîïèðîâàíèå ôàéëîâ . . . . . . . . . . . . . Çàêëþ÷åíèå . . . . . . . . . . . . . . . . . . . . .
Ïðîñòîé èíòåðïðåòàòîð êîìàíä Ââåäåíèå . . . . . . . . . . . . . . . . Ïîñòàíîâêà çàäà÷è . . . . . . . . . . Îñíîâíîé íàáîð ôóíêöèé . . . . . . Âñïîìîãàòåëüíûå òèïû äàííûõ Öèêë èíòåðïðåòàöèè . . . . . . Ôóíêöèè äëÿ èñïîëíåíèÿ êîìàíä . . Çàêëþ÷åíèå . . . . . . . . . . . . . .
63 64 66 69 69 70 71 72
73 . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
Ââåäåíèå . . . . . . . . . . . . . . . . . . . . . . . Ïðîñòåéøèå çàäà÷è . . . . . . . . . . . . . . . . . Òàêèå íåïðîñòûå ïðîñòûå ÷èñëà . . . . . . . . . . ×èñëà Ìåðñåííà . . . . . . . . . . . . . . . . ×èñëà Ôåðìà . . . . . . . . . . . . . . . . . . ×èñëà Ñîôè Æåðìåí . . . . . . . . . . . . . Äðóãèå ïîñëåäîâàòåëüíîñòè ïðîñòûõ ÷èñåë Ñîâåðøåíñòâó íåò ïðåäåëà . . . . . . . . . . . . . Çàêëþ÷åíèå . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
Òåîðèÿ ÷èñåë è ÿçûê Haskell
73 73 74 75 76 78 80
81
Ìàãè÷åñêèå êâàäðàòû è ðåøåíèå ïåðåáîðíûõ çàäà÷ Ââåäåíèå . . . . . . . . . . . . . . . . . . . Ïðîñòåéøèé âàðèàíò ïåðåáîðà . . . . . . Ïåðåáîð ñ èñïîëüçîâàíèåì ïåðåñòàíîâîê . Ïåðåáîð ñ èñïîëüçîâàíèåì ðàçìåùåíèé . Äàëüíåéøàÿ óíèâåðñàëèçàöèÿ àëãîðèòìà Çàêëþ÷åíèå . . . . . . . . . . . . . . . . .
81 82 83 85 86 86 86 87 89
90
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
Çàäà÷à î ðàíöå Ââåäåíèå . . . . . . . . . . . . Êëàññè÷åñêàÿ çàäà÷à . . . . . Ðåàëèçàöèÿ ðåøåíèÿ íà ÿçûêå Çàêëþ÷åíèå . . . . . . . . . .
59 59 60 60 61 61
90 91 94 96 99 102
103 . . . . . . . . . . Haskell . . . . .
. . . .
. . . .
103 104 105 108
6
Îãëàâëåíèå
Êðèâàÿ Äðàêîíà
109
Ââåäåíèå . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ×òî òàêîå Êðèâàÿ Äðàêîíà? . . . . . . . . . . . . . . . . . . Àëãîðèòì ïîñòðîåíèÿ . . . . . . . . . . . . . . . . . . . . . . Ðåàëèçàöèÿ íà ÿçûêå Haskell . . . . . . . . . . . . . . . . . . Ïîäãîòîâèòåëüíûå îïèñàíèÿ ãåîìåòðè÷åñêèõ îáðàçîâ Ïîñòðîåíèå Êðèâîé Äðàêîíà . . . . . . . . . . . . . . . Çàêëþ÷åíèå . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
Íåìíîãî î øàõìàòíûõ çàäà÷àõ Ââåäåíèå . . . . . . . . . . . . . . . . . . . Âñïîìîãàòåëüíûå ïðîãðàììíûå ñóùíîñòè Çàäà÷à î ðàññòàíîâêå ôèãóð . . . . . . . . Çàäà÷à î õîäå êîíÿ . . . . . . . . . . . . .
119 . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
Ãåíåðàöèÿ ðåêóðñèâíûõ ñêàçîê Ââåäåíèå . . . . . . . . . . . . . . . . . . . . . . Êîëîáîê . . . . . . . . . . . . . . . . . . . . . . . Òåðåìîê . . . . . . . . . . . . . . . . . . . . . . . Îáîáùåíèå ôóíêöèé è ïîñòðîåíèå ãåíåðàòîðà Ðåïêà . . . . . . . . . . . . . . . . . . . . . . . . Çàêëþ÷åíèå . . . . . . . . . . . . . . . . . . . .
Ëèòåðàòóðà
109 111 113 113 114 116 118
119 119 122 123
126 . . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
126 127 131 133 136 138
139
Îò àâòîðà  ïåðèîä ñ 2006 ïî 2009 ãîä â îáðàçîâàòåëüíîì æóðíàëå äëÿ ñòàðøåêëàññíèêîâ è ó÷èòåëåé ¾Ïîòåíöèàë¿ (ISSN 1814-6422) áûëè îïóáëèêîâàíû èëè ïîäãîòîâëåíû ê ïóáëèêàöèè ÷åòûðíàäöàòü íàó÷íîïîïóëÿðíûõ ñòàòåé î ôóíêöèîíàëüíîì ïðîãðàììèðîâàíèè è ÿçûêå Haskell. Ìíîãèå èç äàííûõ ñòàòåé íàøëè îïðåäåë¼ííûé îòêëèê â ñåðäöàõ è óìàõ ÷èòàòåëåé, ïîýòîìó àâòîðîì áûëî ðåøåíî ñâåñòè èõ â îäíó êíèãó, âûñòðîèâ â áîëåå èëè ìåíåå ñòðîéíóþ ñèñòåìó ïîâåñòâîâàíèÿ. Âìåñòå ñ òåì ñî âðåìåíè íà÷àëà ïóáëèêàöèè íàó÷íî-ïîïóëÿðíûõ ñòàòåé ïðîøëî äîñòàòî÷íîå êîëè÷åñòâî âðåìåíè, ÷òîáû è ÿçûê Haskell, è ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå â öåëîì ýâîëþöèîíèðîâàëè, ïîýòîìó íåîáõîäèìà è àêòóàëèçàöèÿ èíôîðìàöèè, ïðèâåäåíèå å¼ â áîëåå ñîâðåìåííûé âèä. Âñ¼ ýòî çíà÷èò, ÷òî â íàñòîÿùåé êíèãå èñõîäíûå ñòàòüè íå òîëüêî íå ïðèâåäåíû â èñõîäíîì ïîðÿäêå ïóáëèêàöèè, íî è â íåêîòîðûõ ñëó÷àÿõ äîñòàòî÷íî ñåðü¼çíî ïåðåðàáîòàíû. Êíèãà áóäåò ïîëåçíà øêîëüíèêàì ñòàðøèõ êëàññîâ, æèâî èíòåðåñóþùèìñÿ èíôîðìàòèêîé è ñìåæíûìè îáëàñòÿìè íàóêè è òåõíèêè, à òàêæå ó÷èòåëÿì, êîòîðûå ïðîâîäÿò ôàêóëüòàòèâíûå çàíÿòèÿ ïî èíôîðìàòèêå è êîìïüþòåðíîé ãðàìîòíîñòè. Êðîìå òîãî, ÿ íàäåþñü, ÷òî êíèãà òàêæå áóäåò ïîëåçíà ñòóäåíòàì òåõíè÷åñêèõ âûñøèõ ó÷åáíûõ çàâåäåíèé, êîòîðûå õîòåëè áû îâëàäåòü ïîíèìàíèåì ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ â öåëîì è ÿçûêà Haskell â ÷àñòíîñòè. Íó è â ëþáîì ñëó÷àå êíèãà ñòàíåò íåïëîõèì èñòî÷íèêîì èäåé, çàäà÷ è èõ ðåøåíèé äëÿ âñåõ, êòî èíòåðåñóåòñÿ ôóíêöèîíàëüíûì ïðîãðàììèðîâàíèåì. ß âûðàæàþ ñàìóþ ñåðü¼çíóþ áëàãîäàðíîñòü âñåì ìîèì êîëëåãàì, êîòîðûå â òîé èëè èíîé ìåðå ñïîñîáñòâîâàëè ïîÿâëåíèþ ìíîãèõ èç ïðèâåä¼ííûõ â êíèãå ñòàòåé íà ñâåò. Îñîáî ñòîèò îòìåòèòü Àíòîíþêà Ä. À. è Àñòàïîâà Ä. Å. (â òîì ÷èñëå è â êà÷åñòâå ðåöåíçåíòà), ÷üè áåññìåííûå ñîâåòû è ïðåäëîæåíèÿ ïî óëó÷øåíèþ âñåãäà ïðèõîäèëèñü êñòàòè. Òàêæå õî÷ó âûðàçèòü áëàãîäàðíîñòü âñåìó êîëëåêòèâó ðåäàêöèè æóðíàëà ¾Ïîòåíöèàë¿ çà åãî ñàìîîòâåðæåííûé òðóä íà ïîïðèùå ïðîñâåùåíèÿ è ïîïóëÿðèçàöèè íàóêè ñðåäè ïîäðàñòàþùåãî ïîêîëåíèÿ. Îòäåëüíî õîòåëîñü áû îòìåòèòü Âîðîæöîâà À. Â., ðåäàêòîðà îòäåëà ¾Èíôîðìàòèêà¿. Áóäó êðàéíå ïðèçíàòåëåí ëþáûì êîíñòðóêòèâíûì êîììåíòàðèÿì, çàìå÷àíèÿì è ïðåäëîæåíèÿì, êîòîðûå ìîæíî ïðèñûëàòü ïî àäðåñó ýëåêòðîííîé ïî÷òû
[email protected]. Òàêæå ïî ýòîìó àäðåñó ìîæíî ïðèñûëàòü çàïðîñû íà ôàéëû ñ èñõîäíûìè êîäàìè ïðèìåðîâ, ïðèâåä¼ííûõ â êíèãå (óêàçûâàéòå, ïîæàëóéñòà, íàèìåíîâàíèÿ ýññå, äëÿ êîòîðûõ íåîáõîäèìî âûñëàòü èñõîäíûå êîäû ïðèìåðîâ).  äîáðûé ïóòü.
Äóøêèí Ð. Â. Ìîñêâà, 2011.
Òèïîâîé ïðîöåññ ðàçðàáîòêè ïðîãðàìì íà ÿçûêå Haskell Ñòàòüÿ áûëà ïîäãîòîâëåíà ê ïóáëèêàöèè â îäèí èç íîìåðîâ æóðíàëà ¾Ïîòåíöèàë¿ â êîíöå 2009 ãîäà. Îïóáëèêîâàíà íå áûëà.
 ýññå ðàññêàçûâàåòñÿ î òèïîâîì ïðîöåññå ðàçðàáîòêè ïðîãðàììíûõ ñðåäñòâ íà ôóíêöèîíàëüíîì ÿçûêå ïðîãðàììèðîâàíèÿ Haskell. Îïèñûâàþòñÿ íåêîòîðûå èç èìåþùèõñÿ íà òåêóùèé ìîìåíò ïðîãðàììíûõ ñðåäñòâ è èíñòðóìåíòîâ, äåëàþùèõ ïðîöåññ ðàçðàáîòêè ïðîñòûì è áûñòðûì. Äà¼òñÿ êðàòêàÿ ñóììàðíàÿ èíôîðìàöèÿ î òîì, ãäå è íà êàêèõ óñëîâèÿõ ìîæíî ïîëó÷èòü âåñü íåîáõîäèìûé äëÿ ðàáîòû èíñòðóìåíòàðèé.
 äàëüíåéøåì èçëîæåíèè â íàñòîÿùåé êíèãå ïðèâîäÿòñÿ ðàçíîîáðàçíåéøèå çàäà÷è èç îáëàñòè ìàòåìàòèêè è èíôîðìàòèêè, à òàêæå îïèñûâàþòñÿ ðåøåíèÿ ýòèõ çàäà÷ ïðè ïîìîùè ÿçûêà ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ Haskell. Îïûò îáùåíèÿ àâòîðà ñ ÷èòàòåëÿìè ïîêàçàë, ÷òî èìååòñÿ ïðîáëåìà íåïîñðåäñòâåííî ïðàêòè÷åñêîãî õàðàêòåðà ìíîãèå ÷èòàòåëè ïðîñòî íå çíàþò, ÷òî äåëàòü ñ ïðèâîäèìûìè ïðèìåðàìè è èñõîäíûìè êîäàìè: êàêîé èíñòðóìåíòàðèé èñïîëüçîâàòü, êàê êîìïèëèðîâàòü ïðîãðàììû, êàê çàãðóæàòü äîïîëíèòåëüíûå ïàêåòû è ò. ä. Îñìûñëåíèå ïðîáëåìû ïðèâåëî ê ïîíèìàíèþ òîãî, ÷òî ÿçûê Haskell ïðè âñåõ åãî äîñòîèíñòâàõ î÷åíü ñëîæíî âõîäèò â ðóñëî ïðàêòè÷åñêîãî èñïîëüçîâàíèÿ êàê ëþáèòåëÿìè, òàê è ïðîôåññèîíàëüíûìè ïðîãðàììèñòàìè.  ñâÿçè ñ ýòèì âîçíèêàåò íåîáõîäèìîñòü â èñïîëüçîâàíèè íîâîé ïàðàäèãìû ïîïóëÿðèçàöèè ÿçûêà Haskell è ôóíêöèîíàëüíîãî ïîäõîäà â ïðîãðàììèðîâàíèè (âïåðâûå ââåäåíà â êíèãå [8]). Äàííàÿ ïàðàäèãìà ïðåäïîëàãàåò íåîáõîäèìîñòü âñåìåðíîãî ðàñïðîñòðàíåíèÿ çíàíèé è èíôîðìàöèè î ïðàêòè÷åñêèõ ñðåäñòâàõ è ìåòîäàõ ðàçðàáîòêè, à òåîðåòè÷åñêàÿ ÷àñòü ìîæåò áûòü ïîëó÷åíà çàèíòåðåñîâàííûìè ëþäüìè ñàìîñòîÿòåëüíî, áëàãî â ëèòåðàòóðå èìåííî ïî òåîðåòè÷åñêîé ÷àñòè íåäîñòàòêà íåò (ñì. â òîì ÷èñëå êíèãè [6, 7, 14, 15, 16]). Ýòîò øàã ïîçâîëèò íà ïåðâîíà÷àëüíîì ýòàïå çàèíòåðåñîâàòü è ÷åðåç èíòåðåñ ïðèâëå÷ü ê ôóíêöèîíàëüíîìó ïðîãðàììèðîâàíèþ ìíîæåñòâî íåîôèòîâ. Äàííîå ýññå îïèñûâàåò òèïîâîé ïðîöåññ ðàçðàáîòêè ïðîãðàììíîãî ñðåäñòâà íà ÿçûêå Haskell íà ïðèìåðå ïðîñòåéøåãî ïðèëîæåíèÿ ¾Hello, world!¿. Ñëîæíîñòü ðàçðàáàòûâàåìîãî ïðîãðàììíîãî ñðåäñòâà çäåñü ñîâåðøåííî íå èìååò çíà÷åíèÿ, ïîñêîëüêó îáðèñîâûâàþòñÿ èìåííî ïðîöåññ è èíñòðóìåíòàðèé. ×èòàòåëü âîëåí ñàìîñòîÿòåëüíî ïðèìåíÿòü îïèñûâàåìûå â ðàçäåëå ñðåäñòâà äëÿ ðåøåíèÿ ïðîèçâîëüíûõ çàäà÷, õîòÿ áû è äëÿ ðàññìîòðåíèÿ ïðèìåðîâ â ñëåäóþùèõ ýññå, âõîäÿùèõ â ñîñòàâ êíèãè.
Èíñòðóìåíòàëüíûå ñðåäñòâà Âåñü íàáîð èíñòðóìåíòàëüíûõ ñðåäñòâ, èñïîëüçóåìûõ â ðàáîòå íàä ëþáûì ïðîåêòîì, ìîæíî ðàçäåëèòü íà êëàññû. Ýòî îòíîñèòñÿ íå òîëüêî ê ÿçûêó ïðîãðàììèðîâàíèÿ Haskell, íî è ê ëþáîìó äðóãîìó ÿçûêó
Èíñòðóìåíòàëüíûå ñðåäñòâà
9
ïðîãðàììèðîâàíèÿ, âïðî÷åì, êàê è ê ëþáûì èíûì ïðîåêòàì îò ïðîåêòèðîâàíèÿ äåòñêîé èãðóøêè äî ïîñòðîéêè ãîðîäà.  ïðèíöèïå, ðàçäåëèòü íà êëàññû èíñòðóìåíòàëüíûå ñðåäñòâà äëÿ ðàáîòû ñ ÿçûêîì Haskell ìîæíî òàê, êàê ïîêàçàíî íà ðèñ. 1.
Ðèñ. 1. Êèáåðíåòè÷åñêàÿ ñõåìà ïðåîáðàçîâàíèÿ èäåè â çàêîí÷åííîå ïðîãðàììíîå ñðåäñòâî Òàêæå èíñòðóìåíòàðèé ìîæíî êëàññèôèöèðîâàòü ïî ñòåïåíè ïîëåçíîñòè è íåîáõîäèìîñòè. Íåêîòîðûå êëàññû èíñòðóìåíòîâ îáû÷íî íå èñïîëüçóþòñÿ (ïðåïðîöåññîðû äëÿ ÿçûêà Haskell èñïîëüçóþòñÿ ðåäêî), à áåç, ê ïðèìåðó, òðàíñëÿòîðîâ ÿçûêà âîîáùå íåâîçìîæíî îáîéòèñü. Òàê ÷òî íèæå â òàáëèöå ïåðå÷èñëåíû íàèáîëåå ÷àñòî èñïîëüçóåìûå èíñòðóìåíòàëüíûå ñðåäñòâà, êîòîðûå ïîäõîäÿò äëÿ êàæäîãî ðàçðàáîò÷èêà, äëÿ ëþáîãî ïðîåêòà.
Èíñòðóìåíò
Îïèñàíèå
1
2
Êîìïèëÿòîð GHC
Ñàìûé ìîùíûé è ñîâåðøåííûé êîìïèëÿòîð, íà ñåãîäíÿøíèé äåíü íå èìåþùèé àíàëîãîâ, GHC. Ðåàëèçóåò íå òîëüêî ñòàíäàðò Haskell98, íî è ìíîæåñòâî ðàñøèðåíèé ÿçûêà, ìíîãèå èç êîòîðûõ óæå ñòàëè ñòàíäàðòîì äå-ôàêòî. Èìååò âîçìîæíîñòü ðàáîòû â ðåæèìå èíòåðïðåòàöèè (â ñîñòàâ ïîñòàâêè âõîäèò èíòåðïðåòàòîð GHCi).
Òåñòèðîâàíèå QuickCheck
http://www.haskell.org/ghc/
Äëÿ ïðîâåäåíèÿ òåñòèðîâàíèÿ îáû÷íî èñïîëüçóþòñÿ ñïåöèàëüíûå áèáëèîòåêè âðîäå QuickCheck. Îíè ïîçâîëÿþò ñîçäàâàòü ñåìàíòè÷åñêèå ïðàâèëà, îïèñûâàþùèå ïîâåäåíèÿ ôóíêöèé â ïðîåêòå, ïîñëå ÷åãî çàïóñêàòü ýòè ïðàâèëà íà ïðîâåðêó ñ ðàçëè÷íûìè àðãóìåíòàìè. Ïðîâåðêà îñóùåñòâëÿåòñÿ êîìïèëÿòîðîì â ïðîöåññå ñáîðêè ïðîãðàììû. http://www.md.chalmers.se/rjmh/QuickCheck/
Ïðîäîëæåíèå íà ñëåäóþùåé ñòðàíèöå
10
Òèïîâîé ïðîöåññ ðàçðàáîòêè ïðîãðàìì íà ÿçûêå Haskell 1
2
Äîêóìåíòèðîâàíèå Haddock
Ïðè íàïèñàíèè èñõîäíûõ êîäîâ ìîæíî ñðàçó äîêóìåíòèðîâàòü ïðîãðàììíûå ñóùíîñòè òàêèì îáðàçîì, ÷òî èñïîëüçîâàíèå óòèëèòû Haddock ïîçâîëèò ñîáðàòü ñïðàâî÷íóþ ñèñòåìó äëÿ ðàçðàáîòàííîãî ïðîåêòà â ôîðìàòå HTML. Ýòî ïðàâèëüíûé ïîäõîä ê ðàçðàáîòêå, ïîñêîëüêó äîêóìåíòàöèÿ ïîçâîëÿåò áåç ïðîáëåì ïåðåäàâàòü ðàçðàáîòàííûé ïðîåêò.
Êîíòðîëü âåðñèé Darcs
Ñèñòåìà ñáîðêè Cabal
Ðàñïðîñòðàíåíèå Hackage
http://www.haskell.org/haddock/
Äëÿ õðàíåíèÿ ôàéëîâ ñ èñõîäíûìè êîäàìè è âåäåíèÿ èõ âåðñèé ìîæíî âîñïîëüçîâàòüñÿ óòèëèòîé ðàñïðåäåë¼ííîãî õðàíåíèÿ Darcs. Îíà îáëàäàåò ðÿäîì äîïîëíèòåëüíûõ âîçìîæíîñòåé, ïðåâûøàþùèõ ñòàíäàðòíóþ ôóíêöèîíàëüíîñòü ñèñòåì êîíòðîëÿ âåðñèé. http://www.darcs.net/
Óòèëèòà Cabal ïîçâîëÿåò ñîáðàòü ïàêåò äëÿ ðàñïðîñòðàíåíèÿ ñðåäè ðàçðàáîò÷èêîâ è ïîëüçîâàòåëåé. Ïàêåò ñîáèðàåòñÿ â ñòàíäàðòíîì ôîðìàòå, êîòîðûé ìîæåò áûòü èñïîëüçîâàí íà ïðîèçâîëüíîé ïëàòôîðìå, ïîääåðæèâàþùåé ÿçûê Haskell. Êðîìå òîãî, ýòà æå óòèëèòà ìîæåò óñòàíîâèòü â ñèñòåìó òðåáóåìûé ïàêåò, ñàìîñòîÿòåëüíî ñêà÷àâ åãî èç ñåòè Èíòåðíåò. http://www.haskell.org/cabal/
Äëÿ òîãî ÷òîáû êàæäûé æåëàþùèé ñìîã âîñïîëüçîâàòüñÿ ðàçðàáîòàííûì ïàêåòîì, åãî ìîæíî ïîëîæèòü â îáùèé àðõèâ èñõîäíûõ êîäîâ íà ÿçûêå Haskell Hackage. Ýòîò àðõèâ ÿâëÿåòñÿ öåíòðàëèçîâàííûì, è ñåãîäíÿ â í¼ì õðàíÿòñÿ ñîòíè ðàçëè÷íûõ ïàêåòîâ äëÿ ðåøåíèÿ ïðàêòè÷åñêè ëþáûõ çàäà÷. http://hackage.haskell.org/
Ïåðå÷èñëåííûå â ïðèâåä¼ííîé òàáëèöå èíñòðóìåíòàëüíûå ñðåäñòâà ÿâëÿþòñÿ ñâîáîäíî ðàñïðîñòðàíÿåìûì ïðîãðàììíûì îáåñïå÷åíèåì, äîñòóïíûì äëÿ ïîëó÷åíèÿ ñ óêàçàííûõ àäðåñîâ â ñåòè Èíòåðíåò. ×èòàòåëÿì íàñòîÿòåëüíî ðåêîìåíäóåòñÿ ñêà÷àòü ïåðå÷èñëåííûå ïðîãðàììíûå ñðåäñòâà äëÿ âîçìîæíîñòè ðåàëüíîé ðàáîòû ñ ÿçûêîì Haskell, ÷òî ïîçâîëèò áåç ïðîáëåì ðàáîòàòü íàä ïðèìåðàìè, îïèñàííûìè äàëåå â ýòîé êíèãå.
Îïèñàíèå ïðîöåññà ðàçðàáîòêè
11
Îïèñàíèå ïðîöåññà ðàçðàáîòêè Ïîñëå óñòàíîâêè íà ðàáî÷èé êîìïüþòåð ïåðå÷èñëåííîãî èíñòðóìåíòàðèÿ ìîæíî íà÷èíàòü ðàáîòó íàä ïðîåêòàìè. Íèæå ïðåäñòàâëåíà òèïîâàÿ ñòðóêòóðà ïðîåêòà íà ïðèìåðå ïðîñòåéøåãî ïðèëîæåíèÿ òèïà ¾Hello, World!¿. Òèïîâîé ïðîåêò íà ÿçûêå Haskell áóäåò ñîäåðæàòü ñëåäóþùèå êîìïîíåíòû: 1) _darcs êàòàëîã äëÿ õðàíåíèÿ âåðñèé ôàéëîâ ñ èñõîäíûìè êîäàìè; 2) Hello.hs ãëàâíûé ôàéë ïðîåêòà (â í¼ì ñîäåðæèòñÿ ôóíêöèÿ main); 3) Hello.cabal îïèñàíèå ïðîåêòà äëÿ ñèñòåìû Cabal; 4) Setup.hs ñöåíàðèé ñáîðêè ïðîåêòà â ñèñòåìå Cabal; 5) README ôàéë ñ èíôîðìàöèåé î ïðîåêòå; 6) LICENSE ôàéë ñ îïèñàíèåì ëèöåíçèè. Êîíå÷íî, êàæäûé ðàçðàáîò÷èê âïðàâå âíîñèòü â óêàçàííóþ ñòðóêòóðó èçìåíåíèÿ è äîïîëíåíèÿ, îòðàæàþùèå ñóòü ñîîòâåòñòâóþùåãî ïðîåêòà (íàïðèìåð, ôàéëû ñ èñõîäíûìè êîäàìè õîðîøî áû ðàçìåñòèòü â ïîäêàòàëîãå /src). Çäåñü ïðèâåä¼í èìåííî ïðèìåð ïðîñòåéøåãî ïðîåêòà, ñîñòîÿùåãî, ïî ñóòè, èç îäíîãî ôàéëà ñ èñõîäíûìè êîäàìè. Ê îäíîìó ôàéëó (â ïðèìåðå Hello.hs) äîáàâëÿþòñÿ äîïîëíèòåëüíûå ôàéëû è êàòàëîãè, íåîáõîäèìûå äëÿ ïîääåðæàíèÿ èíôðàñòðóêòóðû ïðîåêòà. Ñëåäóþùàÿ èíñòðóêöèÿ ïîêàçûâàåò ïîøàãîâîå ñîçäàíèå ïðîåêòà ¾Hello, World!¿ äî ïîëó÷åíèÿ èñïîëíÿåìîãî ôàéëà è ðàçìåùåíèÿ åãî â àðõèâå ïðîåêòîâ. 1) Ñîçäàíèå êàòàëîãà ïðîåêòà è ôàéëà ñ èñõîäíûì êîäîì â í¼ì. Ñîäåðæèìîå ôàéëà ìîæåò áûòü ñëåäóþùèì:
module Main −− | Ôóíêöèÿ ' main ' , âûâîäÿùàÿ íà ýêðàí ïðèâåòñòâèå . main : : IO ( ) main = putStr " Hello , World ! " 2) Ñîõðàíåíèå èíôîðìàöèè â ñèñòåìå õðàíåíèÿ âåðñèé. Ýòî äåëàåòñÿ ïðè ïîìîùè ñëåäóþùèõ êîìàíä:
darcs init darcs add Hello . hs darcs record Ïðè âûïîëíåíèè ïîñëåäíåé êîìàíäû óòèëèòà Darcs çàäàñò ïîëüçîâàòåëþ ðÿä âîïðîñîâ, ïîñëå ÷åãî ôàéë Hello.hs áóäåò ñîõðàí¼í â àðõèâå äëÿ ñîõðàíåíèÿ ïåðâîé âåðñèè. 3) Ïîñêîëüêó ôàéë ñ èñõîäíûìè êîäàìè ãîòîâ (ñàìî ñîáîé ðàçóìååòñÿ, ÷òî â ñëó÷àå ñëîæíûõ ïðîåêòîâ íåîáõîäèìî áûòü óâåðåííûì â ïîëíîé ãîòîâíîñòè âñåõ ôàéëîâ ïðîåêòà), íåîáõîäèìî ñîçäàòü ôàéë ñ îïèñàíèåì ïðîåêòà äëÿ ñèñòåìû Cabal. Ñîäåðæèìîå ôàéëà Hello.cabal ñîäåðæèò ïðèìåðíî ñëåäóþùèå äàííûå:
Name : Version : Description : License : License−file : Author :
hello 0.0.0.1 Simplest Haskell Application GPL3 LICENSE John Smith
12
Òèïîâîé ïðîöåññ ðàçðàáîòêè ïðîãðàìì íà ÿçûêå Haskell
Maintainer : Build−Type : Cabal−Version : Executable haq Main−is : Build−Depends :
john . smith@example . com Simple >= 1 . 8 Hello . hs base >= 3 && < 5
Åñëè ðàçðàáàòûâàåìûé ïðîåêò çàâèñèò îò êàêèõ-ëèáî èíûõ ïàêåòîâ, òî âñå îíè äîëæíû áûòü óêàçàíû â ôàéëå . cabal äëÿ ñáîðêè â ïîëå Build−Depends. 4) Äàëåå íåîáõîäèìî íàïèñàòü ñöåíàðèé ñáîðêè. Äëÿ ïîäàâëÿþùåãî ÷èñëà ïðîåêòîâ ñöåíàðèé Setup.hs îäèíàêîâ (óòèëèòà Cabal ïîçâîëÿåò èñïîëüçîâàòü êàê îáû÷íûå ôàéëû . hs, òàê è êîäû â ëèòåðàòóðíîì ñòèëå . lhs). Åãî ñîäåðæèìîå ñëåäóþùåå:
import Distribution . Simple main = defaultMain 5) Åñëè åñòü ïîòðåáíîñòü, ìîæíî ðàçðàáîòàòü ôàéëû README ñ îáùåé èíôîðìàöèåé î ïðîåêòå è LICENSE ñ èíôîðìàöèåé î ëèöåíçèðîâàíèè ïðîåêòà. Ýòè ôàéëû íå ó÷àñòâóþò â ïðîöåññå ñáîðêè, íî ïðåäíàçíà÷àþòñÿ äëÿ áîëåå öåëîñòíîãî ïðåäñòàâëåíèÿ ïðîåêòà ïîòåíöèàëüíûì ïîòðåáèòåëÿì. 6) Íîâûå ôàéëû òàêæå íåîáõîäèìî ñîõðàíèòü â ñèñòåìå õðàíåíèÿ âåðñèé Darcs. Ýòî äåëàåòñÿ ïðè ïîìîùè âûïîëíåíèÿ ñëåäóþùèõ êîìàíä (îïÿòü æå, ïðè èõ âûïîëíåíèè óòèëèòà ìîæåò çàäàòü äîïîëíèòåëüíûå âîïðîñû, íà êîòîðûå íåîáõîäèìî îòâåòèòü ïî ñóùåñòâó):
darcs add Hello . cabal Setup . hs LICENSE README darcs record −−all 7) Ñáîðêà ïðîåêòà ìîæåò îñóùåñòâëÿòüñÿ êàê ïðè ïîìîùè òðàíñëÿòîðà, òàê è ïðè ïîìîùè óòèëèòû Cabal. Ïîñëåäíèé ñïîñîá ãàðàíòèðóåò òî, ÷òî ïîëó÷àåìûå èñïîëíÿåìûå ôàéëû ïðîåêòà áóäóò ãîòîâû äëÿ ñîõðàíåíèÿ â öåíòðàëèçîâàííîì àðõèâå Hackage. Ñáîðêà ïðîåêòà îñóùåñòâëÿåòñÿ ïðè ïîìîùè âûïîëíåíèÿ ñëåäóþùèõ êîìàíä:
cabal install −−prefix =\ $HOME −−user Âûïîëíåíèå êîìàíäû ñîçäàñò â ïîäêàòàëîãå /bin èñïîëíÿåìûé ôàéë ïðîåêòà. Åãî ìîæíî áóäåò çàïóñêàòü íà èñïîëíåíèå. 8) Òåïåðü ìîæíî ñãåíåðèðîâàòü äîêóìåíòàöèþ äëÿ ïðîåêòà. Ýòî òàêæå ìîæíî îñóùåñòâèòü êàê ïðè ïîìîùè óòèëèòû Haddock, òàê è íåïîñðåäñòâåííî èñïîëüçóÿ ñèñòåìó Cabal, ïîñêîëüêó èìååòñÿ öåíòðàëèçîâàííàÿ èíòåãðàöèÿ èíñòðóìåíòîâ ñ ýòîé ñèñòåìîé ñáîðêè. Äîêóìåíòàöèÿ ãåíåðèðóåòñÿ ñëåäóþùåé êîìàíäîé:
cabal haddock  ðåçóëüòàòå èñïîëíåíèÿ êîìàíäû áóäåò ñãåíåðèðîâàí íàáîð ôàéëîâ . html è íåêîòîðûõ äîïîëíèòåëüíûõ ê íèì ñëóæåáíûõ ôàéëîâ è ïîäêàòàëîãîâ. Äàííûå ôàéëû ñîäåðæàò äîêóìåíòàöèþ ïðîåêòà, ñîçäàííóþ íà îñíîâàíèè êîììåíòàðèåâ ðàçðàáîò÷èêà, íàïèñàííûõ â èñõîäíûõ êîäàõ. 9) Òàêæå â ïðîåêò ìîæíî äîáàâèòü ìåòîäû àâòîìàòèçèðîâàííîãî òåñòèðîâàíèÿ ôóíêöèé ïðè ïîìîùè áèáëèîòåêè QuickCheck. Îðãàíèçàöèþ òåñòèðîâàíèÿ ìîæíî îñóùåñòâèòü ïðè ïîìîùè ñèñòåìû õðàíåíèÿ âåðñèé Darcs ïðè ñîõðàíåíèè î÷åðåäíûõ èçìåíåíèé óòèëèòà ñàìîñòîÿòåëüíî áóäåò
Îïèñàíèå ïðîöåññà ðàçðàáîòêè
13
îñóùåñòâëÿòü òåñòèðîâàíèå è áóäåò ïðîèçâîäèòü óâåäîìëåíèå ïîëüçîâàòåëÿ â ñëó÷àÿõ, åñëè òåñòèðîâàíèå çàâåðøèëîñü íåóäà÷åé.  íàñòîÿùåì ïðèìåðå ôóíêöèÿ main ñëèøêîì ïðîñòà äëÿ ïðîâåäåíèÿ òåñòèðîâàíèÿ.  áîëåå ñëîæíûõ ïðîåêòàõ æåëàòåëüíî îðãàíèçîâûâàòü àâòîìàòèçèðîâàííîå òåñòèðîâàíèå äëÿ ¾îòëîâà¿ ïîòåíöèàëüíûõ ëîãè÷åñêèõ îøèáîê. Ïóñòü ñöåíàðèé òåñòèðîâàíèÿ ðàñïîëîæåí â ôàéëå Test.hs, â ýòîì ñëó÷àå èíòåãðàöèÿ ïðîöåññà òåñòèðîâàíèÿ ñ ïðîöåññîì ñîõðàíåíèÿ âåðñèè â ñèñòåìå õðàíåíèÿ âûïîëíÿåòñÿ ïðè ïîìîùè ñëåäóþùåé êîìàíäû:
darcs setpref test " runhaskell Tests . hs " Ñàìî ñîáîé ðàçóìååòñÿ, ÷òî íîâûé ôàéë Test.hs òàêæå íåîáõîäèìî ñîõðàíèòü â ñèñòåìå õðàíåíèÿ âåðñèé. Êñòàòè, â ïîñëåäíèõ âåðñèÿõ Cabal òåñòèðîâàíèå ìîæíî ïðîâîäèòü ñðåäñòâàìè ýòîé óòèëèòû. 10) Ïîñëå ïîÿâëåíèÿ ñòàáèëüíîé âåðñèè ïðîåêòà (âåðñèè, êîòîðàÿ íå ñîäåðæèò êðèòè÷åñêèõ îøèáîê, ïðèâîäÿùèõ ê ¾ïàäåíèþ¿ ïðèëîæåíèÿ) å¼ ìîæíî ïîìåòèòü ñïåöèàëüíûì îáðàçîì â ñèñòåìå õðàíåíèÿ â öåëÿõ áûñòðîãî äîñòóïà ê ôàéëàì âåðñèè. Ýòî äåëàåòñÿ ïðè ïîìîùè ñëåäóþùåé êîìàíäû:
darcs tag Óòèëèòà Darcs çàäàñò äîïîëíèòåëüíûå âîïðîñû î òîì, êàêàÿ ìåòêà äîëæíà áûòü ïðèñâîåíà òåêóùèì âåðñèÿì ôàéëîâ â ðåïîçèòîðèè. 11) Äàëåå ïðè ïîìîùè ñèñòåìû Cabal íåîáõîäèìî ñîçäàòü ïàêåò äëÿ ðàñïðîñòðàíåíèÿ è ïîìåùåíèÿ â öåíòðàëèçîâàííûé àðõèâ Hackage. Ïåðåä ýòèì æåëàòåëüíî ïðîâåðèòü, âñ¼ ëè ãîòîâî äëÿ çàãðóçêè â öåíòðàëèçîâàííûé àðõèâ, äëÿ ÷åãî ìîæíî âûïîëíèòü òàêóþ êîìàíäó:
cabal check Åñëè âñ¼ â ïîðÿäêå, òî ìîæíî ãîòîâèòü ôàéë äëÿ çàãðóçêè â Hackage. Ýòî äåëàåòñÿ ïðîñòî, ïðè ïîìîùè êîìàíäû:
cabal sdist  ðåçóëüòàòå âûïîëíåíèÿ êîìàíäû â êàòàëîãå ïðîåêòà áóäåò ñîçäàí ôàéë hello−0.0.0.1.tar.gz, â êîòîðîì íàõîäÿòñÿ ïîëíîå îïèñàíèå ïðîåêòà, èñõîäíûå êîäû äëÿ íåãî, à ñàì ïðîåêò áóäåò ïîëíîñòüþ ãîòîâ äëÿ ðàçìåùåíèÿ â àðõèâå Hackage. 12) Îêîí÷àòåëüíûì øàãîì â ðàáîòå íàä ïðîåêòîì áóäåò îòñûëêà ôàéëà ñ äèñòðèáóòèâîì (ïàêåòîì) â öåíòðàëèçîâàííûé àðõèâ Hackage. Äëÿ ýòîãî íåîáõîäèìî èìåòü ó÷¼òíóþ çàïèñü ïîëüçîâàòåëÿ àðõèâà (å¼ ìîæíî ïîëó÷èòü ïðè ïîìîùè ðåãèñòðàöèè íà âåá-ñàéòå http://hackage.haskell.org/). Ïîñëå âõîäà â àðõèâ ïîä ó÷¼òíîé çàïèñüþ áóäåò äîñòóïíà ôîðìà äëÿ çàãðóçêè ôàéëà. Çàãðóçêà ôàéëà ïàêåòà íà âåá-ñàéò ïðèâåä¼ò ê àâòîìàòè÷åñêîé ïðîâåðêå è, â ñëó÷àå å¼ óñïåøíîñòè, ïîìåùåíèþ ïàêåòà â àðõèâ. Äåëî ñäåëàíî. Íî äëÿ áîëåå ñåðü¼çíîãî ïðîåêòà áóäåò õîðîøèì òîíîì ñîçäàíèå íà âåá-ñàéòå http://www.haskell.org/ ñòðàíèöû ñ îïèñàíèåì ïðîåêòà. Äàííûé ñàéò îôèöèàëüíûé ñàéò ñîîáùåñòâà ïðîãðàììèñòîâ íà ÿçûêå Haskell. Îí èñïîëüçóåò òåõíîëîãèþ Wiki, ïðè ïîìîùè êîòîðîé ëþáîé æåëàþùèé ïîñåòèòåëü ìîæåò âíåñòè â ñòðàíèöû âåá-ñàéòà èíôîðìàöèþ. Ñîçäàíèå íîâûõ ðàçäåëîâ ñ îïèñàíèÿìè ïðîåêòîâ ïîîùðÿåòñÿ âëàäåëüöàìè ñàéòà, è ñåãîäíÿ íà í¼ì ñîäåðæèòñÿ îïèñàíèå áîëüøèíñòâà ñóùåñòâóþùèõ ïðîåêòîâ, ñîçäàííûõ êàê íà ÿçûêå Haskell, òàê è äëÿ ðàáîòû ñ íèì. Òàêîâ îáùèé ïðîöåññ ðàçðàáîòêè ïðîåêòîâ íà ÿçûêå Haskell. Àâòîð èñêðåííå íàäååòñÿ, ÷òî äàííîå êðàòêîå ýññå ñòàíåò õîðîøèì ïîäñïîðüåì êàê äëÿ íà÷èíàþùèõ ïðîãðàììèñòîâ, òàê è äëÿ óìåëûõ ðàçðàáîò÷èêîâ. Ñîáñòâåííî, çàíèìàòüñÿ ñî âñåìè ïîñëåäóþùèìè ðàçäåëàìè êíèãè ìîæíî èìåííî ïî ïðèâåä¼ííîé ñõåìå.
14
Òèïîâîé ïðîöåññ ðàçðàáîòêè ïðîãðàìì íà ÿçûêå Haskell
Òàêæå íåîáõîäèìî îòìåòèòü, ÷òî â 2009 ãîäó (óæå ïîñëå íàïèñàíèÿ ýòîãî ýññå) ñîîáùåñòâîì ÿçûêà Haskell áûë ïîäãîòîâëåí öåëîñòíûé ïàêåò ïðèêëàäíîãî ïðîãðàììíîãî îáåñïå÷åíèÿ äëÿ ðàáîòû íà ýòîì ÿçûêå Haskell Platform. Äàííûé ïàêåò âêëþ÷àåò â ñåáÿ êîìïèëÿòîð GHC, ñèñòåìó ãåíåðàöèè ñïðàâêè Haddock, ñèñòåìó ïîäãîòîâêè äèñòðèáóòèâîâ Cabal, ïàêåò òåñòèðîâàíèÿ QuickCheck, à òàêæå íåñêîëüêî äðóãèõ ÷àñòî èñïîëüçóåìûõ â ðàáîòå ïàêåòîâ è óòèëèò. Àêòóàëüíîå îïèñàíèå òîãî, êàê ðàçðàáàòûâàòü ïðîãðàììû íà ÿçûêå Haskell, ãîòîâèòü èõ ê ðàñïðîñòðàíåíèþ è ïîìåùàòü â öåíòðàëèçîâàííûé àðõèâ Hackage, âñåãäà ìîæíî íàéòè ïî àäðåñó http://www.haskell.org/haskellwiki/How_to_write_a_Haskell_program.
Ôóíêöèîíàëüíûé ïîäõîä â ïðîãðàììèðîâàíèè Ñòàòüÿ îïóáëèêîâàíà â 08 (56) æóðíàëà ¾Ïîòåíöèàë¿ â àâãóñòå 2009 ãîäà. Ñàìà ïî ñåáå ñòàòüÿ ÿâëÿåòñÿ óïðîù¼ííîé ïåðåðàáîòêîé ñòàòüè ¾Ôóíêöèè è ôóíêöèîíàëüíûé ïîäõîä¿, îïóáëèêîâàííîé â 01 íàó÷íî-ïðàêòè÷åñêîãî æóðíàëà ¾Ïðàêòèêà ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ¿.
 ýññå â ñæàòîé ôîðìå ðàññêàçûâàåòñÿ ïðî ôóíêöèîíàëüíûé ïîäõîä ê îïèñàíèþ âû÷èñëèòåëüíûõ ïðîöåññîâ (è â îáùåì ê îïèñàíèþ ïðîèçâîëüíûõ ïðîöåññîâ â ðåàëüíîì ìèðå), à òàêæå ïðî ïðèìåíåíèå ýòîãî ïîäõîäà â èíôîðìàòèêå â ôóíêöèîíàëüíîé ïàðàäèãìå ïðîãðàììèðîâàíèÿ. Ïðèìåðû ðåàëèçàöèè ôóíêöèé äàþòñÿ íà ÿçûêå ïðîãðàììèðîâàíèÿ Haskell.
Ââåäåíèå Èìååòñÿ íåñêîëüêî ðàçëè÷àþùèõñÿ ïîäõîäîâ ê îðãàíèçàöèè âû÷èñëèòåëüíûõ ïðîöåññîâ, íàèáîëåå èçâåñòíûìè è â êàêîé-òî ñòåïåíè ¾êîíêóðèðóþùèìè¿ ÿâëÿþòñÿ èìïåðàòèâíûé (ïðîöåäóðíûé) è ôóíêöèîíàëüíûé ñòèëè. Ýòè ñòèëè âû÷èñëåíèé áûëè èçâåñòíû â äàë¼êîì ïðîøëîì, è ñåé÷àñ óæå íåâîçìîæíî óçíàòü, êàêîé ïîäõîä áûë ðàçðàáîòàí ïåðâûì. Ïîñëåäîâàòåëüíîñòè øàãîâ âû÷èñëåíèé, êàê îñîáåííîñòü ïðîöåäóðíîãî ñòèëÿ, ìîæíî ðàññìàòðèâàòü â êà÷åñòâå åñòåñòâåííîãî ñïîñîáà âûðàæåíèÿ ÷åëîâå÷åñêîé äåÿòåëüíîñòè ïðè å¼ ïëàíèðîâàíèè. Ýòî ñâÿçàíî ñ òåì, ÷òî ÷åëîâåêó ïðèõîäèòñÿ æèòü â ìèðå, ãäå íåóìîëèìûé áåã âðåìåíè è îãðàíè÷åííîñòü ðåñóðñîâ êàæäîãî îòäåëüíîãî èíäèâèäóóìà çàñòàâëÿë ëþäåé ïëàíèðîâàòü ïî øàãàì ñâîþ äàëüíåéøóþ æèçíåäåÿòåëüíîñòü. Âìåñòå ñ òåì íåëüçÿ ñêàçàòü, ÷òî ôóíêöèîíàëüíûé ñòèëü âû÷èñëåíèé áûë íåèçâåñòåí ÷åëîâåêó, à ïîÿâèëñÿ òîëüêî ñ âîçíèêíîâåíèåì òåîðèè âû÷èñëåíèé â òîì èëè èíîì âèäå â êîíöå XIX íà÷àëå XX âåêà. Äåêîìïîçèöèÿ çàäà÷è íà ïîäçàäà÷è è âûðàæåíèå åù¼ íåðåø¼ííûõ ïðîáëåì ÷åðåç óæå ðåø¼ííûå ýòè ìåòîäèêè òàêæå áûëè èçâåñòíû ñ äàâíèõ âðåì¼í, à èìåííî îíè ñîñòàâëÿþò ñóòü ôóíêöèîíàëüíîãî ïîäõîäà. Èìåííî ýòîò ïîäõîä è ÿâëÿåòñÿ ïðåäìåòîì ðàññìîòðåíèÿ íàñòîÿùåãî ðàçäåëà, à îáúÿñíÿòüñÿ åãî ïîëîæåíèÿ áóäóò ïðè ïîìîùè ôóíêöèîíàëüíîãî ÿçûêà Haskell (äëÿ èçó÷åíèÿ ÿçûêà ìîæíî âîñïîëüçîâàòüñÿ êíèãîé [6]). Íåñìîòðÿ íà òî ÷òî ôàêòè÷åñêè ôóíêöèîíàëüíûé ïîäõîä ê âû÷èñëåíèÿì áûë èçâåñòåí ñ äàâíèõ âðåì¼í, åãî òåîðåòè÷åñêèå îñíîâû ñòàëè ðàçðàáàòûâàòüñÿ âìåñòå ñ íà÷àëîì ðàáîò íàä âû÷èñëèòåëüíûìè ìàøèíàìè ñíà÷àëà ìåõàíè÷åñêèìè, à ïîòîì óæå è ýëåêòðîííûìè. Ñ ðàçâèòèåì ôîðìàëüíîé ëîãèêè è îáîáùåíèåì ìíîæåñòâà ñõîäíûõ èäåé ïîä ñâîäîì êèáåðíåòèêè ïîÿâèëîñü ïîíèìàíèå òîãî, ÷òî ôóíêöèÿ ÿâëÿåòñÿ ïðåêðàñíûì ìàòåìàòè÷åñêèì ôîðìàëèçìîì äëÿ îïèñàíèÿ ðåàëèçóåìûõ â ôèçè÷åñêîì ìèðå óñòðîéñòâ [2]. Íî íå âñÿêàÿ ôóíêöèÿ, à òîëüêî òàêàÿ, êîòîðàÿ îáëàäàåò ðÿäîì âàæíûõ ñâîéñòâ, à èìåííî: âî-ïåðâûõ, îíà îïåðèðóåò èñêëþ÷èòåëüíî ñâîåé âíóòðåííåé ïàìÿòüþ, à âî-âòîðûõ, îíà äåòåðìèíèðîâàíà (òî åñòü å¼ çíà÷åíèå çàâèñèò òîëüêî îò âõîäíûõ ïàðàìåòðîâ ýòî ñâîéñòâî áóäåò ïîäðîáíî ðàññìîòðåíî äàëåå). Äàííûå îãðàíè÷åíèÿ íà ðåàëèçóåìîñòü â ðåàëüíîñòè ñâÿçàíû ñ ôèçè÷åñêèìè çàêîíàìè ñîõðàíåíèÿ,
16
Ôóíêöèîíàëüíûé ïîäõîä â ïðîãðàììèðîâàíèè
â ïåðâóþ î÷åðåäü ýíåðãèè. Èìåííî òàêèå ¾÷èñòûå¿ ïðîöåññû ðàññìàòðèâàþòñÿ â êèáåðíåòèêå ïðè ïîìîùè ìåòîäîëîãèè ÷¼ðíîãî ÿùèêà ðåçóëüòàò ðàáîòû òàêîãî ÿùèêà çàâèñèò òîëüêî îò çíà÷åíèé âõîäíûõ ïàðàìåòðîâ. Êëàññè÷åñêàÿ èëëþñòðàöèÿ, äåìîíñòðèðóþùàÿ ýòó ñèòóàöèþ, âñòðå÷àåòñÿ â áîëüøèíñòâå ó÷åáíèêîâ ïî êèáåðíåòèêå è ñìåæíûì äèñöèïëèíàì:
x1 x 2 X ...xm
- y1 . . .- y2 Y yn
F
Ðèñ. 2. ×¼ðíûé ÿùèê ôóíêöèè F ñ âåêòîðîì âõîäîâ X è âåêòîðîì âûõîäîâ Y Ôîðìàëüíûå îñíîâû òåîðèè âû÷èñëåíèé áûëè çàëîæåíû íåñêîëüêèìè ó÷¼íûìè, îäíèì èç âåäóùèõ ñðåäè êîòîðûõ áûë Àëîíçî ×¼ð÷, ïðåäëîæèâøèé â êà÷åñòâå ôîðìàëèçìà äëÿ ïðåäñòàâëåíèÿ âû÷èñëèìûõ ôóíêöèé è ïðîöåññîâ λ-èñ÷èñëåíèå [1]. Ñàìî ïî ñåáå λ-èñ÷èñëåíèå ïðåäëàãàåò íîòàöèþ äëÿ ïðîñòåéøåãî ÿçûêà ïðîãðàììèðîâàíèÿ. Ñîáñòâåííî, ÿäðî ÿçûêà ïðîãðàììèðîâàíèÿ Haskell ïðåäñòàâëÿåò ñîáîé òèïèçèðîâàííîå λ-èñ÷èñëåíèå. Òàêæå ñòîèò óïîìÿíóòü ïðî êîìáèíàòîðíóþ ëîãèêó [4], êîòîðàÿ èñïîëüçóåò íåñêîëüêî èíóþ íîòàöèþ äëÿ ïðåäñòàâëåíèÿ ôóíêöèé, à â êà÷åñòâå áàçîâîé îïåðàöèè èñïîëüçóåò òîëüêî ïðèìåíåíèå ôóíêöèè ê ñâîèì àðãóìåíòàì. Áàçèñ ñèñòåìû ñîñòîèò èç îäíîãî êîìáèíàòîðà, òî åñòü óòâåðæäàåòñÿ, ÷òî ëþáàÿ ôóíêöèÿ ìîæåò áûòü âûðàæåíà ÷åðåç ýòîò åäèíñòâåííûé áàçèñíûé êîìáèíàòîð (áàçèñíóþ ôóíêöèþ). Òðàäèöèîííî èñïîëüçóþòñÿ íåñêîëüêî áîëåå ðàñøèðåííûå áàçèñû (íàïðèìåð, áàçèñ S, K, I), ÷òî ïîçâîëÿåò ñîêðàòèòü çàïèñè â íîòàöèè êîìáèíàòîðíîé ëîãèêè. Ñàìà ïî ñåáå êîìáèíàòîðíàÿ ëîãèêà èçîìîðôíà λ-èñ÷èñëåíèþ, íî îáëàäàåò, ïî ñëîâàì íåêîòîðûõ ñïåöèàëèñòîâ, áîëüøåé âûðàçèòåëüíîé ñèëîé. Òàêèì îáðàçîì, ôóíêöèîíàëüíûé ïîäõîä èìååò â ñâî¼ì îñíîâàíèè ñåðü¼çíóþ òåîðåòè÷åñêóþ ïðîðàáîòêó, à ïîòîìó åãî èçó÷åíèå ìîæåò ñòàòü ñåðü¼çíûì ïîäñïîðüåì êàê äëÿ íà÷èíàþùèõ ðàçðàáîò÷èêîâ ïðîãðàììíîãî îáåñïå÷åíèÿ, òàê è äëÿ ïðîôåññèîíàëîâ, æåëàþùèõ ðàñøèðèòü ñâîé êðóãîçîð è ïîëó÷èòü íàâûêè âëàäåíèÿ íîâûìè èíñòðóìåíòàìè äëÿ ðåøåíèÿ ïðàêòè÷åñêèõ çàäà÷.
Îáùèå ñâîéñòâà ïðîãðàììèðîâàíèÿ
ôóíêöèé
â
ôóíêöèîíàëüíûõ
ÿçûêàõ
Ïåðåä èçó÷åíèåì ïðèìåðîâ íåîáõîäèìî ðàññìîòðåòü îáùèå ñâîéñòâà ôóíêöèé, ðàññìàòðèâàåìûå â ôóíêöèîíàëüíîì ïðîãðàììèðîâàíèè. Ê òàêèì ñâîéñòâàì íàèáîëåå ÷àñòî îòíîñÿò (òî åñòü îòñóòñòâèå ïîáî÷íûõ ýôôåêòîâ è äåòåðìèíèðîâàííîñòü), è (íàëè÷èå ó ôóíêöèè îñîáîãî òèïà, ÷òî âëå÷¼ò çà ñîáîé âîçìîæíîñòü ïðîèçâîäèòü ÷àñòè÷íûå âû÷èñëåíèÿ è èñïîëüçîâàòü ôóíêöèè â êà÷åñòâå îáúåêòà âû÷èñëåíèé ïîëó÷àòü èõ â êà÷åñòâå ïàðàìåòðîâ è âîçâðàùàòü â êà÷åñòâå ðåçóëüòàòîâ). Èòàê, êàê óæå óïîìèíàëîñü, ôèçè÷åñêè ðåàëèçóåìûìè ÿâëÿþòñÿ òàêèå êèáåðíåòè÷åñêèå ìàøèíû, âûõîä êîòîðûõ çàâèñèò òîëüêî îò çíà÷åíèé âõîäíûõ ïàðàìåòðîâ. Ýòî ïîëîæåíèå îòíîñèòñÿ è ê òàêèì êèáåðíåòè÷åñêèì ìàøèíàì, êîòîðûå èìåþò âíóòðåííèé íàêîïèòåëü ïàìÿòü. Äàííîå ïîëîæåíèå íàøëî ÷¼òêîå îòðàæåíèå â ïàðàäèãìå ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ, ïîñêîëüêó â íåé ïðèíÿòî, ÷òî ôóíêöèè, ÿâëÿÿñü ÷èñòûìè ìàòåìàòè÷åñêèìè îáúåêòàìè, äîëæíû îáëàäàòü ñâîéñòâîì ÷èñòîòû. Ýòî îáîçíà÷àåò, ÷òî ôóíêöèÿ ìîæåò óïðàâëÿòü òîëüêî âûäåëåííîé äëÿ íå¼ ïàìÿòüþ, íå ìîäèôèöèðóÿ ïàìÿòü âî âíå ñâîåé îáëàñòè. Ëþáîå èçìåíåíèå ñòîðîííåé ïàìÿòè íàçûâàåòñÿ ïîáî÷íûì ýôôåêòîì, è ôóíêöèÿì â ôóíêöèîíàëüíûõ ÿçûêàõ ïðîãðàììèðîâàíèÿ îáû÷íî çàïðåùåíî èìåòü ïîáî÷íûå ýôôåêòû. Òî æå è ñ äåòåðìèíèðîâàííîñòüþ. Äåòåðìèíèðîâàííîé íàçûâàåòñÿ ôóíêöèÿ, âûõîäíîå çíà÷åíèå êîòîðîé çàâèñèò òîëüêî îò çíà÷åíèé âõîäíûõ ïàðàìåòðîâ. Åñëè ïðè îäèíàêîâûõ çíà÷åíèÿõ âõîäíûõ ïàðàìåòðîâ â ðàçëè÷íûõ âûçîâàõ ôóíêöèÿ ìîæåò âîçâðàùàòü ðàçëè÷íûå çíà÷åíèÿ, òî ãîâîðÿò, ÷òî
ëåíèâîñòü
÷èñòîòó êàððèðîâàííîñòü
Ïðèìåðû îïðåäåëåíèÿ ôóíêöèé
17
òàêàÿ ôóíêöèÿ ÿâëÿåòñÿ íåäåòåðìèíèðîâàííîé. Ñîîòâåòñòâåííî, îáû÷íî âñå ôóíêöèè â ôóíêöèîíàëüíîé ïàðàäèãìå ÿâëÿþòñÿ äåòåðìèíèðîâàííûìè. Êîíå÷íî, åñòü íåêîòîðûå èñêëþ÷åíèÿ, ïîñêîëüêó, ê ïðèìåðó, ñèñòåìó ââîäà-âûâîäà íåâîçìîæíî ñäåëàòü áåç ïîáî÷íûõ ýôôåêòîâ è â óñëîâèÿõ ïîëíîé äåòåðìèíèðîâàííîñòè. Òàêæå è ãåíåðàöèÿ ïñåâäîñëó÷àéíûõ ÷èñåë îñóùåñòâëÿåòñÿ íåäåòåðìèíèðîâàííîé ôóíêöèåé. Ñàìî ñîáîé ðàçóìååòñÿ, ÷òî ýòè ïðàêòè÷åñêèå çàäà÷è äîëæíû ðåøàòüñÿ óíèâåðñàëüíûì ÿçûêîì ïðîãðàììèðîâàíèÿ, êîèì ÿâëÿåòñÿ ÿçûê Haskell.  ÿçûêå èìåþòñÿ ñïåöèàëüíûå ìåõàíèçìû äëÿ ýòîãî, íî èõ ðàññìîòðåíèå âûõîäèò çà ðàìêè íàñòîÿùåãî ðàçäåëà. Î÷åíü èíòåðåñíûì ñâîéñòâîì ôóíêöèé ÿâëÿåòñÿ ëåíèâîñòü. Íå âñå ôóíêöèîíàëüíûå ÿçûêè ïðåäîñòàâëÿþò ðàçðàáîò÷èêó âîçìîæíîñòü îïðåäåëÿòü ëåíèâûå ôóíêöèè, íî ÿçûê Haskell èçíà÷àëüíî ÿâëÿåòñÿ ëåíèâûì, è ðàçðàáîò÷èêó íåîáõîäèìî äåëàòü ñïåöèàëüíûå ïîìåòêè äëÿ ôóíêöèé, êîòîðûå äîëæíû îñóùåñòâëÿòü ¾ýíåðãè÷íûå¿ âû÷èñëåíèÿ. Ëåíèâàÿ æå ñòðàòåãèÿ âû÷èñëåíèé çàêëþ÷àåòñÿ â òîì, ÷òî ôóíêöèÿ íå ïðîèçâîäèò âû÷èñëåíèé äî òåõ ïîð, ïîêà èõ ðåçóëüòàò íå áóäåò íåîáõîäèì â ðàáîòå ïðîãðàììû [9]. Òàê, çíà÷åíèÿ âõîäíûõ ïàðàìåòðîâ íèêîãäà íå âû÷èñëÿþòñÿ, åñëè îíè íå òðåáóþòñÿ â òåëå ôóíêöèè. Ýòî ïîçâîëÿåò â òîì ÷èñëå ñîçäàâàòü ïîòåíöèàëüíî áåñêîíå÷íûå ñòðóêòóðû äàííûõ (ñïèñêè, äåðåâüÿ è ò. ä.), êîòîðûå îãðàíè÷åíû òîëüêî ôèçè÷åñêèì ðàçìåðîì êîìïüþòåðíîé ïàìÿòè. Òàêèå áåñêîíå÷íûå ñòðóêòóðû âïîëíå ìîæíî îáðàáàòûâàòü ëåíèâûì ñïîñîáîì, ïîñêîëüêó âû÷èñëÿþòñÿ â íèõ òîëüêî òå ýëåìåíòû, êîòîðûå íåîáõîäèìû äëÿ ðàáîòû. È ïåðåäà÷à íà âõîä êàêîé-ëèáî ôóíêöèè áåñêîíå÷íîãî ñïèñêà íå âëå÷¼ò çàöèêëèâàíèÿ ïðîãðàììû, ïîñêîëüêó îíà íå âû÷èñëÿåò âåñü ýòîò ñïèñîê öåëèêîì (÷òî áûëî áû íåâîçìîæíûì). Íàêîíåö, óæå óïîìèíàëîñü, ÷òî ó ôóíêöèé åñòü òèï.  ôóíêöèîíàëüíûõ ÿçûêàõ ïðîãðàììèðîâàíèÿ ïðèíÿòî, ÷òî òèï ôóíêöèé ÿâëÿåòñÿ êàððèðîâàííûì, òî åñòü òàêèì, îáùèé âèä êîòîðîãî âûãëÿäèò ñëåäóþùèì îáðàçîì:
A1 → (A2 → . . . (An → B) . . .),
(1)
ãäå A1 , A2 , . . . An òèïû âõîäíûõ ïàðàìåòðîâ, à B òèï ðåçóëüòàòà. Êàððèðîâàííîñòü ôóíêöèé îçíà÷àåò, ÷òî òàêèå ôóíêöèè ïðèíèìàþò âõîäíûå ïàðàìåòðû ïîîäèíî÷êå, à â ðåçóëüòàòå òàêîãî îäèíî÷íîãî ïðèìåíåíèÿ ïîëó÷àåòñÿ íîâàÿ ôóíêöèÿ. Òàê, åñëè â ôóíêöèþ óêàçàííîãî âûøå òèïà ïîäàòü ïåðâûé ïàðàìåòð òèïà A1 , òî â èòîãå ïîëó÷èòñÿ íîâàÿ ôóíêöèÿ ñ òèïîì:
A2 → (A3 → . . . (An → B) . . .).
(2)
Êîãäà íà âõîä ôóíêöèè ïîäàþòñÿ âñå âõîäíûå ïàðàìåòðû, â ðåçóëüòàòå ïîëó÷àåòñÿ çíà÷åíèå òèïà B .  ñâîþ î÷åðåäü, ýòî îçíà÷àåò íå òîëüêî âîçìîæíîñòü (íà âõîä ôóíêöèè ïåðåäà¼òñÿ òîëüêî ÷àñòü ïàðàìåòðîâ, à íå âñå ñðàçó), íî è òî, ÷òî ôóíêöèè ñàìè ïî ñåáå ìîãóò áûòü îáúåêòàìè âû÷èñëåíèé, òî åñòü ïåðåäàâàòüñÿ â êà÷åñòâå ïàðàìåòðîâ äðóãèì ôóíêöèÿì è áûòü âîçâðàùàåìûìè â êà÷åñòâå ðåçóëüòàòîâ. Âåäü íèêòî íå îãðàíè÷èâàåò óêàçàííûå òèïû A1 , A2 , . . . An è B òîëüêî òèïàìè äàííûõ, ýòî âñ¼ ìîãóò áûòü òàêæå è ôóíêöèîíàëüíûå òèïû. Ïåðå÷èñëåííûå ñâîéñòâà ôóíêöèé â ôóíêöèîíàëüíûõ ÿçûêàõ ïðîãðàììèðîâàíèÿ îòêðûâàþò äîïîëíèòåëüíûå âîçìîæíîñòè ïî èñïîëüçîâàíèþ ôóíêöèîíàëüíîãî ïîäõîäà, ïîýòîìó ðàçðàáîò÷èêàì ïðîãðàììíîãî îáåñïå÷åíèÿ ðåêîìåíäóåòñÿ èçó÷èòü ýòîò âîïðîñ áîëåå ïîäðîáíî.
÷àñòè÷íîãî ïðèìåíåíèÿ
Ïðèìåðû îïðåäåëåíèÿ ôóíêöèé  îäíîé èç êîììåð÷åñêèõ êîìïàíèé ïðè îòáîðå êàíäèäàòîâ íà âàêàíòíûå äîëæíîñòè èíæåíåðîâïðîãðàììèñòîâ ïðèøåäøèì çàäàâàëàñü ïðîñòàÿ çàäà÷à íåîáõîäèìî íàïèñàòü ôóíêöèþ, êîòîðàÿ ïîëó÷àåò íà âõîä íåêîòîðîå öåëîå ÷èñëî, à âîçâðàùàåò ñòðîêó ñ ïðåäñòàâëåíèåì äàííîãî ÷èñëà â øåñòíàäöàòåðè÷íîì âèäå. Çàäà÷à î÷åíü ïðîñòàÿ, íî âìåñòå ñ òåì îíà äîñòàòî÷íî ëåãêî ìîæåò ïðîÿâèòü ìåòîäû ðåøåíèÿ çàäà÷ ó êàíäèäàòîâ, ïîýòîìó îñíîâíîé óïîð íà ñîáåñåäîâàíèè äåëàëñÿ íå íà ïðàâèëüíîñòü
18
Ôóíêöèîíàëüíûé ïîäõîä â ïðîãðàììèðîâàíèè
íàïèñàíèÿ êîäà, à íà ïîäõîä è êàíâó ðàññóæäåíèé ïðè íàïèñàíèè ýòîé ôóíêöèè. Áîëåå òîãî, åñëè êàíäèäàò çàòðóäíÿëñÿ ñ àëãîðèòìîì, åìó îí ïîëíîñòüþ ðàçúÿñíÿëñÿ, ïîñêîëüêó èíòåðåñíû áûëè èìåííî õîä ðàññóæäåíèé è îêîí÷àòåëüíûé ñïîñîá ðåàëèçàöèè àëãîðèòìà. Ñîîòâåòñòâåííî, äëÿ ðåøåíèÿ çàäà÷è ìîæíî áûëî èñïîëüçîâàòü ïðîèçâîëüíûé ÿçûê ïðîãðàììèðîâàíèÿ íà âûáîð êàíäèäàòà. Ìîæíî áûëî äàæå èñïîëüçîâàòü ïñåâäîÿçûê îïèñàíèÿ àëãîðèòìîâ, áëîê-ñõåìû è ïðî÷èå ïîäîáíûå âåùè. Ñàì àëãîðèòì ïðîñò. Íåîáõîäèìî äåëèòü çàäàííîå ÷èñëî íà îñíîâàíèå (â çàäàâàåìîé çàäà÷å, ñòàëî áûòü, íà 16), ñîáèðàòü îñòàòêè è ïðîäîëæàòü ýòîò ïðîöåññ äî òåõ ïîð, ïîêà â ðåçóëüòàòå äåëåíèÿ íå ïîëó÷èòñÿ 0. Ïîëó÷åííûå îñòàòêè íåîáõîäèìî ïåðåâåñòè â ñòðîêîâûé âèä ïîñèìâîëüíî (ó÷èòûâàÿ øåñòíàäöàòåðè÷íûå öèôðû), ïîñëå ÷åãî ñöåïèòü (ïðè ïîìîùè îïåðàöèè êîíêàòåíàöèè) âñå ýòè ñèìâîëû â ðåçóëüòèðóþùóþ ñòðîêó â ïðàâèëüíîì íàïðàâëåíèè (ïåðâûé îñòàòîê äîëæåí áûòü ïîñëåäíèì ñèìâîëîì â ðåçóëüòèðóþùåé ñòðîêå, âòîðîé ïðåäïîñëåäíèì è ò. ä.). Êàêîâû áûëè òèïîâûå ðàññóæäåíèÿ áîëüøèíñòâà ïðèõîäÿùèõ íà ñîáåñåäîâàíèå? ¾Ïîëó÷àåì âõîäíîå ÷èñëî îðãàíèçóåì öèêë while äî òåõ ïîð, ïîêà ïàðàìåòð öèêëà íå ñòàíåò ðàâåí 0 â öèêëå ñîáèðàåì îñòàòêè îò äåëåíèÿ ïàðàìåòðà íà îñíîâàíèå, òóò æå ïåðåâîäèì èõ â ñèìâîëû è êîíêàòåíèðóåì ñ ïåðåìåííîé, êîòîðàÿ ïîòîì áóäåò âîçâðàùåíà â êà÷åñòâå ðåçóëüòàòà ïåðåä âîçâðàùåíèåì ïåðåìåííóþ îáðàùàåì¿. Ê ñîæàëåíèþ, çà âñ¼ âðåìÿ ðàáîòû äàííîé îðãàíèçàöèè íè îäèí èç êàíäèäàòîâ íå ïðåäëîæèë ðåøåíèÿ çàäà÷è â ôóíêöèîíàëüíîì ñòèëå. Âîò êàê âûãëÿäèò òèïîâàÿ ôóíêöèÿ äëÿ îïèñàííîé öåëè íà ÿçûêå C++:
std : : string int2hex ( int i ) {
std : : string result = " " ; while ( i ) { result = hexDigit ( i % 1 6 ) + result ; i /= 1 6 ; } return result ; } Çäåñü ôóíêöèÿ hexDigit âîçâðàùàåò ñèìâîë, ñîîòâåòñòâóþùèé øåñòíàäöàòåðè÷íîé öèôðå. Êàê æå ðåøèòü ýòó çàäà÷ó ïðè ïîìîùè ôóíêöèîíàëüíîãî ïîäõîäà? Ïðè ðàçìûøëåíèè ñòàíîâèòñÿ ÿñíî, ÷òî, âçÿâ ïåðâûé îñòàòîê îò äåëåíèÿ íà 16 è ïîñëå ýòîãî öåëî÷èñëåííî ðàçäåëèâ ñàìî ÷èñëî íà 16, çàäà÷à ñâîäèòñÿ ê òîé æå ñàìîé. È òàêîå ñâåäåíèå áóäåò ïðîèñõîäèòü äî òåõ ïîð, ïîêà ÷èñëî, êîòîðîå íåîáõîäèìî äåëèòü, íå ñòàíåò ðàâíûì 0. Íàëèöî ðåêóðñèÿ, êîòîðàÿ ÿâëÿåòñÿ îäíèì èç øèðîêî èñïîëüçóåìûõ ìåòîäîâ ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ. Íà ÿçûêå Haskell ýòà çàäà÷à ìîæåò áûòü ðåøåíà ñëåäóþùèì îáðàçîì:
int2hex : : Integer −> String int2hex 0 = "" int2hex i = int2hex ( div i 1 6 ) ++ hexDigit ( mod i 1 6 ) Çäåñü ôóíêöèè div è mod âîçâðàùàþò ñîîòâåòñòâåííî ðåçóëüòàò öåëî÷èñëåííîãî äåëåíèÿ è îñòàòîê îò òàêîãî äåëåíèÿ. Ôóíêöèÿ (++) êîíêàòåíèðóåò äâå ñòðîêè. Âñå ýòè ôóíêöèè îïðåäåëåíû â ñòàíäàðòíîì ìîäóëå Prelude. Ïåðâàÿ ñòðîêà îïðåäåëåíèÿ ôóíêöèè òàê íàçûâàåìàÿ ñèãíàòóðà, êîòîðàÿ îïðåäåëÿåò òèï ôóíêöèè (íåîáõîäèìî îáðàòèòü âíèìàíèå íà ýòó çàïèñü îíà ïîëíîñòüþ ñîîòâåòñòâóåò òîìó, ÷òî îïèñàíî â ïðåäûäóùåì ðàçäåëå îòíîñèòåëüíî ôóíêöèîíàëüíûõ òèïîâ). Âòîðàÿ ñòðîêà îïðåäåëÿåò ðåçóëüòàò ôóíêöèè int2hex â ñëó÷àå, åñëè çíà÷åíèåì å¼ åäèíñòâåííîãî âõîäíîãî ïàðàìåòðà áóäåò 0 (çäåñü òàêæå íåîáõîäèìî îòìåòèòü, ÷òî îïðåäåëåíèå íå î÷åíü êîððåêòíî îíî íå áóäåò ðàáîòàòü íà ãðàíè÷íîì çíà÷åíèè âõîäíîãî ïàðàìåòðà 0, ïîýòîìó ôàêòè÷åñêè ôóíêöèÿ îïðåäåëåíà òîëüêî äëÿ íàòóðàëüíûõ ÷èñåë). Òðåòüÿ ñòðîêà, ñîîòâåòñòâåííî, îïðåäåëÿåò ðåçóëüòàò
Ïðèìåðû îïðåäåëåíèÿ ôóíêöèé
19
ôóíêöèè â îñòàâøèõñÿ ñëó÷àÿõ (êîãäà çíà÷åíèå âõîäíîãî ïàðàìåòðà íåíóëåâîå). Çäåñü ïðèìåí¼í ìåõàíèçì , êîãäà äëÿ îïðåäåëåíèÿ ôóíêöèè çàïèñûâàþòñÿ íåñêîëüêî âûðàæåíèé (èíîãäà â ëèòåðàòóðå ïî ôóíêöèîíàëüíîìó ïðîãðàììèðîâàíèþ èñïîëüçóåòñÿ òåðìèí ¾ ¿ îò àíãë. ¾clause¿ äëÿ îáîçíà÷åíèÿ îäíîãî òàêîãî âûðàæåíèÿ â îïðåäåëåíèè ôóíêöèè), êàæäûé èç êîòîðûõ îïðåäåëÿåò çíà÷åíèå ôóíêöèè â îïðåäåë¼ííûõ óñëîâèÿõ. Ïðåäñòàâëåííûé ïðèìåð óæå äîñòàòî÷íî ïîêàçûâàåò îòëè÷èå äâóõ ïîäõîäîâ ê ïðåäñòàâëåíèþ âû÷èñëåíèé. Òåì íå ìåíåå óæå ñåé÷àñ âèäíî, ÷òî èìååòñÿ øèðîêèé ïðîñòîð äëÿ óñîâåðøåíñòâîâàíèÿ êîäà.  ïåðâóþ î÷åðåäü ýòî êàñàåòñÿ îñíîâàíèÿ ïðåîáðàçîâàíèÿ, âåäü ÷àñòî ïðè ïðîãðàììèðîâàíèè íåîáõîäèìû ÷èñëà â äâîè÷íîé è âîñüìåðè÷íîé çàïèñè. Áîëåå òîãî, ïî÷åìó áû íå ñäåëàòü óíèâåðñàëüíóþ ôóíêöèþ äëÿ ïðåîáðàçîâàíèÿ ÷èñëà â ïðîèçâîëüíóþ ñèñòåìó ñ÷èñëåíèÿ? Ýòà çàäà÷à ëåãêî ðåøàåòñÿ ïðåîáðàçîâàíèåì óæå íàïèñàííîé ôóíêöèè:
ñîïîñòàâëåíèÿ ñ îáðàçöàìè
êëîç
convert : : Int −> Int −> String convert _ 0 = "" convert r i = convert r ( div i r ) ++ digit r ( mod i r ) Çäåñü â ñèãíàòóðó âíåñåíû äâà èçìåíåíèÿ. Âî-ïåðâûõ, òèï Integer èçìåí¼í íà òèï Int, ÷òî ñâÿçàíî ñ íåîáõîäèìîñòüþ îãðàíè÷åíèÿ (òèï Integer ïðåäñòàâëÿåò íåîãðàíè÷åííûå öåëûå ÷èñëà, òèï Int îãðàíè÷åííûå èíòåðâàëîì [−229 ; 229 − 1]) äëÿ îïòèìèçàöèè âû÷èñëåíèé. Âî-âòîðûõ, òåïåðü ôóíêöèÿ convert ïðèíèìàåò äâà ïàðàìåòðà ïåðâûì ïàðàìåòðîì îíà ïðèíèìàåò çíà÷åíèå îñíîâàíèÿ, â ñèñòåìó ñ÷èñëåíèÿ ïî êîòîðîìó íåîáõîäèìî ïðåîáðàçîâàòü âòîðîé ïàðàìåòð. Êàê âèäíî, îïðåäåëåíèå ôóíêöèè ñòàëî íå íàìíîãî ñëîæíåå. Íó è â-òðåòüèõ, â ïåðâîì êëîçå îïðåäåëåíèÿ íà ìåñòå ïåðâîãî ïàðàìåòðà ñòîèò òàê íàçûâàåìàÿ (_), êîòîðàÿ îáîçíà÷àåò, ÷òî äàííûé ïàðàìåòð íå èñïîëüçóåòñÿ â òåëå ôóíêöèè. Ñîîòâåòñòâåííî, ôóíêöèÿ digit, âîçâðàùàþùàÿ öèôðó â çàäàííîì îñíîâàíèè, òåïåðü òîæå äîëæíà ïîëó÷àòü è ñàìî îñíîâàíèå. Íî å¼ âèä, â îòëè÷èå îò ôóíêöèè hexDigit, êîòîðàÿ ÿâëÿëàñü ïðîñòåéøèì îòîáðàæåíèåì ïåðâûõ øåñòíàäöàòè ÷èñåë íà ñîîòâåòñòâóþùèå ñèìâîëû øåñòíàäöàòåðè÷íîé ñèñòåìû ñ÷èñëåíèÿ, òåïåðü äîëæåí ñòàòü ñîâåðøåííî èíûì. Íàïðèìåð, âîò òàêèì:
ìàñêà ïîäñòàíîâêè
digit r i | r < 37
= i f ( i < 10)
then show i el s e [ ( toEnum ( i + 5 5 ) ) : : Char ]
| otherwise = " ( " ++ ( show i ) ++ " ) " Çäåñü, â îïðåäåëåíèè ôóíêöèè digit, èìåþòñÿ íåñêîëüêî èíòåðåñíûõ îñîáåííîñòåé ÿçûêà Haskell. Âî-ïåðâûõ, âìåñòî ìåõàíèçìà ñîïîñòàâëåíèÿ ñ îáðàçöàìè îïðåäåëåíèå ïðîèçâåäåíî ÷åðåç ìåõàíèçì (îõðàííûõ âûðàæåíèé), êîòîðûå òàêæå ïîçâîëÿþò ñðàâíèâàòü âõîäíûå ïàðàìåòðû ñ íåêîòîðûìè çíà÷åíèÿìè è îñóùåñòâëÿòü âåòâëåíèå âû÷èñëåíèé. Âòîðàÿ îñîáåííîñòü èñïîëüçîâàíèå âûðàæåíèÿ if -then-else äëÿ òåõ æå ñàìûõ öåëåé â ïåðâîì âàðèàíòå. Îñîáîé ðàçíèöû ìåæäó ýòèìè ïîäõîäàìè íåò, âäóì÷èâîìó ÷èòàòåëþ ïðåäëàãàåòñÿ ïîýêñïåðèìåíòèðîâàòü ñ îõðàííûìè è óñëîâíûìè âûðàæåíèÿìè (ïîäðîáíîñòè ñèíòàêñèñà â ñïåöèàëèçèðîâàííîé ëèòåðàòóðå, ðåêîìåíäóåòñÿ èñïîëüçîâàòü ñïðàâî÷íèê [7]). Ôóíêöèè show è toEnum îïÿòü æå îïèñàíû â ñòàíäàðòíîì ìîäóëå Prelude, êîòîðûé ïîäãðóæàåòñÿ â òðàíñëÿòîð âñåãäà. Ïåðâàÿ ôóíêöèÿ ïðåîáðàçóåò ëþáîå çíà÷åíèå â ñòðîêó (å¼ òèï a −> String), âòîðàÿ ïðåîáðàçóåò öåëîå ÷èñëî â çàäàííûé òèï (å¼ òèï Int −> a, ïðè÷¼ì êîíêðåòíî â äàííîì ñëó÷àå îíà ïðåîáðàçóåò öåëîå â êîä ñèìâîëà Char). Òàêèì îáðàçîì, àëãîðèòì ðàáîòû ôóíêöèè digit ïðîñò: åñëè îñíîâàíèå ñèñòåìû ñ÷èñëåíèÿ ìåíüøå 37 (ýòî ÷èñëî ïåðâîå ÷èñëî, êîòîðîå íà åäèíèöó áîëüøå ñóììû êîëè÷åñòâà äåñÿòåðè÷íûõ öèôð è áóêâ ëàòèíñêîãî àëôàâèòà), òî ðåçóëüòèðóþùàÿ ñòðîêà ñîáèðàåòñÿ èç ñèìâîëîâ öèôð è ëàòèíñêèõ áóêâ. Åñëè æå îñíîâàíèå áîëüøå èëè ðàâíî 37, òî êàæäàÿ öèôðà â òàêèõ ñèñòåìàõ ñ÷èñëåíèÿ çàïèñûâàåòñÿ êàê ñîîòâåòñòâóþùåå ÷èñëî â äåñÿòåðè÷íîé ñèñòåìå, âçÿòîå â êðóãëûå ñêîáêè.
îõðàíû
20
Ôóíêöèîíàëüíûé ïîäõîä â ïðîãðàììèðîâàíèè
Òåïåðü ìîæíî îïðåäåëèòü íåñêîëüêî äîïîëíèòåëüíûõ ôóíêöèé, êîòîðûå íàèáîëåå ÷àñòî ìîãóò èñïîëüçîâàòüñÿ íà ïðàêòèêå:
int2bin = convert 2 int2oct = convert 8 int2hex = convert 16
÷àñòè÷íûì ïðèìåíåíèåì
Âîò çäåñü è ïðèìåíÿåòñÿ ïîäõîä, êîòîðûé íàçûâàåòñÿ .  äàííûõ îïðåäåëåíèÿõ ïðîèçâîäèòñÿ ÷àñòè÷íûé âûçîâ óæå îïðåäåë¼ííîé ðàíåå ôóíêöèè convert, êîòîðàÿ, êàê âèäíî, îæèäàåò íà âõîä äâà ïàðàìåòðà. Íî çäåñü åé íà âõîä ïåðåäà¼òñÿ âñåãî îäèí ïàðàìåòð, â ðåçóëüòàòå ÷åãî ïîëó÷àþòñÿ íîâûå ôóíêöèè, îæèäàþùèå íà âõîä îäèí ïàðàìåòð. Ýòîò ïîäõîä ïðîùå âñåãî ïîíÿòü, ïðåäñòàâèâ, ÷òî ïåðâûé ïàðàìåòð ôóíêöèè convert ïðîñòî ïîäñòàâëåí âî âñå ìåñòà, ãäå îí âñòðå÷àåòñÿ â òåëå ôóíêöèè. Òàê ÷àñòè÷íàÿ ïîäñòàíîâêà convert 2 ïðåâðàùàåò îïðåäåëåíèå â:
convert : : Int −> Int −> String convert 2 0 = "" convert 2 i = convert 2 ( i ` div ` 2 ) ++ digit 2 ( i ` mod ` 2 ) Ïîñêîëüêó äàííîå îïðåäåëåíèå ìîæíî ëåãêî ïðåîáðàçîâàòü â ôóíêöèþ îäíîãî ïàðàìåòðà (ïåðâûé æå òåïåðü çàôèêñèðîâàí è ÿâëÿåòñÿ êîíñòàíòîé), ñîâðåìåííûå òðàíñëÿòîðû ÿçûêà Haskell ïðîâîäÿò èìåííî òàêóþ îïòèìèçàöèþ, ñîçäàâàÿ äîïîëíèòåëüíîå îïðåäåëåíèå íîâîé ôóíêöèè äëÿ ÷àñòè÷íûõ ïðèìåíåíèé. Îñòàëîñü íåìíîãî îïòèìèçèðîâàòü îïðåäåëåíèå ôóíêöèè convert, ÷òîáû èçó÷èòü íåêîòîðûå ýëåìåíòû ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ, ñâÿçàííûå ñ îïòèìèçàöèåé, óëó÷øåíèåì âíåøíåãî âèäà èñõîäíîãî êîäà è ò. ä. Âîò íîâîå îïðåäåëåíèå ôóíêöèè ïðåîáðàçîâàíèÿ ÷èñëà:
convert ' : : Int −> Int −> String convert ' r i = convert_a r i ""
where
convert_a _ 0 result = result convert_a r i result = convert_a r ( i ` div ` r ) ( digit r ( i ` mod ` r ) ++ result ) Äàííîå îïðåäåëåíèå íåîáõîäèìî ðàçîáðàòü ïîäðîáíî. Ôóíêöèÿ convert' âûïîëíÿåò àáñîëþòíî òî æå âû÷èñëåíèå, ÷òî è ôóíêöèÿ convert, îäíàêî îíî îñíîâàíî íà ïîäõîäå, êîòîðûé íàçûâàåòñÿ ¾ ¿ (èëè ¾àêêóìóëÿòîð¿). Äåëî â òîì, ÷òî â èçíà÷àëüíîì îïðåäåëåíèè ôóíêöèè convert èñïîëüçóåòñÿ ðåêóðñèÿ, êîòîðàÿ â íåêîòîðûõ ñëó÷àÿõ ìîæåò ïðèâîäèòü ê íåîïòèìàëüíûì âû÷èñëèòåëüíûì öåïî÷êàì. Íó è, ñîáñòâåííî, äëÿ íåêîòîðûõ ðåêóðñèâíûõ ôóíêöèé ìîæíî ïðîâåñòè ïðåîáðàçîâàíèå òàê, ÷òî îíè ïðèíèìàþò âèä ¾ ¿, êîòîðàÿ ìîæåò âûïîëíÿòüñÿ â ïîñòîÿííîì îáú¼ìå ïàìÿòè.  ôóíêöèîíàëüíîì ïðîãðàììèðîâàíèè òàêîå ïðåîáðàçîâàíèå äåëàþò ïðè ïîìîùè íàêàïëèâàþùåãî ïàðàìåòðà. Îïðåäåëåíèå íà÷àëüíîé ôóíêöèè çàìåíÿþò íà âûçîâ íîâîé ôóíêöèè ñ íàêàïëèâàþùèì ïàðàìåòðîì, à â äàííîì âûçîâå ïåðåäàþò íà÷àëüíîå çíà÷åíèå ýòîãî ïàðàìåòðà. Äîïîëíèòåëüíàÿ æå ôóíêöèÿ ïðîèçâîäèò âû÷èñëåíèÿ êàê ðàç â íàêàïëèâàþùåì ïàðàìåòðå, äåëàÿ ðåêóðñèâíûé âûçîâ ñàìîé ñåáÿ â êîíöå âñåõ âû÷èñëåíèé (â ýòîì è çàêëþ÷àåòñÿ ñìûñë õâîñòîâîé ðåêóðñèè). Ñîîòâåòñòâåííî, çäåñü âèäíî, ÷òî ëîêàëüíàÿ ôóíêöèÿ convert_a âûçûâàåò ñàìó ñåáÿ â ñàìîì êîíöå âû÷èñëåíèé, à ïðèðàùåíèå öèôð â íîâîé ñèñòåìå ñ÷èñëåíèÿ ïðîèçâîäèòñÿ êàê ðàç â òðåòüåì ïàðàìåòðå, êîòîðûé è ÿâëÿåòñÿ íàêàïëèâàþùèì. Îñîáî íàäî îáðàòèòü âíèìàíèå íà âèä ôóíêöèè convert_a. ż îïðåäåëåíèå çàïèñàíî íåïîñðåäñòâåííî â òåëå ôóíêöèè convert' ïîñëå êëþ÷åâîãî ñëîâà where. Ýòî åù¼ îäèí èç ýëåìåíòîâ ïðîãðàììèðîâàíèÿ, êîòîðûé çàêëþ÷àåòñÿ â ñîçäàíèè ëîêàëüíûõ îïðåäåëåíèé ôóíêöèé, èëè ¾ ¿. Çàìûêàíèå íàõîäèòñÿ â îáëàñòè èì¼í îñíîâíîé ôóíêöèè, ïîýòîìó èç åãî òåëà âèäíû âñå ïàðàìåòðû. Êðîìå òîãî, çàìûêàíèÿ èñïîëüçóþòñÿ äëÿ îïòèìèçàöèè âû÷èñëåíèé åñëè â òåëå îñíîâíîé ôóíêöèè íåñêîëüêî ðàç
íàêàïëèâàþùèé ïàðàìåòð
õâîñòîâîé
ðåêóðñèè
çàìûêàíèé
Çàêëþ÷åíèå
21
âûçâàòü ëîêàëüíóþ ôóíêöèþ ñ îäíèì è òåì æå íàáîðîì ïàðàìåòðîâ, òî ðåçóëüòàò áóäåò âû÷èñëåí îäèí ðàç. Äîïîëíèòåëüíûå ïðè¼ìû ïðîãðàììèðîâàíèÿ, îïèñàíèå êëþ÷åâûõ ñëîâ, à òàêæå îïèñàíèå ìåòîäà ïðåîáðàçîâàíèÿ ôóíêöèè ê õâîñòîâîé ðåêóðñèè ìîæíî äåòàëüíî èçó÷èòü ïðè ïîìîùè êíèãè [7]. Çäåñü æå îñòàëîñü óïîìÿíóòü òî, ÷òî ïîëó÷åííûå ôóíêöèè convert è convert' ìîæíî èñïîëüçîâàòü òàê, êàê ëþáûå èíûå.
Çàêëþ÷åíèå Îáñóæäåíèå ïðåèìóùåñòâ è íåäîñòàòêîâ òåõ èëè èíûõ ïîäõîäîâ ê ïðîãðàììèðîâàíèþ óäåë èäåàëèñòîâ. Âìåñòå ñ òåì çíàíèå îáîèõ ìåòîäîâ îïèñàíèÿ âû÷èñëèòåëüíûõ ïðîöåññîâ ïîçâîëÿåò áîëåå ïîëíîöåííî âçãëÿíóòü íà ïðîåêòèðîâàíèå è ðàçðàáîòêó ïðîãðàììíûõ ñðåäñòâ. Íî, ê ñîæàëåíèþ, â íà÷àëüíûõ ó÷åáíûõ çàâåäåíèÿõ ðåäêî èçó÷àþò îáà ïîäõîäà íà óðîêàõ èíôîðìàòèêè, à ïîòîìó ó íà÷èíàþùèõ ñïåöèàëèñòîâ è èíòåðåñóþùèõñÿ èìååòñÿ èçâåñòíûé ïåðåêîñ â ñòîðîíó ïðîöåäóðíîãî ñòèëÿ. Âìåñòå ñ òåì âëàäåíèå ôóíêöèîíàëüíûì ñòèëåì è åãî îñíîâíûìè ìåòîäèêàìè (äåêîìïîçèöèåé è âûðàæåíèåì åù¼ íåðåø¼ííûõ çàäà÷ ÷åðåç óæå ðåø¼ííûå) ïîçâîëÿåò áîëåå ýôôåêòèâíî ðåøàòü íå òîëüêî ïîâñåäíåâíûå, íî è óïðàâëåí÷åñêèå çàäà÷è, ïîñêîëüêó ýòè ïðè¼ìû òàêæå ïîâñåìåñòíî âñòðå÷àþòñÿ â îáëàñòè ðåãóëèðîâàíèÿ è óïðàâëåíèÿ. Ââèäó âûøåèçëîæåííîãî àâòîð íàäååòñÿ, ÷òî ðàñïðîñòðàíåíèå è ïîïóëÿðèçàöèÿ ïàðàäèãìû ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ ïîçâîëÿò íå òîëüêî âçðàùèâàòü áîëåå ñåðü¼çíûõ è âäóì÷èâûõ ñïåöèàëèñòîâ â îáëàñòè èíôîðìàöèîííûõ è àâòîìàòèçèðîâàííûõ ñèñòåì, íî è ðåøèò íåêîòîðûå ïðîáëåìû ïîäãîòîâêè óïðàâëåí÷åñêèõ êàäðîâ.
Àëãåáðàè÷åñêèå òèïû äàííûõ â ÿçûêå Haskell Ñòàòüÿ áûëà îïóáëèêîâàíà â 12 (24) æóðíàëà ¾Ïîòåíöèàë¿ â äåêàáðå 2006 ãîäà.
Íàñòîÿùåå ýññå ïðîäîëæàåò ñîáîé öèêë, íàïðàâëåííûé íà ïðåäîñòàâëåíèå âñåì æåëàþùèì íåîáõîäèìîãî ìèíèìóìà â îâëàäåíèè ïàðàäèãìîé ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ íà ïðèìåðå ÿçûêà Haskell. Ïðèøëî âðåìÿ áîëåå äåòàëüíî èçó÷èòü òàêîé íåìàëîâàæíûé àñïåêò ïðîãðàììèðîâàíèÿ, êàê ñîçäàíèå ïîëüçîâàòåëüñêèõ òèïîâ äàííûõ, êîòîðûå â ÿçûêå Haskell íîñÿò íàèìåíîâàíèå ¾àëãåáðàè÷åñêèõ òèïîâ äàííûõ¿.
Ââåäåíèå  ïðîöåññå ñîçäàíèÿ ïðîãðàììíîãî îáåñïå÷åíèÿ ïðàêòè÷åñêè âñåãäà âñòà¼ò çàäà÷à ñîçäàíèÿ ñîáñòâåííûõ òèïîâ äàííûõ, òàê êàê îáû÷íî áàçîâûé íàáîð ïåðâè÷íûõ òèïîâ ñëèøêîì óçîê. Çà÷àñòóþ ýòîò íàáîð ñîñòîèò òîëüêî èç òð¼õ èëè ÷åòûð¼õ òèïîâ, îòðàæàþùèõ îñíîâíûå ìíîæåñòâà ÷èñåë â ìàòåìàòèêå, à òàêæå ñèìâîëû, êîòîðûå ìîãóò áûòü âûâåäåíû íà ýêðàí èëè çàïèñàíû â ôàéë. Îäíàêî ñîâðåìåííîå âûñîêîóðîâíåâîå ïðîãðàììèðîâàíèå ïîäðàçóìåâàåò, ÷òî ñàìà ïðîãðàììà äîëæíà îáëàäàòü âûñîêîé ñòåïåíüþ àáñòðàêöèè äàííûõ, ÷òî ïîçâîëèëî áû íå òîëüêî ãðàìîòíî îïèñûâàòü ïðîáëåìíóþ îáëàñòü ðåøàåìîé çàäà÷è, íî è ïîâòîðíî èñïîëüçîâàòü ñîçäàííûå îïðåäåëåíèÿ. Èìåííî ïîýòîìó êàæäûé ðàçâèòûé ÿçûê ïðîãðàììèðîâàíèÿ ïðåäîñòàâëÿåò ïðîãðàììèñòó îáøèðíîå ìíîæåñòâî èíñòðóìåíòîâ äëÿ îïðåäåëåíèÿ íîâûõ òèïîâ. Ïðè ýòîì çà÷àñòóþ ñàìè íîâûå òèïû ìîæíî ñîçäàâàòü êàê íà îñíîâå óæå èìåþùèõñÿ, òàê è íåïîñðåäñòâåííî, ÷òî íàçûâàåòñÿ ¾ñ íóëÿ¿. Íå îáîø¼ë ñòîðîíîé ýòó ïðîáëåìó è ÿçûê Haskell ñîâðåìåííûé ôóíêöèîíàëüíûé ÿçûê ïðîãðàììèðîâàíèÿ.  åãî ÿäðå èìååòñÿ äîñòàòî÷íî ìîùíàÿ è ðàçâèòàÿ ñèñòåìà òèïèçàöèè, êîòîðàÿ ïîçâîëÿåò íå òîëüêî îïðåäåëÿòü òèïû èñïîëüçóåìûõ â ïðîãðàììå îáúåêòîâ àâòîìàòè÷åñêè, íî è ñîçäàâàòü ñîáñòâåííûå òèïû ëþáîé ñëîæíîñòè, â òîì ÷èñëå è ñ èñïîëüçîâàíèåì (ïîíèìàíèå ïàðàìåòðè÷åñêîãî ïîëèìîðôèçìà áóäåò ïðåäëîæåíî â îäíîì èç ñëåäóþùèõ ïîäðàçäåëîâ ýòîãî ðàçäåëà). Ýòèì ÿçûê Haskell îòëè÷àåòñÿ îò ìíîãèõ èìïåðàòèâíûõ ÿçûêîâ ïðîãðàììèðîâàíèÿ, â êîòîðûõ ïîëèìîðôèçì â ëó÷øåì ñëó÷àå ïðåäñòàâëåí îáû÷íîé ïåðåãðóçêîé èì¼í îáúåêòîâ (îáû÷íî íàèìåíîâàíèé ôóíêöèé èëè ïðîöåäóð). Âñå îïðåäåëåíèÿ, ïðèâåä¼ííûå â äàííîì ðàçäåëå, ìîæíî íåïîñðåäñòâåííî ïðîâåðèòü â èíòåðïðåòàòîðå ÿçûêà Haskell HUGS 98, êîòîðûé ìîæíî áåñïëàòíî ïîëó÷èòü íà îôèöèàëüíîì ñàéòå èçó÷àåìîãî ÿçûêà â ñåòè Èíòåðíåò http://www.haskell.org/hugs/. Âñå ïðåäñòàâëåííûå îïðåäåëåíèÿ ïðîòåñòèðîâàíû â ýòîì èíòåðïðåòàòîðå, ïîýòîìó èõ ïðàâèëüíîñòü ãàðàíòèðóåòñÿ. Èñïîëüçîâàíèå äðóãèõ òðàíñëÿòîðîâ ÿçûêà Haskell (íàïðèìåð, êîìïèëÿòîðîâ GHC èëè NHC) òàêæå âîçìîæíî, îäíàêî äëÿ èõ èñïîëüçîâàíèÿ, âîçìîæíî, ïðèä¼òñÿ âíîñèòü â îïðåäåëåíèÿ ôóíêöèé è òèïîâ íåçíà÷èòåëüíûå èçìåíåíèÿ. Äëÿ ïîíèìàíèÿ ìàòåðèàëà, èçëîæåííîãî â ðàçäåëå, íåîáõîäèìî îáëàäàòü áàçîâûìè ïîçíàíèÿìè â èíôîðìàòèêå, ïîíèìàòü, ÷òî òàêîå òèïû äàííûõ, à òàêæå çíàòü îñíîâíîé ñèíòàêñèñ ÿçûêà Haskell.
ïàðàìåòðè÷åñêîãî ïîëèìîðôèçìà
Ïðîñòûå ïåðå÷èñëåíèÿ
23
Äëÿ èçó÷åíèÿ ïîñëåäíåãî ìîæíî âîñïîëüçîâàòüñÿ ñîâðåìåííûìè êíèãàìè è ñïðàâî÷íèêàìè íà ýòó òåìó, íàïðèìåð [6, 7, 14].
Ïðîñòûå ïåðå÷èñëåíèÿ Äëÿ îïðåäåëåíèÿ ïîëüçîâàòåëüñêèõ òèïîâ äàííûõ â ÿçûêå Haskell èñïîëüçóåòñÿ ñëóæåáíîå ñëîâî data, êîòîðîå äîëæíî ñòîÿòü íà ñàìîì âåðõíåì óðîâíå îïðåäåëåíèé â ìîäóëå. Ýòî ñëóæåáíîå ñëîâî îïðåäåëÿåò òàê íàçûâàåìûé ¾ ¿, âûäåëÿÿ äëÿ íåãî îïðåäåë¼ííîå íàèìåíîâàíèå, à òàêæå íàáîð âîçìîæíûõ êîíñòðóêòîðîâ, òî åñòü ôóíêöèé, êîòîðûå âîçâðàùàþò îáúåêò îïðåäåëÿåìîãî òèïà. Âñå âîçìîæíûå êîíñòðóêòîðû äîëæíû áûòü ðàçäåëåíû ñèìâîëîì (|) ¾âåðòèêàëüíàÿ ÷åðòà¿.  êàæäîì àëãåáðàè÷åñêîì òèïå äàííûõ äîëæåí áûòü ïî êðàéíåé ìåðå îäèí êîíñòðóêòîð. Íàïðèìåð, ïðè ïîìîùè àëãåáðàè÷åñêîãî òèïà äàííûõ â ñòàíäàðòíîì ìîäóëå Prelude îïðåäåë¼í òèï äëÿ ïðåäñòàâëåíèÿ áóëåâñêèõ çíà÷åíèé èñòèííîñòè (ìîæíî îòìåòèòü, ÷òî âî ìíîãèõ ÿçûêàõ ïðîãðàììèðîâàíèÿ áóëåâñêèé òèï ÿâëÿåòñÿ îäíèì èç ïðèìèòèâíûõ òèïîâ, ïðåäîñòàâëÿåìûõ ñàìèì ÿçûêîì, íàïðèìåð, â ÿçûêå Pascal ýòî òèï Boolean, à â ÿçûêàõ C, C++ è ìíîãèõ èì ïîäîáíûõ òèï bool). Ýòî ñäåëàíî òàê:
àëãåáðàè÷åñêèé òèï äàííûõ
data Bool = True | False Íàäî îñîáî îòìåòèòü, ÷òî ïî ñîãëàøåíèþ î íàèìåíîâàíèè îáúåêòîâ â ÿçûêå Haskell âñå íàèìåíîâàíèÿ òèïîâ, à òàêæå èõ êîíñòðóêòîðû äîëæíû íà÷èíàòüñÿ ñ çàãëàâíîé áóêâû. Ýòî ìîæíî âèäåòü â ïðåäñòàâëåííîì îïðåäåëåíèè. Òàêîå ñîãëàøåíèå â òîì ÷èñëå ïîìîãàåò ÷¼òêî ðàçäåëÿòü âñòðå÷àþùèåñÿ â èñõîäíîì êîäå îáúåêòû ïåðâàÿ áóêâà èäåíòèôèêàòîðà ñâèäåòåëüñòâóåò î ðîäå îáúåêòà. Ìîæíî âèäåòü, ÷òî ïðåäñòàâëåííîå îïðåäåëåíèå áóëåâñêîãî òèïà â ÿçûêå Haskell ïîëíîñòüþ ñîâïàäàåò ñ ìàòåìàòè÷åñêèì îïðåäåëåíèåì ýòîãî òèïà, à èìåííî:
B = ⟨true, f alse⟩. Çäåñü ìîæíî äîïîëíèòåëüíî óáåäèòüñÿ â íåîáû÷àéíîé âûðàçèòåëüíîñòè ÿçûêà Haskell åãî ñîçäàòåëè, êàê îáû÷íî, ñòðåìèëèñü ñäåëàòü åãî ñèíòàêñèñ íàèáîëåå ïðèáëèæåííûì ê ìàòåìàòè÷åñêîé íîòàöèè. Ïðåäñòàâëåííîå îïðåäåëåíèå ÿâëÿåò ñîáîé òàê íàçûâàåìîå , òî åñòü ïðèìåðíî òî æå ñàìîå, ÷òî â ÿçûêàõ C è C++ ââîäèòñÿ êëþ÷åâûì ñëîâîì enum. Ïðîñòîå ïåðå÷èñëåíèå ïðåäñòàâëÿåò ñîáîé íåóïîðÿäî÷åííûé íàáîð íàèìåíîâàíèé îáúåêòîâ, ïðèíàäëåæàùèõ îïðåäåë¼ííîìó ìíîæåñòâó, ñîñòàâëÿþùåìó îïèñûâàåìûé òèï. Äðóãèìè ñëîâàìè, êàæäîå ïðîñòîå ïåðå÷èñëåíèå îïðåäåëÿåò îäèí èëè áîëåå íàèìåíîâàíèé îáúåêòîâ, êîòîðûå ìîãóò ïðèíàäëåæàòü òèïó. Ïðè ýòîì íàäî îòìåòèòü, ÷òî îäíî èç òàêèõ íàèìåíîâàíèé ìîæåò ñîâïàäàòü ñ íàèìåíîâàíèåì òèïà (îíè íàõîäÿòñÿ â ðàçíûõ ïðîñòðàíñòâàõ èì¼í). Äðóãèì ïðèìåðîì, êîòîðûé î÷åíü ÷¼òêî äà¼ò ïðåäñòàâëåíèå î òîì, ÷òî òàêîå ïðîñòîå ïåðå÷èñëåíèå, ÿâëÿåòñÿ îïèñàíèå òèïà äëÿ ïðåäñòàâëåíèÿ ðàçëè÷íûõ öâåòîâ. Ïðè ýòîì êàæäûé öâåò ìîæíî îïèñàòü åãî íàçâàíèåì íà åñòåñòâåííîì ÿçûêå (â äàííîì ñëó÷àå íà àíãëèéñêîì, òàê êàê ñèíòàêñèñ ÿçûêà Haskell ïîêà íå ðàçðåøàåò èñïîëüçîâàíèå ñèìâîëîâ ñ êîäîì âûøå 127). Ýòî ìîæíî ñäåëàòü ïðèìåðíî òàê (åñòåñòâåííî, íàäî ïðèíèìàòü âî âíèìàíèå, ÷òî ïîäîáíûì îáðàçîì ìîæíî îïèñàòü ëþáûå íàáîðû öâåòîâ, êîòîðûå áóäóò îòëè÷àòüñÿ äðóã îò äðóãà êàê êîëè÷åñòâîì, òàê è íàèìåíîâàíèåì êîíêðåòíûõ ýëåìåíòîâ):
ïðîñòîå ïåðå÷èñëåíèå
data Color = Black | | | | |
Blue Brown Cyan Gray Green
−− −− −− −− −− −−
×¼ðíûé Ñèíèé Êîðè÷íåâûé Ãîëóáîé Ñåðûé Çåë¼íûé
24
Àëãåáðàè÷åñêèå òèïû äàííûõ â ÿçûêå Haskell | | | | |
Magenta Orange Red White Yellow
−− −− −− −− −−
Ðîçîâûé Îðàíæåâûé Êðàñíûé Áåëûé Ƽëòûé
Âñ¼, ÷òî ñòîèò ïîñëå äâóõ ñèìâîëîâ ¾äåôèñ¿ (--), ÿâëÿåòñÿ êîììåíòàðèåì, êîòîðûé äëèòñÿ äî êîíöà ñòðîêè. Òàêæå íàäî îòìåòèòü, ÷òî â ÿçûêå Haskell âî ìíîãèõ ìåñòàõ äåéñòâóåò ïðàâèëî äâóìåðíîãî ñèíòàêñèñà, êîãäà îïðåäåëåíèÿ îáúåêòîâ ìîæíî ðàñïîëàãàòü íà íåñêîëüêèõ ñòðî÷êàõ êîäà, âûðàâíèâàÿ èõ ïî îäíîé êîëîíêå. Çäåñü âèäåí èìåííî òàêîé ñïîñîá çàïèñè, õîòÿ ýòî è íå îáÿçàòåëüíî, òàê êàê ìîæíî çàïèñûâàòü âñ¼ â îäíó ñòðîêó (òîãäà, åñòåñòâåííî, êîììåíòàðèè òàê ñòàâèòü íåëüçÿ). Ïðè ïîìîùè ïðîñòûõ ïåðå÷èñëåíèé ìîæíî ëåãêî ïîÿñíèòü, ÷òî òàêîå . Ìîæíî âåðíóòüñÿ ê îïðåäåëåíèþ áóëåâñêîãî òèïà è ðàññìîòðåòü ðàçëè÷íûå îïåðàöèè íàä îáúåêòàìè ýòîãî òèïà. Èç ôîðìàëüíîé íàóêè èçâåñòíî ìíîæåñòâî òàêèõ îïåðàöèé îòðèöàíèå, êîíúþíêöèÿ, äèçúþíêöèÿ, èñêëþ÷àþùåå ¾èëè¿, ýêâèâàëåíòíîñòü, èìïëèêàöèÿ è ìíîãèå äðóãèå. Âîò, ê ïðèìåðó, îïðåäåëåíèå ôóíêöèè äëÿ âû÷èñëåíèÿ îòðèöàíèÿ:
ñîïîñòàâëåíèå ñ îáðàçöîì
not : : Bool −> Bool not True = False not False = True  ýòîì îïðåäåëåíèè, ñîñòîÿùåì èç òð¼õ ñòðîê, ïåðâàÿ ñòðîêà ïðåäñòàâëÿåò ñîáîé îãðàíè÷åíèå, íàêëàäûâàåìîå íà òèï ôóíêöèè not (èíà÷å íàçûâàåìîå ). Ýòà çàïèñü ãîâîðèò èíòåðïðåòàòîðó, ÷òî ôóíêöèÿ not ïðèíèìàåò íà âõîä îäèí àðãóìåíò òèïà Bool è âîçâðàùàåò çíà÷åíèå ýòîãî æå òèïà. Âòîðàÿ ñòðîêà îïðåäåëÿåò ðåçóëüòàò ôóíêöèè not, åñëè åé íà âõîä ïîäàíî çíà÷åíèå True, à òðåòüÿ äëÿ çíà÷åíèÿ False ñîîòâåòñòâåííî. Îáðàçöû ïðåäñòàâëÿþò ñîáîé íàáîðû âõîäíûõ çíà÷åíèé â îïðåäåëåíèÿõ ôóíêöèé, ñ êîòîðûìè ñðàâíèâàþòñÿ ôàêòè÷åñêèå ïàðàìåòðû, ïîäàííûå íà âõîä ôóíêöèé. Íàáîðû îáðàçöîâ â èäåàëüíîì ñëó÷àå äîëæíû ïîêðûâàòü âñ¼ ìíîæåñòâî âîçìîæíûõ âõîäíûõ ïàðàìåòðîâ. Ñîïîñòàâëåíèå ñ îáðàçöîì, òî åñòü âûáîð êîíêðåòíîé ñòðîêè íàáîðà îïðåäåëåíèé, ïðîèñõîäèò ïðîñòî èíòåðïðåòàòîð äâèæåòñÿ ñâåðõó âíèç ïî îïðåäåëåíèÿì è ïûòàåòñÿ ñîïîñòàâèòü ôàêòè÷åñêèé âõîäíîé ïàðàìåòð ñ òåì, ÷òî ïðåäñòàâëåí â îáðàçöå. Êàê òîëüêî òàêîå ñîïîñòàâëåíèå ïðîèñõîäèò óñïåøíî, âûáèðàåòñÿ ýòà ñòðîêà è âû÷èñëÿåòñÿ ðåçóëüòàò. Òàê, â ïðèâåä¼ííîì âûøå îïðåäåëåíèè âòîðàÿ ñòðîêà âûáèðàåòñÿ â ñëó÷àå, åñëè íà âõîä ôóíêöèè not ïîäàíî çíà÷åíèå True è ò. ä. Åñòåñòâåííî, ÷òî îáðàçöû ìîãóò áûòü íàìíîãî ñëîæíåå, èáî äëÿ áåñêîíå÷íûõ ìíîæåñòâ (òèïîâ) ñëîæíî ïåðå÷èñëèòü âñå âîçìîæíûå âàðèàíòû çíà÷åíèé. Ïîýòîìó ÷àñòî èñïîëüçóåòñÿ òàê íàçûâàåìàÿ ìàñêà ïîäñòàíîâêè, îáîçíà÷àåìàÿ ñèìâîëîì (_) ¾ïîä÷¼ðêèâàíèå¿. Ýòîò ñèìâîë îáîçíà÷àåò ëþáîå çíà÷åíèå ëþáîãî òèïà. Íàïðèìåð, ïðè ïîìîùè íåãî ìîæíî îïðåäåëèòü îïåðàöèþ êîíúþíêöèè íà áóëåâñêèõ çíà÷åíèÿõ:
ñèãíàòóðîé
(&&) : : Bool −> Bool −> Bool True && True = True _ && _ = False  äàííîì îïðåäåëåíèè ïîêàçàíî, ÷òî çíà÷åíèå êîíúþíêöèè ðàâíî True òîëüêî â ñëó÷àå, åñëè îáà âõîäíûõ àðãóìåíòà ðàâíû True, à â ïðîòèâíîì ñëó÷àå (è ýòî óæå íå âàæíî, êàêèå êîíêðåòíî òàì çíà÷åíèÿ â êàêèõ êîìáèíàöèÿõ) çíà÷åíèåì êîíúþíêöèè áóäåò False. Ïðèìåðíî òàêîå æå îïðåäåëåíèå ìîæíî ïðèâåñòè è äëÿ äèçúþíêöèè: ( | | ) : : Bool −> Bool −> Bool False | | False = False _ || _ = True
Ïàðàìåòðèçàöèÿ
25
Êàê âèäíî, âñ¼ äîâîëüíî ïðîñòî. ×èòàòåëþ ïðåäëàãàåòñÿ ñàìîñòîÿòåëüíî ðàçðàáîòàòü ôóíêöèè äëÿ âû÷èñëåíèÿ èñêëþ÷àþùåãî ¾èëè¿ (íàèìåíîâàíèå (|+|)), ýêâèâàëåíòíîñòè (íàèìåíîâàíèå (===)) è èìïëèêàöèè (íàèìåíîâàíèå (==>)). Îïðåäåëåíèÿ ýòèõ ôóíêöèé ìîæíî âûðàçèòü êàê ïðè ïîìîùè óæå èìåþùèõñÿ, òàê è ñîçäàòü íà îñíîâå ìåõàíèçìà ñîïîñòàâëåíèÿ ñ îáðàçöîì (÷òî áîëåå ïðåäïî÷òèòåëüíî ââèäó âîçìîæíîñòè äîïîëíèòåëüíîãî çàêðåïëåíèÿ ïðîéäåííîãî ìàòåðèàëà). Îñòà¼òñÿ ïðåäëîæèòü âäóì÷èâîìó ÷èòàòåëþ äëÿ èçó÷åíèÿ åù¼ îäèí òèï äàííûõ, ïðåäñòàâëÿþùèé ñîáîé îòîáðàæåíèå çíà÷åíèé . Ýòà ëîãèêà èñïîëüçóåòñÿ â òåõ ñëó÷àÿõ, êîãäà çíà÷åíèåì èñòèííîñòè ìîãóò âûñòóïàòü íå òîëüêî ïîëíîñòüþ îïðåäåë¼ííûå çíà÷åíèÿ ¾ÈÑÒÈÍÀ¿ è ¾ËÎÆÜ¿, íî è òðåòüå çíà÷åíèå ¾ÍÅ ÎÏÐÅÄÅËÅÍο. Îïðåäåëåíèå ýòîãî òèïà ìîæåò âûãëÿäåòü òàê:
òðîè÷íîé ëîãèêè
data Ternary = TTrue | TUndefined | TFalse  êîíñòðóêòîðàõ ýòîãî òèïà ïåðâîé ïîñòàâëåí ñèìâîë T â öåëÿõ èñêëþ÷åíèÿ êîíôëèêòà ñ êîíñòðóêòîðàìè òèïà Bool. Îïÿòü æå ÷èòàòåëþ ïðåäëàãàåòñÿ ñàìîñòîÿòåëüíî ñîçäàòü îïåðàöèè äëÿ ðàáîòû ñ ýòèì òèïîì äàííûõ. Ïðè íåîáõîäèìîñòè íàäî îáðàòèòüñÿ ê äîïîëíèòåëüíûì èñòî÷íèêàì äëÿ ïîíèìàíèÿ òîãî, êàê ðàáîòàåò òðîè÷íàÿ ëîãèêà (íàïðèìåð, êíèãè [10, 12] äàþò îòëè÷íîå ïîíèìàíèå òðîè÷íîé è äðóãèõ ìíîãîçíà÷íûõ ëîãèê).
Ïàðàìåòðèçàöèÿ Îäíàêî áûëî áû ñòðàííûì ïîëàãàòü, ÷òî âñå âîçìîæíîñòè ÿçûêà Haskell äëÿ îïðåäåëåíèÿ òèïîâ îãðàíè÷èâàëèñü áû ïðîñòûìè ïåðå÷èñëåíèÿìè. Êîíå÷íî, îíè ïðåäîñòàâëÿþò ïðîãðàììèñòó õîðîøèé èíñòðóìåíò äëÿ ðàáîòû, íî â ïðèðîäå ñóùåñòâóþò áîëåå ñëîæíûå îáúåêòû, ÷åì ïåðå÷èñëèìûå ìíîæåñòâà. Íàïðèìåð, äëÿ ïðåäñòàâëåíèÿ òî÷åê íà äâóìåðíîé ïëîñêîñòè èñïîëüçóþòñÿ äâå êîîðäèíàòû, ïðåäñòàâëÿþùèå ñîáîé äåéñòâèòåëüíûå ÷èñëà, à â òð¼õìåðíîì ïðîñòðàíñòâå ñîîòâåòñòâåííî òðè äåéñòâèòåëüíûõ ÷èñëà. Äëÿ ðåøåíèÿ ýòîé è ìíîãèõ äðóãèõ ïîäîáíûõ çàäà÷ èìååòñÿ âîçìîæíîñòü àëãåáðàè÷åñêèõ òèïîâ äàííûõ. Òàêàÿ ïàðàìåòðèçàöèÿ äåëàåòñÿ ïðè ïîìîùè ïåðå÷èñëåíèÿ ïîñëå èì¼í êîíñòðóêòîðîâ òèïà äîïîëíèòåëüíûõ òèïîâ, îò êîòîðûõ çàâèñèò îïðåäåëÿåìûé òèï. Íàïðèìåð, äëÿ ïðåäñòàâëåíèÿ äâóìåðíûõ êîîðäèíàò ìîæíî èñïîëüçîâàòü òàêîå îïðåäåëåíèå:
ïàðàìåòðèçàöèè
data Point2D = Point2D Float Float Ýòî îïðåäåëåíèå îáîçíà÷àåò, ÷òî äëÿ ïîëó÷åíèÿ îáúåêòà òèïà Point2D â åãî êîíñòðóêòîð, êîòîðûé íàçûâàåòñÿ òàêæå, íåîáõîäèìî ïåðåäàòü â êà÷åñòâå ïàðàìåòðîâ äâà äåéñòâèòåëüíûõ ÷èñëà (òèï Float, ïðåäñòàâëÿþùèé äåéñòâèòåëüíûå ÷èñëà îäèíàðíîé òî÷íîñòè, ÿâëÿåòñÿ âñòðîåííûì ïðèìèòèâíûì òèïîì â ÿçûêå Haskell). Òî÷íî òàê æå ìîæíî îïðåäåëèòü è òèï äàííûõ äëÿ ïðåäñòàâëåíèÿ òð¼õìåðíûõ òî÷åê:
data Point3D = Point3D Float Float Float Âïîëíå åñòåñòâåííî, ÷òî ìåõàíèçì ñîïîñòàâëåíèÿ ñ îáðàçöàìè â äàííîì ñëó÷àå ðàáîòàåò àáñîëþòíî òàê æå, êàê è â ñëó÷àå ïðîñòûõ ïåðå÷èñëåíèé.  êà÷åñòâå îáðàçöîâ íåîáõîäèìî óêàçûâàòü êîíñòðóêòîðû àëãåáðàè÷åñêèõ òèïîâ äàííûõ è ìíîæåñòâî âîçìîæíûõ çíà÷åíèé, êîòîðûìè ïàðàìåòðèçóåòñÿ ýòîò òèï. Íàïðèìåð, ôóíêöèÿ äëÿ ñäâèãà òî÷êè â äâóìåðíîì ïðîñòðàíñòâå íà îïðåäåë¼ííîå ñìåùåíèå ïî îáåèì îñÿì êîîðäèíàò ìîæåò áûòü îïðåäåëåíà òàê:
shift2D : : Point2D −> Float −> Float −> Point2D shift2D ( Point2D x y ) dx dy = Point2D ( x + dx ) ( y + dy ) Òî÷íî òàê æå ìîæåò áûòü îïðåäåëåíà ôóíêöèÿ è äëÿ ñäâèãà â òð¼õìåðíîì ïðîñòðàíñòâå, îäíàêî â ýòîì ñëó÷àå áóäóò äâå ïðàêòè÷åñêè îäèíàêîâûå ôóíêöèè. Íè÷òî íå ìåøàåò îïðåäåëèòü åäèíñòâåííûé
26
Àëãåáðàè÷åñêèå òèïû äàííûõ â ÿçûêå Haskell
òèï äëÿ ïðåäñòàâëåíèÿ òî÷åê êàê íà ïëîñêîñòè, òàê è â òð¼õìåðíîì ïðîñòðàíñòâå. Ýòî ìîæíî ñäåëàòü, îáúåäèíèâ äâà âûøåïðèâåä¼ííûõ îïðåäåëåíèÿ:
data Point = Point2D Float Float | Point3D Float Float Float Òîãäà äëÿ ïîäîáíîãî òèïà äàííûõ îïðåäåëåíèå ôóíêöèè äëÿ ñäâèãà òî÷êè áóäåò âûãëÿäåòü òàê:
shift : : Point shift ( Point2D ( Point2D shift ( Point3D ( Point3D
−> Point −> Point x y) dx dy ) = Point2D ( x + dx ) ( y + dy ) x y z) dx dy dz ) = Point3D ( x + dx ) ( y + dy ) ( z + dz )
Îäíàêî ïðåäñòàâëåííîå îïðåäåëåíèå òèïà íå òàê êðàñèâî, êàê êàæåòñÿ íà ïåðâûé âçãëÿä. Îíî íå óíèâåðñàëüíî, à îãðàíè÷èâàåòñÿ òîëüêî òî÷êàìè íà ïëîñêîñòè è â òð¼õìåðíîì ïðîñòðàíñòâå. ×òî äåëàòü, åñëè âäðóã ïîíàäîáèòñÿ ðåøèòü êàêóþ-ëèáî çàäà÷ó â ÷åòûð¼õìåðíîì ïðîñòðàíñòâå? À â n-ìåðíîì?  ñàìîì äåëå, íå ïåðå÷èñëÿòü æå â ñïèñêå êîíñòðóêòîðîâ âñå âîçìîæíûå ðàçìåðíîñòè.  ýòîì ñëó÷àå íà ïîìîùü ïðèõîäèò ñïèñîê, ÷üÿ äëèíà çàðàíåå íå îïðåäåëåíà. Ïîýòîìó ñàì òèï äëÿ ïðåäñòàâëåíèÿ òî÷åê ìîæíî îïðåäåëèòü òàê:
data Point = Point [ Float ] Òàêîå îïðåäåëåíèå îáîçíà÷àåò, ÷òî òèï Point ïàðàìåòðèçóåòñÿ ñïèñêîì äåéñòâèòåëüíûõ ÷èñåë, à äëèíà ñïèñêà îïðåäåëÿåò ðàçìåðíîñòü îïèñûâàåìîãî ýòèì òèïîì ïðîñòðàíñòâà.  ýòîì ðåøåíèè, îäíàêî, îñòà¼òñÿ îäíà âîçìîæíîñòü äëÿ ìíîæåñòâà ëîãè÷åñêèõ îøèáîê, êîòîðûå ìîãóò ïðîêðàñòüñÿ â ïðîãðàììó, ó ñïèñêîâ íåò çàðàíåå óêàçàííîé äëèíû, ïîýòîìó â ôóíêöèÿõ, êîòîðûå áóäóò ðàáîòàòü ñ òàêèìè òî÷êàìè, íåîáõîäèìî î÷åíü âíèìàòåëüíî ñëåäèòü çà òåì, ÷òîáû ðàçìåðíîñòè òî÷åê ñîâïàäàëè. Ýòî ìîæíî ñäåëàòü, ëèáî ñðàâíèâàÿ äëèíû ïîëó÷àåìûõ íà âõîäå ñïèñêîâ êîîðäèíàò è âûäàâàÿ ñîîáùåíèå îá îøèáêå ïðè èõ íåñîâïàäåíèè, ëèáî âûáèðàÿ ìèíèìàëüíóþ äëèíó è îòñåêàÿ âñå êîîðäèíàòû, ëåæàùèå äàëåå òàêîé ìèíèìàëüíîé äëèíû. Ïî ýòîìó ïóòè ðåøåíî ïîéòè ïðè ñîçäàíèè íîâîãî îïðåäåëåíèÿ ôóíêöèè shift:
shift shift shift shift
: : Point −> Point −> Point ( Point [ ] ) _ = Point [ ] _ ( Point [ ] ) = Point [ ] ( Point ( x : xs ) ) ( Point ( dx : dxs ) ) = Point ( ( x + dx ) : others )
where
Point others = shift ( Point xs ) ( Point dxs ) Ýòî îïðåäåëåíèå óæå íå òàê î÷åâèäíî è âûðàçèòåëüíî, îäíàêî ðàáîòàåò íà òî÷êàõ ëþáîé ðàçìåðíîñòè, äàæå íóëåâîé (ìîæíî ïîïðîáîâàòü îñóùåñòâèòü âûçîâ shift (Point []) (Point []) â ðåçóëüòàòå áóäåò âûäàí ðåçóëüòàò Point []). Âïîëíå åñòåñòâåííî, ÷òî íè÷òî íå îãðàíè÷èâàåò ïðîãðàììèñòà èñïîëüçîâàòü â îäíîì îïðåäåëåíèè àëãåáðàè÷åñêîãî òèïà äàííûõ êàê êîíñòðóêòîðû áåç ïàðàìåòðîâ (èìåííî òàêèå êîíñòðóêòîðû èñïîëüçóþòñÿ â ïðîñòûõ ïåðå÷èñëåíèÿõ), òàê è êîíñòðóêòîðû ñ ïàðàìåòðàìè. Òàê, ê ïðèìåðó, ìîæíî çàíîâî îïðåäåëèòü òèï äëÿ ïðåäñòàâëåíèÿ öâåòîâ, äîáàâèâ äîïîëíèòåëüíûé êîíñòðóêòîð, ïðèíèìàþùèé íà âõîä òðè öåëî÷èñëåííûõ àðãóìåíòà è âîçâðàùàþùèé öâåò â ôîðìàòå RGB (RGB îäíà èç öâåòîâûõ ñèñòåì, èñïîëüçóåìàÿ äëÿ êîäèðîâàíèÿ öâåòà â êîìïüþòåðàõ; ïðåäñòàâëÿåò ñîáîé òðè öåëî÷èñëåííûå êîîðäèíàòû â öâåòîâîì ïðîñòðàíñòâå, ñîîòâåòñòâóþùèå íàñûùåííîñòè êðàñíîãî Red, çåë¼íîãî Green è ñèíåãî Blue öâåòîâ). Òîãäà îïðåäåëåíèå òèïà Color áóäåò âûãëÿäåòü óæå ñëåäóþùèì îáðàçîì:
data Color = Black | Blue | Brown
−− ×¼ðíûé −− Ñèíèé −− Êîðè÷íåâûé
Ïàðàìåòðè÷åñêèé ïîëèìîðôèçì | | | | | | | | |
Cyan Gray Green Magenta Orange Red White Yellow RGB Int Int Int
27
−− −− −− −− −− −− −− −− −−
Ãîëóáîé Ñåðûé Çåë¼íûé Ðîçîâûé Îðàíæåâûé Êðàñíûé Áåëûé Ƽëòûé RGB
Îñòà¼òñÿ îòìåòèòü, ÷òî â êà÷åñòâå òèïîâ, êîòîðûìè ïàðàìåòðèçóþòñÿ ñîçäàâàåìûå àëãåáðàè÷åñêèå òèïû, ìîãóò áûòü êàê ïðèìèòèâíûå òèïû, âñòðîåííûå â èíòåðïðåòàòîð, òàê è òèïû, ñîçäàííûå ïîëüçîâàòåëåì.
Ïàðàìåòðè÷åñêèé ïîëèìîðôèçì Íî äàæå òàêîé ìîùíûé ìåõàíèçì, êàê ïàðàìåòðèçàöèÿ òèïîâ, íå ìîæåò îáåñïå÷èòü âñåõ ïîòðåáíîñòåé â ñîçäàíèè íîâûõ òèïîâ äàííûõ. Âåäü èíîãäà èìååòñÿ íåîáõîäèìîñòü ñîçäàòü (êîíòåéíåðíûì íàçûâàåòñÿ òàêîé òèï äàííûõ, êîòîðûé ñîäåðæèò âíóòðè ñåáÿ îáúåêòû èíûõ òèïîâ, â òîì ÷èñëå è äðóãèå îáúåêòû êîíòåéíåðíûõ òèïîâ, èíà÷å íàçûâàåìûå ïðîñòî ¾êîíòåéíåðàìè¿; íàïðèìåð, ñïèñîê ýòî êîíòåéíåðíûé òèï äàííûõ), âíóòðè êîòîðîãî ìîãóò ñîäåðæàòüñÿ îáúåêòû ëþáîãî òèïà. Ïåðå÷èñëÿòü âñå òàêèå òèïû â êîíñòðóêòîðàõ íåöåëåñîîáðàçíî, òàê êàê ñàìèõ òèïîâ ìîæåò áûòü îãðîìíîå ÷èñëî, äà è íåâîçìîæíî çàðàíåå ïðåäóñìîòðåòü, îáúåêòû êàêèõ òèïîâ çàõî÷åò êòî-ëèáî ïîëîæèòü â êîíòåéíåð. Çäåñü íà ïîìîùü ïðèõîäèò , èíîãäà íàçûâàåìûé èñòèííûì ïîëèìîðôèçìîì äàííûõ. Ïàðàìåòðè÷åñêèé ïîëèìîðôèçì â ïðèìåíåíèè ê àëãåáðàè÷åñêèì òèïàì äàííûõ â ÿçûêå Haskell çàêëþ÷àåòñÿ â òîì, ÷òî â êîíñòðóêòîðàõ òèïîâ ìîãóò óïîòðåáëÿòüñÿ òàê íàçûâàåìûå ïàðàìåòðè÷åñêèå ïåðåìåííûå òèïîâ, êîòîðûå îáû÷íî îáîçíà÷àþòñÿ ñòðî÷íûìè áóêâàìè èç íà÷àëà ëàòèíñêîãî àëôàâèòà. Òàêèå ïåðåìåííûå ìîãóò îáîçíà÷àòü ëþáîé òèï, à ñàìèõ ïåðåìåííûõ ìîæåò áûòü ñòîëüêî, ñêîëüêî íåîáõîäèìî ïðîãðàììèñòó. Åäèíñòâåííàÿ îñîáåííîñòü çàêëþ÷àåòñÿ â òîì, ÷òî âñå èñïîëüçóåìûå ïàðàìåòðè÷åñêèå ïåðåìåííûå äîëæíû áûòü ïåðå÷èñëåíû ïîñëå íàèìåíîâàíèÿ òèïà.  êà÷åñòâå ïðèìåðà ìîæíî ïðèâåñòè òèï äëÿ ïðåäñòàâëåíèÿ áèíàðíûõ äåðåâüåâ, â âåðøèíàõ êîòîðûõ ìîãóò íàõîäèòüñÿ ìåòêè ëþáîãî òèïà. Ýòîò òèï ìåòîê äîëæåí áûòü îäèíàêîâ äëÿ âñåõ âåðøèí äåðåâà, íî ïðè ïîìîùè ïàðàìåòðè÷åñêîãî ïîëèìîðôèçìà, èìåÿ åäèíñòâåííûé êîíñòðóêòîð äëÿ áèíàðíîãî äåðåâà, ìîæíî ñîçäàâàòü òàêèå äåðåâüÿ ñ ìåòêàìè ðàçëè÷íûõ òèïîâ â âåðøèíàõ. Îïðåäåëåíèå òàêîãî òèïà ìîæåò âûãëÿäåòü òàê:
êîíòåéíåðíûé òèï
ïàðàìåòðè÷åñêèé ïîëèìîðôèçì
data BTree a = Empty | Node ( a , BTree a , BTree a ) Ïåðâûé êîíñòðóêòîð Empty îïðåäåëÿåò ïóñòîå äåðåâî. Âòîðîé êîíñòðóêòîð Node îïðåäåëÿåò âåðøèíó, íà êîòîðîé ñòîèò ïîìåòêà íåêîòîðîãî òèïà a è êîòîðàÿ èìååò äâà äî÷åðíèõ ïîääåðåâà ñ ìåòêàìè òîãî æå òèïà. Êàê óæå áûëî ñêàçàíî, íà ìåñòå ïàðàìåòðè÷åñêîé ïåðåìåííîé a ìîæåò ñòîÿòü ëþáîé òèï äàííûõ. Íàïðèìåð, åñëè èìååòñÿ íåîáõîäèìîñòü â ñóùåñòâîâàíèè äåðåâüåâ, ìåòêè â âåðøèíàõ êîòîðûõ ïðåäñòàâëÿþò ñîáîé öåëûå ÷èñëà, òî òèï òàêèõ äåðåâüåâ äîëæåí áûòü BTree Int è ò. ï. Äðóãèìè ñëîâàìè, ïàðàìåòðè÷åñêèé ïîëèìîðôèçì ïîçâîëÿåò îïðåäåëÿòü íàèáîëåå îáùèå òèïû äàííûõ, â êîòîðûõ êîíêðåòíûå òèïû íå îïðåäåëåíû, íî èìåþòñÿ ïàðàìåòðè÷åñêèå ïåðåìåííûå òèïîâ, êîòîðûå ïî ñîãëàøåíèþ îá èìåíîâàíèè îáúåêòîâ â ÿçûêå Haskell äîëæíû íà÷èíàòüñÿ ñî ñòðî÷íîé áóêâû. Ýòî äîñòàòî÷íî ìîùíûé ìåõàíèçì, êîòîðûé ïîçâîëÿåò äîñòèãàòü íàèáîëüøåé ñòåïåíè àáñòðàêöèè ïðè îïðåäåëåíèè òèïîâ.
28
Àëãåáðàè÷åñêèå òèïû äàííûõ â ÿçûêå Haskell
Åñòåñòâåííî, ÷òî ïàðàìåòðèçîâàííûå ïîäîáíûì îáðàçîì àëãåáðàè÷åñêèå òèïû âñ¼ òàê æå ìîãóò ó÷àñòâîâàòü â ïðîöåññå ñîïîñòàâëåíèÿ ñ îáðàçöàìè, êîòîðûé èñïîëüçóåòñÿ ïðè âû÷èñëåíèè çíà÷åíèé ôóíêöèé. Îáðàçöû â äàííîì ñëó÷àå íè÷åì íå îòëè÷àþòñÿ îò ðàññìîòðåííûõ ðàíåå, à â òèïàõ ôóíêöèé ïîÿâëÿþòñÿ òàêèå æå ïàðàìåòðè÷åñêèå ïåðåìåííûå òèïîâ. Äëÿ èçó÷åíèÿ ýòîãî àñïåêòà ìîæíî ðàññìîòðåòü íåñêîëüêî ôóíêöèé, ðàáîòàþùèõ ñ áèíàðíûìè äåðåâüÿìè. Ïåðâàÿ ôóíêöèÿ íàçûâàåòñÿ depth îíà âû÷èñëÿåò ìàêñèìàëüíóþ ãëóáèíó äåðåâà, òî åñòü íàèáîëüøóþ äëèíó èç âñåõ ïóòåé, êîòîðûå ìîæíî ïðîëîæèòü îò êîðíåâîé âåðøèíû äåðåâà ê åãî êîíå÷íûì ëèñòüåâûì âåðøèíàì. Îïðåäåëåíèå ýòîé ôóíêöèè âûãëÿäèò òàê:
depth : : ( Num a , Ord a ) => BTree b −> a depth Empty = 0 depth ( Node ( _ , left , right ) ) = 1 + max ( depth left ) ( depth right ) Âòîðàÿ ôóíêöèÿ ïîäñ÷èòûâàåò îáùåå êîëè÷åñòâî âåðøèí â çàäàííîì äåðåâå. ż îïðåäåëåíèå ïðàêòè÷åñêè òàêîå æå, êàê è ó ôóíêöèè depth (ïî êðàéíåé ìåðå, îíî ïîñòðîåíî íà òåõ æå ñàìûõ ïðèíöèïàõ îáõîäà äåðåâà):
count : : Num a => BTree b −> a count Empty = 0 count ( Node ( _ , left , right ) ) = 1 + count left + count right Òðåòüÿ ôóíêöèÿ âîçâðàùàåò ñïèñîê ìåòîê â âåðøèíàõ äåðåâà ïðè îáõîäå ýòîãî äåðåâà ïî ñõåìå ¾ëåâûé êîðåíü ïðàâûé¿. ż îïðåäåëåíèå óæå íåìíîãèì áîëåå èíòåðåñíîå:
flatten : : BTree a −> [ a ] flatten Empty = [] flatten ( Node ( x , left , right ) ) = flatten left ++ [ x ] ++ flatten right Íàêîíåö, ñàìîé èíòåðåñíîé ÿâëÿåòñÿ ôóíêöèÿ, êîòîðàÿ ïðèíèìàåò íà âõîä äðóãóþ ôóíêöèþ è íåêîòîðîå áèíàðíîå äåðåâî, à âîçâðàùàåò äðóãîå áèíàðíîå äåðåâî, êî âñåì ìåòêàì â âåðøèíàõ êîòîðîãî ïðèìåíåíà çàäàííàÿ â êà÷åñòâå ïåðâîãî àðãóìåíòà ôóíêöèÿ. Ýòî àíàëîã ôóíêöèè map äëÿ ñïèñêîâ:
mapBTree : : ( a −> b ) −> BTree a −> BTree b mapBTree _ Empty = Empty mapBTree f ( Node ( x , left , right ) ) = Node ( f x , ( mapBTree f left ) , ( mapBTree f right ) )
ôóíêöèåé âûñøåãî ïîðÿäêà
Êàê âèäíî, ôóíêöèÿ mapBTree ÿâëÿåòñÿ , êîòîðàÿ ïðèíèìàåò íà âõîä äðóãóþ ôóíêöèþ â êà÷åñòâå ñâîåãî ïåðâîãî àðãóìåíòà. Ýòî ïîçâîëÿåò ðåøàòü ïðè ïîìîùè òàêîé ôóíêöèè äîñòàòî÷íî øèðîêèé íàáîð çàäà÷, ñâÿçàííûõ ñ ïðåîáðàçîâàíèåì äåðåâüåâ. Òàêèì îáðàçîì, ïàðàìåòðè÷åñêèé ïîëèìîðôèçì ÿâëÿåòñÿ âåñüìà ìîùíûì ìåõàíèçìîì, êîòîðûé ïðè èñïîëüçîâàíèè â îïðåäåëåíèÿõ òèïîâ äàííûõ ïîçâîëÿåò ðåøèòü ïðàêòè÷åñêè ëþáóþ çàäà÷ó ïî îïèñàíèþ ñóùíîñòåé ëþáûõ ïðîáëåìíûõ îáëàñòåé. Ïîíèìàíèå òîãî, êàê ðàáîòàþò ïîëèìîðôíûå òèïû, ïîìîãàåò áîëåå ïîëíîöåííî èñïîëüçîâàòü âñå ìåõàíèçìû, êîòîðûå ïðåäîñòàâëÿåò ïðîãðàììèñòó ÿçûê Haskell. Ïîýòîìó ïðè èçó÷åíèè ýòîãî ìîùíîãî ÿçûêà íåîáõîäèìî äîñòàòî÷íîå âíèìàíèå óäåëèòü èìåííî ýòîé òåìå.
Çàêëþ÷åíèå Óìåíèå ãðàìîòíî îïèñûâàòü ïðîáëåìíóþ îáëàñòü èññëåäóåìîé çàäà÷è îäèí èç ãëàâíûõ àñïåêòîâ òåõíîëîãèè ïðîãðàììèðîâàíèÿ, êàêàÿ áû ïàðàäèãìà è ñòèëü ïðè ýòîì íè èñïîëüçîâàëèñü áû. Ðàçðàáîò÷èê, êîòîðûé ìîæåò ïîñòðîèòü îïòèìàëüíîå îïðåäåëåíèå òèïîâ äëÿ îáúåêòîâ è ñâÿçåé ìåæäó íèìè, òî åñòü
Çàêëþ÷åíèå
29
äëÿ òåõ ñóùíîñòåé, êîòîðûìè îïåðèðóåò ïðîãðàììà, äîðîãîãî ñòîèò. Ïîýòîìó ïðè èçó÷åíèè òîãî èëè èíîãî ÿçûêà ïðîãðàììèðîâàíèÿ íåîáõîäèìî î÷åíü âíèìàòåëüíî ïîäõîäèòü ê ïîíèìàíèþ ñïîñîáîâ îïðåäåëåíèÿ òèïîâ.  ñëåäóþùåì ðàçäåëå áóäåò ïîêàçàíî ñëèÿíèå ôóíêöèîíàëüíîé è îáúåêòíî-îðèåíòèðîâàííîé ïàðàäèãì ïðîãðàììèðîâàíèÿ â ÿçûêå Haskell, à òàêæå ñïîñîáû íàïèñàíèÿ îáúåêòíî-îðèåíòèðîâàííûõ ïðîãðàìì íà ýòîì çàìå÷àòåëüíîì ÿçûêå ïðîãðàììèðîâàíèÿ. Êðîìå òîãî, áóäóò ïîêàçàíû äîïîëíèòåëüíûå àñïåêòû ðàáîòû ñ àëãåáðàè÷åñêèìè òèïàìè äàííûõ â ÿçûêå Haskell.
Îáúåêòíî-îðèåíòèðîâàííîå è ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå Ñòàòüÿ áûëà îïóáëèêîâàíà â 02 (26) æóðíàëà ¾Ïîòåíöèàë¿ â ôåâðàëå 2007 ãîäà.
Äàííîå ýññå ðàññìàòðèâàåò âîïðîñû ñëèÿíèÿ äâóõ íàèáîëåå èíòåðåñíûõ ïàðàäèãì ïðîãðàììèðîâàíèÿ îáúåêòíî-îðèåíòèðîâàííîé è ôóíêöèîíàëüíîé, êîòîðûå íàèáîëåå ìàññîâî èñïîëüçóþòñÿ â íàñòîÿùåå âðåìÿ â ïðèêëàäíîé îáëàñòè. Ïðèìåðû ïðèìåíåíèÿ èäèîì îáúåêòíî-îðèåíòèðîâàííîãî ïðîãðàììèðîâàíèÿ ïðèâîäÿòñÿ íà ÿçûêå Haskell.
Ââåäåíèå Ñ ìîìåíòà ðîæäåíèÿ íàóêè î âû÷èñëèòåëüíûõ ïðîöåññàõ â å¼ ïðèêëàäíûõ àñïåêòàõ áûëî ðàçðàáîòàíî äîñòàòî÷íî øèðîêîå ìíîæåñòâî , êîòîðûå èñïîëüçîâàëèñü è äî ñèõ ïîð èñïîëüçóþòñÿ â ðàçëè÷íûõ îáëàñòÿõ êîìïüþòåðíîé íàóêè. Ïîä ïàðàäèãìîé (îò ãðå÷åñêîãî ñëîâà παράδειγμα ïðèìåð, ìîäåëü, îáðàçåö) çäåñü è äàëåå ïîíèìàåòñÿ îáùàÿ êîíöåïòóàëüíàÿ ñõåìà ïîñòàíîâêè ïðîáëåì è ìåòîäîâ èõ ðåøåíèÿ.  áîëåå óçêîì ñìûñëå ïîä ïàðàäèãìîé ïðîãðàììèðîâàíèÿ áóäåò ïîíèìàòüñÿ íå ïðîñòî ñòèëü íàïèñàíèÿ ïðîãðàìì, à ñïîñîá ìûøëåíèÿ, êîòîðûé ïîçâîëÿåò èñïîëüçîâàòü òîò èëè èíîé ñòèëü ïðè ñîçäàíèè òàêèõ ïðîãðàìì. Ïðè ýòîì ÷àñòî òàê ïîëó÷àëîñü, ÷òî íîâàÿ ïàðàäèãìà ðàçðàáàòûâàëàñü äëÿ ðåøåíèÿ íîâûõ êëàññîâ çàäà÷. Íî âñ¼ ðàçíîîáðàçèå èäåé ìîæíî ðàçäåëèòü íà äâà áîëüøèõ êëàññà èìïåðàòèâíîå è äåêëàðàòèâíîå ïðîãðàììèðîâàíèå. Âíóòðè æå ýòèõ êëàññîâ ðàññìàòðèâàþòñÿ îòäåëüíûå ïàðàäèãìû, êîòîðûå ìîãóò âïîëíå è ïåðåñåêàòüñÿ äðóã ñ äðóãîì. Äà è ñàìè ýòè íàïðàâëåíèÿ òàêæå ïåðåñåêàþòñÿ íåêîòîðûå çàäà÷è ìîæíî ëåãêî ðåøèòü êàê ñ ïîìîùüþ èìïåðàòèâíîãî, òàê è ñ ïîìîùüþ äåêëàðàòèâíîãî ñòèëåé.  ïðèíöèïå, âñå ðàçðàáîòàííûå ïàðàäèãìû ïðîãðàììèðîâàíèÿ ìîæíî ñâåñòè ê åäèíîé ñõåìå, êîòîðàÿ áóäåò âêëþ÷àòü â ñåáÿ îáëàñòè â òàê íàçûâàåìîì ¾ìóëüòèïàðàäèãìåííîì¿ ïðîñòðàíñòâå, îòâå÷àþùèå çà òó èëè èíóþ êîíêðåòíóþ ïàðàäèãìó. Òàêèå îáëàñòè áóäóò ïåðåñåêàòüñÿ, è âñå èõ ìîæíî ðàçäåëèòü â ñîîòâåòñòâèè ñ óïîìÿíóòûì ðàíåå ïðèíöèïîì èìïåðàòèâíîñòè èëè äåêëàðàòèâíîñòè. Ñõåìàòè÷åñêè ïîäîáíîå ïðîñòðàíñòâî ïîêàçàíî íà ðèñ. 3. Íà óêàçàííîé ñõåìå öèôðîé 1 óêàçàíî èìåííî èìïåðàòèâíîå ïðîãðàììèðîâàíèå, êîòîðîå õàðàêòåðèçóåòñÿ òåì, ÷òî íàïèñàííûå íà èìïåðàòèâíîì ñòèëå ïðîãðàììû êàê áû ïðåäïèñûâàþò ÝÂÌ âûïîëíÿòü íåêîòîðûå àëãîðèòìè÷åñêèå äåéñòâèÿ (îò ëàò. ïîâåëèòåëüíûé). Ñ äðóãîé ñòîðîíû (ïîä öèôðîé 2) íàõîäèòñÿ äåêëàðàòèâíîå ïðîãðàììèðîâàíèå, õàðàêòåðèçóþùååñÿ îïèñàòåëüíûì ïîäõîäîì ê ïîñòðîåíèþ ïðîãðàìì (îò ëàò. îïèñàòåëüíûé). Äåêëàðàòèâíûå ïðîãðàììû îïèñûâàþò ñïîñîá ðåøåíèÿ çàäà÷è â òåðìèíàõ ïðîáëåìíîé îáëàñòè, à ÝÂÌ ñàìà âûáèðàåò ñïîñîá íàõîæäåíèÿ ðåøåíèÿ. Âî âñ¼ì ìíîæåñòâå ïàðàäèãì âûäåëÿþòñÿ äâå, êîòîðûå èñïîëüçóþòñÿ îñîáåííî ÷àñòî. Ïåðâàÿ îáúåêòíî-îðèåíòèðîâàííàÿ ïàðàäèãìà ïðîãðàììèðîâàíèÿ, êîòîðàÿ íàøëà ñàìîå øèðîêîå ïðèìåíåíèå â ïðèêëàäíûõ îáëàñòÿõ, ñâÿçàííûõ ñ ðàçðàáîòêîé ïðîãðàììíîãî îáåñïå÷åíèÿ ëþáîé ñëîæíîñòè.
ïàðàäèãì ïðîãðàììèðîâàíèÿ
imperativus
declarativus
Èìåíîâàííûå ïîëÿ è ñòðóêòóðû
31
Ðèñ. 3. Ñõåìàòè÷åñêîå èçîáðàæåíèå ¾ìóëüòèïàðàäèãìåííîãî¿ ïðîñòðàíñòâà Âòîðàÿ ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå, ñòàâøåå îñíîâíûì èíñòðóìåíòîì â íàó÷íûõ èññëåäîâàíèÿõ ïî êîìïüþòåðíîé íàóêå. Ïåðâûé ñòèëü îïåðèðóåò îáúåêòàìè è èõ êëàññàìè, ïðè ïîìîùè êîòîðûõ îïèñûâàþòñÿ ïðîáëåìíàÿ îáëàñòü è âñå âçàèìîñâÿçè ìåæäó ñóùíîñòÿìè â íåé. Âòîðîé ñòèëü èñïîëüçóåò ôóíêöèè äëÿ ïðåäñòàâëåíèÿ âû÷èñëèòåëüíûõ ïðîöåññîâ, òàê êàê ôóíêöèè ÿâëÿþòñÿ åñòåñòâåííûì ñïîñîáîì îïèñàíèÿ ïðåîáðàçîâàíèÿ âõîäíûõ ïàðàìåòðîâ â âûõîäíîé ðåçóëüòàò.  äàííîì ðàçäåëå îïèñûâàåòñÿ ñëèÿíèå îáúåêòíî-îðèåíòèðîâàííîé è ôóíêöèîíàëüíîé ïàðàäèãì íà ïðèìåðå ôóíêöèîíàëüíîãî ÿçûêà Haskell, â êîòîðîì èìåþòñÿ äîñòàòî÷íûå ñðåäñòâà äëÿ âûðàæåíèÿ âñåõ ïðèíÿòûõ â îáúåêòíî-îðèåíòèðîâàííîì ñòèëå êîíñòðóêöèé è èäèîì.
Èìåíîâàííûå ïîëÿ è ñòðóêòóðû  îäíîì èç ïðåäûäóùèõ ðàçäåëîâ ¾Àëãåáðàè÷åñêèå òèïû äàííûõ â ÿçûêå Haskell¿ íà÷àòî ðàññìîòðåíèå ðàçëè÷íûõ ñïîñîáîâ îïðåäåëåíèÿ ïîëüçîâàòåëüñêèõ òèïîâ äàííûõ. Îäíàêî âíèìàòåëüíûé ÷èòàòåëü äîëæåí áûë çàäàòüñÿ âîïðîñîì: ¾Èìååòñÿ ëè â ÿçûêå Haskell ìåõàíèçì äëÿ îðãàíèçàöèè íåêîòîðûõ òèïîâ, ñîîòâåòñòâóþùèõ çàïèñÿì èëè ñòðóêòóðàì?¿ Äåéñòâèòåëüíî, â ïðåäûäóùåì ðàçäåëå âîïðîñ îðãàíèçàöèè ñòðóêòóð (òî åñòü òàêèõ òèïîâ äàííûõ, ê ïîëÿì êîòîðûõ ìîæíî îáðàùàòüñÿ ïî îïðåäåë¼ííûì èìåíàì, òàêèå òèïû äàííûõ îïðåäåëÿþòñÿ â ÿçûêàõ C, C++ è èì ïîäîáíûõ ïðè ïîìîùè êëþ÷åâîãî ñëîâà struct) ðàññìîòðåí íå áûë, è ìîãëî ñëîæèòüñÿ âïå÷àòëåíèå, ÷òî òàêèõ ìåõàíèçìîâ â ÿçûêå Haskell ïðîñòî íåò. Íî ðàçðàáîò÷èêè ÿçûêà Haskell ðåøèëè äàòü ïðîãðàììèñòó âîçìîæíîñòü îïðåäåëÿòü ñòðóêòóðû äëÿ ñâîèõ íóæä. È õîòÿ èõ îïðåäåëåíèå âûãëÿäèò âåñüìà òðàäèöèîííûì, íî èõ âíóòðåííÿÿ ðåàëèçàöèÿ è èñïîëüçîâàíèå äîñòàòî÷íî ñèëüíî îòëè÷àþòñÿ îò ñòðóêòóð â èìïåðàòèâíûõ ÿçûêàõ ïðîãðàììèðîâàíèÿ. Íè÷åãî íå ïîäåëàåøü ôóíêöèîíàëüíûé ñòèëü íàêëàäûâàåò ñâîè îãðàíè÷åíèÿ íà âñå àñïåêòû äåÿòåëüíîñòè ðàçðàáîò÷èêà ïðîãðàììíîãî îáåñïå÷åíèÿ. Îäíàêî ñòîèò ðàññìîòðåòü ïðèìåð, ÷òîáû ïîíÿòü ïðèíöèïû è ñïîñîáû èñïîëüçîâàíèÿ â ÿçûêå Haskell àëãåáðàè÷åñêèõ òèïîâ äàííûõ ñ .  êà÷åñòâå òàêîãî ïðèìåðà î÷åíü õîðîøî ïîäîéä¼ò îïèñàíèå òèïîâ äëÿ ðàáîòû ñ ðàçëè÷íûìè ãåîìåòðè÷åñêèìè ôèãóðàìè, êîòîðûå çàäàþòñÿ ñâîèìè êîîðäèíàòàìè è íåêîòîðûìè èíûìè ïàðàìåòðàìè. Çàîäíî òàêîé ïðèìåð ïîìîæåò âñïîìíèòü îñíîâû ãåîìåòðèè. Äëÿ íà÷àëà íåîáõîäèìî îïðåäåëèòü òèï, êîòîðûé áóäåò ïðåäñòàâëÿòü ñîáîé òî÷êó íà ïëîñêîñòè. Ýòî áàçîâûé òèï äëÿ ëþáûõ ãåîìåòðè÷åñêèõ ôèãóð (¾áàçîâûé¿ íå â ñìûñëå îáúåêòíî-îðèåíòèðîâàííîãî ïðîãðàììèðîâàíèÿ, à òàêîé, íà îñíîâå êîòîðîãî ñòðîÿòñÿ âñå îñòàëüíûå ôèãóðû). Òî÷êà õàðàêòåðèçóåòñÿ íàëè÷èåì äâóõ êîîðäèíàò x è y, ïðè÷¼ì îíè èìåþò îäèíàêîâûé òèï, êîòîðûé ïîçâîëÿåò ïðîèçâîäèòü íàä êîîðäèíàòàìè àðèôìåòè÷åñêèå îïåðàöèè è âû÷èñëÿòü òðèãîíîìåòðè÷åñêèå ôóíêöèè (åñòåñòâåííî, äëÿ ïðåîáðàçîâàíèÿ êîîðäèíàò íà ïëîñêîñòè). Âñ¼ ýòî ìîæíî îïèñàòü íà ÿçûêå Haskell äîñòàòî÷íî ïðîñòî:
èìåíîâàííûìè ïîëÿìè
32
Îáúåêòíî-îðèåíòèðîâàííîå è ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå
data Floating a => Point a = Point { x :: a, y :: a } Êàê âèäíî, â ýòîé çàïèñè îïðåäåëÿåòñÿ àëãåáðàè÷åñêèé òèï äàííûõ ñ îäíèì êîíñòðóêòîðîì Point, êîòîðûé ïàðàìåòðèçóåòñÿ òèïîì a, íà êîòîðûé, â ñâîþ î÷åðåäü, íàêëàäûâàåòñÿ îãðàíè÷åíèå îí äîëæåí èìåòü âîçìîæíîñòü ó÷àñòâîâàòü â àðèôìåòè÷åñêèõ îïåðàöèÿõ è òðèãîíîìåòðè÷åñêèõ ôóíêöèÿõ â êà÷åñòâå òèïà îïåðàíäîâ (îãðàíè÷åíèå çàïèñàíî êàê Floating a => òàêèå êîíñòðóêöèè ïîäðîáíî îïèñûâàþòñÿ â ñëåäóþùåì ðàçäåëå). Äðóãèìè ñëîâàìè, äëÿ îïðåäåëåíèÿ ñòðóêòóðû ñ èìåíîâàííûìè ïîëÿìè äàííûõ èñïîëüçóåòñÿ àáñîëþòíî òàêîé æå ìåõàíèçì ñîçäàíèÿ àëãåáðàè÷åñêèõ òèïîâ äàííûõ. Åäèíñòâåííîå îòëè÷èå îïðåäåë¼ííûé ñèíòàêñèñ, êîòîðûé ïîçâîëÿåò äàâàòü ïîëÿì òðåáóåìûå èìåíà. Íà ñàìîì äåëå çàïèñü Point { x :: a , y :: a } àáñîëþòíî òîæäåñòâåííà òðàäèöèîííîé: Point a a. Äîïîëíèòåëüíûå èìåíà x è y çàñòàâëÿþò òðàíñëÿòîð ÿçûêà Haskell ñîçäàòü äâå îäíîèì¼ííûå ôóíêöèè äëÿ äîñòóïà ê îïðåäåë¼ííûì ïîëÿì. Ïîýòîìó òàêîå îïðåäåëåíèå íåÿâíî îáóñëîâëèâàåò íàëè÷èå äâóõ ôóíêöèé, íàõîäÿùèõñÿ íà âåðõíåì óðîâíå èåðàðõèè îáúåêòîâ â ìîäóëå:
x : : Fractional a => Point a −> a x ( Point v1 v2 ) = v1 y : : Fractional a => Point a −> a y ( Point v1 v2 ) = v2 Íî è ýòî åù¼ íå âñ¼. Ïðè ïîìîùè ýòèõ èì¼í ìîæíî ìåíÿòü îïðåäåë¼ííûå ïîëÿ â ñîçäàííîé ñòðóêòóðå. Êîíå÷íî, ñîãëàñíî ïðèíöèïàì ïàðàäèãìû ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ, â ïàìÿòè áóäåò ñîçäàí íîâûé îáúåêò ñ èçìåí¼ííûì çíà÷åíèåì îäíîãî èëè íåñêîëüêèõ ïîëåé, íî ñ òî÷êè çðåíèÿ ïðîãðàììèñòà ýòî áóäåò âûãëÿäåòü ïðèìåðíî òàê:
shiftByX : : Fractional a => Point a −> a −> Point a shiftByX ( Point v _ ) dX = Point { x = v + dX } shiftByY : : Fractional a => Point a −> a −> Point a shiftByY ( Point _ v ) dY = Point { y = v + dY } Çäåñü íàäî îòìåòèòü, ÷òî ïðè èñïîëüçîâàíèè çàïèñè íîâûõ çíà÷åíèé â íåêîòîðûå ïîëÿ äàííûõ îñòàëüíûå ïîëÿ ïîëó÷àò çíà÷åíèå undefined (¾íå îïðåäåëåíî¿ ⊥), ïîýòîìó âûçîâ x (shiftByY (Point 0 0) 1) âûäàñò îøèáêó, à âûçîâ y (shiftByY (Point 0 0) 1) âåðí¼ò çíà÷åíèå 1. Çäåñü íàäî áûòü î÷åíü âíèìàòåëüíûì ïðè ïðîãðàììèðîâàíèè. Äëÿ òîãî ÷òîáû èçáåæàòü òàêèõ îøèáîê, äîñòàòî÷íî èñïîëüçîâàòü èìåíîâàííûå îáðàçöû, äëÿ êîòîðûõ óæå èçìåíÿòü çíà÷åíèÿ îïðåäåë¼ííûõ ïîëåé.  ýòîì ñëó÷àå çíà÷åíèÿ äðóãèõ ïîëåé îñòàíóòñÿ íåèçìåííûìè, à íå ïîëó÷àò çíà÷åíèå undefined:
shiftByX : : Fractional a => Point a −> a −> Point a shiftByX p@ ( Point v _ ) dX = p { x = v + dX } shiftByY : : Fractional a => Point a −> a −> Point a shiftByY p@ ( Point _ v ) dY = p { y = v + dY } Íî ïðè ýòîì îñòà¼òñÿ âîçìîæíîñòü ïîëüçîâàòüñÿ îáû÷íûì ñïîñîáîì çàïèñè íîâûõ çíà÷åíèé â ïîëÿ ñòðóêòóðû:
shift : : Fractional a => Point a −> a −> a −> Point a
Èìåíîâàííûå ïîëÿ è ñòðóêòóðû
33
shift ( Point v1 v2 ) dX dY = Point ( v1 + dX ) ( v2 + dY ) Äàííûå ôóíêöèè ÿâëÿþòñÿ ïðèìåðîì òîãî, êàê ìîæíî ðàáîòàòü ñ âíîâü ñîçäàííûì òèïîì äàííûõ, ïðåäñòàâëÿþùèì ñîáîé òî÷êó. Îäíàêî ñàì òèï ãîòîâ, ÷òîáû íà åãî îñíîâå ñäåëàòü òèï äàííûõ, ïðåäñòàâëÿþùèé ñîáîé ëþáóþ ãåîìåòðè÷åñêóþ ôèãóðó. Íàäî çàìåòèòü, ÷òî äëÿ àëãåáðàè÷åñêèõ òèïîâ ñ èìåíîâàííûìè ïîëÿìè äåéñòâóþò òå æå ñàìûå ïðàâèëà îïðåäåëåíèÿ òèïîâ, ïîýòîìó âïîëíå ìîæíî ñäåëàòü ÷òî-òî òèïà ñëåäóþùåãî:
data Floating a => Figure a = Circle {
center : : Point a , radius : : a } | Rectangle {
anchor : : Point a , width : : a , height : : a } | Polygon {
points : : [ Point a ] } Îäíàêî òàêàÿ çàïèñü íå î÷åíü õîðîøà ñ òî÷êè çðåíèÿ ìàñøòàáèðóåìîñòè ðåøåíèÿ. Åñëè ïîòðåáóåòñÿ äîáàâèòü íîâîå îïèñàíèå êàêîé-ëèáî ãåîìåòðè÷åñêîé ôèãóðû, òî ïðèä¼òñÿ ìåíÿòü âåñü òèï, ÷òî ïðèâåä¼ò ê íåîáõîäèìîñòè ïåðåêîìïèëÿöèè ïðîåêòà. Ïîýòîìó ëó÷øå ñäåëàòü íåñêîëüêî òèïîâ, íàáîð êîòîðûõ ìîæíî äîïîëíÿòü ïî ìåðå íåîáõîäèìîñòè, â òîì ÷èñëå è èç âíåøíèõ ìîäóëåé, îïèñûâàÿ â íèõ íîâûå ãåîìåòðè÷åñêèå ôèãóðû. Òàêèì îáðàçîì, ïåðâîíà÷àëüíûé íàáîð ôèãóð òàêîâ:
data Floating a => Circle a = Circle {
center : : Point a , radius : : a }
data Floating a => Rectangle a = Rectangle {
anchor : : Point a , width : : a , height : : a }
data Floating a => Polygon a = Polygon {
points : : [ Point a ] }
34
Îáúåêòíî-îðèåíòèðîâàííîå è ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå
Íî òåïåðü âîçíèêàåò æåëàíèå ïðèìåíèòü ê îáúåêòàì ýòèõ òèïîâ òàêóþ æå îïåðàöèþ äëÿ ñäâèãà shift. Ïðîñòî òàê ýòî íå ïîëó÷èòñÿ, òàê êàê ñèãíàòóðà ôóíêöèè shift ïîçâîëÿåò åé ðàáîòàòü òîëüêî ñ îáúåêòàìè òèïà Point a. Ïðèä¼òñÿ ïèñàòü îòäåëüíûå ìåòîäû ñ óíèêàëüíûìè èìåíàìè äëÿ êàæäîé ãåîìåòðè÷åñêîé ôèãóðû. Íî âåäü ýòîãî òàê íå õî÷åòñÿ äåëàòü! Íà ñöåíó âûõîäÿò òàêèå ñóùíîñòè ÿçûêà Haskell, êàê .
êëàññû
òèïîâ
Êëàññû òèïîâ Íåîáõîäèìî ñðàçó îòìåòèòü, ÷òî â ÿçûêå Haskell ïîä ïîíÿòèåì ¾êëàññ¿ ïîíèìàåòñÿ íå÷òî èíîå, íåæåëè â îáúåêòíî-îðèåíòèðîâàííîì ïîäõîäå ê ïðîãðàììèðîâàíèþ. Êëàññ â ÿçûêå Haskell ýòî áîëåå àáñòðàêòíîå ïîíÿòèå, êîòîðîå îòíîñèòñÿ ê ñèñòåìå òèïîâ ÿçûêà ïðîãðàììèðîâàíèÿ. Êëàññ ýòî íå òèï äàííûõ, ýòî ¾òèï òèïîâ¿. Ýêçåìïëÿðàìè êëàññà ìîãóò áûòü òèïû äàííûõ. Äðóãàÿ òî÷êà çðåíèÿ íà êëàññ çàêëþ÷àåòñÿ â òîì, ÷òî ïîä êëàññîì â ÿçûêå Haskell ïîíèìàåòñÿ èíòåðôåéñ, êîòîðûé ñïåöèôèöèðóåò îïðåäåë¼ííûé íàáîð ìåòîäîâ äëÿ ðàáîòû ñ íåêîòîðîé ñòðóêòóðîé äàííûõ. Òàêîé ïîäõîä èìååò ïðàâî íà ñóùåñòâîâàíèå, òàê êàê â äåéñòâèòåëüíîñòè ïðè îïðåäåëåíèè êëàññîâ ïðîèñõîäèò îïèñàíèå ôóíêöèé, êîòîðûå íåîáõîäèìî îïðåäåëèòü äëÿ òåõ òèïîâ, êîòîðûå âïîñëåäñòâèè ñòàíóò ýêçåìïëÿðàìè ñîçäàâàåìîãî êëàññà.  ýòîì è çàêëþ÷àåòñÿ êëþ÷ ê ðåøåíèþ òåõ ïðîáëåì, êîòîðûå ïîñòàâëåíû â ïðåäûäóùåì ðàçäåëå. Êëàññ îïðåäåëÿåò èìåíà ôóíêöèé, êîòîðûå áóäóò îïåðèðîâàòü ñ îáúåêòàìè îïðåäåë¼ííûõ òèïîâ, ïðè÷¼ì äîñòàòî÷íî âñå ýòè òèïû îïðåäåëèòü ýêçåìïëÿðàìè êëàññà. Ïðåæäå ÷åì ïåðåéòè ê ñîçäàíèþ êëàññà äëÿ îïèñàíèÿ äåéñòâèé, êîòîðûå ìîãóò áûòü ïðåäïðèíÿòû íàä ãåîìåòðè÷åñêèìè ôèãóðàìè, ñòîèò ðàññìîòðåòü ïðèìåð èç ñòàíäàðòíîãî ìîäóëÿ Prelude ÿçûêà Haskell, ÷òîáû áîëåå ÷¼òêî ïîíÿòü òî, ÷òî òàêîå êëàññû.  êà÷åñòâå ïðèìåðà ìîæíî ðàññìîòðåòü áàçîâûå àðèôìåòè÷åñêèå îïåðàöèè.  ìàòåìàòèêå äëÿ èõ îáîçíà÷åíèÿ òðàäèöèîííî èñïîëüçóþòñÿ ñèìâîëû (+), (−) è (×) (ïðè ýòîì îïåðàöèÿ äåëåíèÿ (:) íå ðàññìàòðèâàåòñÿ, òàê êàê îíà íå ÿâëÿåòñÿ çàìêíóòîé îòíîñèòåëüíî ìíîæåñòâà öåëûõ ÷èñåë, à ñåé÷àñ âàæíî ðàññìîòðåòü èìåííî öåëûå ÷èñëà â êà÷åñòâå îáó÷àþùåãî ïðèìåðà). Íî ïðèìåíÿòü àðèôìåòè÷åñêèå îïåðàöèè ìîæíî íàä îïåðàíäàìè ðàçíûõ òèïîâ íàòóðàëüíûå ÷èñëà, öåëûå ÷èñëà, äåéñòâèòåëüíûå ÷èñëà è ò. ä.  ¾÷èñòîé¿ ìàòåìàòèêå ó÷¼íûé ðåäêî çàäóìûâàåòñÿ íàä òåì, ÷òî ýòè îáúåêòû ðàçíûõ òèïîâ, îäíàêî ïðîãðàììèñò îá ýòîì ïîìíèò âñåãäà. Íî, åñòåñòâåííî, â ñèëó òðàäèöèè õî÷åòñÿ îáîçíà÷àòü àðèôìåòè÷åñêèå îïåðàöèè îäèíàêîâî äëÿ âñåõ òèïîâ ÷èñåë.  ðàçíûõ ÿçûêàõ ïðîãðàììèðîâàíèÿ äëÿ ýòèõ öåëåé èñïîëüçóþòñÿ ðàçíûå ìåõàíèçìû.  áîëüøèíñòâå áàçîâûå àðèôìåòè÷åñêèå îïåðàöèè è ïåðåãðóçêà èõ èì¼í ¾âøèòû¿ â òðàíñëÿòîð ÿçûêà. Íî ñîçäàòåëè ÿçûêà Haskell ïîøëè èíûì ïóò¼ì. Äëÿ ýòèõ öåëåé â ñòàíäàðòíîì ìîäóëå Prelude îïèñàí êëàññ Num, ïðåäñòàâëÿþùèé ñîáîé êëàññ òèïîâ, îáúåêòû êîòîðûõ ¾ïîõîæè¿ íà öåëûå ÷èñëà. Íàä îáúåêòàìè ýòèõ ÷èñåë ìîæíî ïðîèçâîäèòü áàçîâûå àðèôìåòè÷åñêèå îïåðàöèè, öåëî÷èñëåííîå äåëåíèå, âçÿòèå îñòàòêà îò äåëåíèÿ, à òàêæå íåñêîëüêî äðóãèõ ôóíêöèé. Îïðåäåëåíèå ýòîãî êëàññà âûãëÿäèò òàê:
c l a s s ( Eq a , Show a ) => Num a where (+) , ( − ) , ( ∗ ) : : negate :: abs , signum :: fromInteger :: fromInt ::
a −> a −> a a −> a a −> a Integer −> a Int −> a
x − y = x + negate y negate x = 0 − x fromInt = fromIntegral
Ýêçåìïëÿðû êëàññîâ
35
Êàê âèäíî, îïðåäåëåíèå êëàññà íà÷èíàåòñÿ ñ êëþ÷åâîãî ñëîâà class, ïîñëå êîòîðîãî èä¼ò ñåêöèÿ ñî ñïåöèôèêàöèåé èìåíè êëàññà (î íåé ïîçæå) äî êëþ÷åâîãî ñëîâà where. Ïîñëå ýòîãî êëþ÷åâîãî ñëîâà èä¼ò ïåðå÷èñëåíèå ìåòîäîâ êëàññà, à òàêæå îïèñàíèå âçàèìîñâÿçåé ìåòîäîâ äðóã ñ äðóãîì (ïðè íåîáõîäèìîñòè). Ìåòîäû îïèñûâàþòñÿ ïðîñòî ïîñëå èìåíè ñòîèò ñèìâîë ( :: ) ¾èìååò òèï¿, ïîñëå êîòîðîãî îïèñûâàåòñÿ ñèãíàòóðà ñîîòâåòñòâóþùåãî ìåòîäà. Ìåòîäû ñ îäèíàêîâûìè ñèãíàòóðàìè ìîæíî ïåðå÷èñëÿòü ÷åðåç çàïÿòóþ. Ñåêöèÿ ñ îïèñàíèåì âçàèìîñâÿçåé çàïèñûâàåòñÿ ïðè íåîáõîäèìîñòè è âîçìîæíîñòè âûðàçèòü îäèí ìåòîä êëàññà ÷åðåç äðóãîé. Òàê, â ïðèâåä¼ííîì ïðèìåðå âû÷èòàíèå îäíîãî ÷èñëà èç äðóãîãî ìîæíî âûðàçèòü ÷åðåç ñëîæåíèå è ôóíêöèþ negate (îòðèöàíèå). Åñòåñòâåííî, ÷òî òàêèå âçàèìîñâÿçè ìîæíî îïèñàòü íå âñåãäà. Ñïåöèôèêàöèÿ èìåíè êëàññà ñîñòîèò èç îãðàíè÷åíèÿ íà ïåðåìåííûå òèïîâ (íåîáÿçàòåëüíàÿ ÷àñòü), ñîáñòâåííî èìåíè êëàññà è ïåðåìåííîé, êîòîðàÿ îáîçíà÷àåò áóäóùèå ýêçåìïëÿðû îïèñûâàåìîãî êëàññà (â ðàññìàòðèâàåìîì ïðèìåðå a). Îãðàíè÷åíèå íà òèï a çàäà¼òñÿ ïðè ïîìîùè ïåðå÷èñëåíèÿ êëàññîâ, ýêçåìïëÿðîì êîòîðûõ äîëæåí áûòü òèï a, íàïèñàííûé äî ñèìâîëà (=>). Åñëè òàêèõ îãðàíè÷åíèé íåñêîëüêî, òî èõ íàäî ïåðå÷èñëèòü ÷åðåç çàïÿòóþ è çàêëþ÷èòü â êðóãëûå ñêîáêè. Òàêèì îáðàçîì, ïðèâåä¼ííîå îïðåäåëåíèå êëàññà Num ìîæíî ÷èòàòü ñëåäóþùèì îáðàçîì: ¾Êëàññ Num ñïåöèôèöèðóåò äëÿ íåêîòîðîãî òèïà a, êîòîðûé îáÿçàí ÿâëÿòüñÿ ýêçåìïëÿðîì êëàññîâ Eq è Show, ìåòîäû (+), (−), (∗), negate, abs, signum, fromInteger, fromInt, êîòîðûå èìåþò çàäàííûå ñèãíàòóðû. Êðîìå òîãî, äëÿ ìåòîäîâ (−), negate è fromInt îïðåäåëÿþòñÿ âûðàæåíèÿ ÷åðåç èíûå ìåòîäû ýòîãî êëàññà è ïðî÷èå ôóíêöèè¿. Òàêîé êëàññ ìîæíî èñïîëüçîâàòü äëÿ îïðåäåëåíèÿ ìåòîäîâ íàä ýëåìåíòàìè îïðåäåë¼ííîãî òèïà, êîòîðûå ïðåäíàçíà÷åíû äëÿ ñëîæåíèÿ, âû÷èòàíèÿ è ò. ä. Ýòî ìîãóò áûòü ëþáûå ýëåìåíòû âñ¼ çàâèñèò òîëüêî îò ôàíòàçèè ðàçðàáîò÷èêà. Òåïåðü ìîæíî âîçâðàòèòüñÿ ê ïðèìåðó ñ ãåîìåòðè÷åñêèìè ôèãóðàìè. Ê ëþáîé ôèãóðå, íåçàâèñèìî îò å¼ ôàêòè÷åñêîãî òèïà, ìîãóò ïðèìåíÿòüñÿ òàê íàçûâàåìûå àôèííûå ïðåîáðàçîâàíèÿ, òî åñòü îíà ìîæåò ïåðåìåùàòüñÿ, ìàñøòàáèðîâàòüñÿ è âåðòåòüñÿ îòíîñèòåëüíî êàêîé-òî òî÷êè. Ïîýòîìó ìîæíî îïðåäåëèòü òðè ìåòîäà: shift, scale è rotate â êëàññå Figure:
c l a s s Figure f where shift : : Floating a => f a −> a −> a −> f a scale : : Floating a => f a −> Point a −> a −> f a rotate : : Floating a => f a −> Point a −> a −> f a Ê ñîæàëåíèþ, ýòè ìåòîäû íåëüçÿ âûðàçèòü äðóã ÷åðåç äðóãà, ïîýòîìó çäåñü îïèñàíû òîëüêî ñèãíàòóðû ýòèõ ìåòîäîâ. Ñèãíàòóðû ìîãóò ïîìî÷ü ïîíÿòü, ÷òî äîëæíû äåëàòü ñàìè ìåòîäû. Òàê, ê ïðèìåðó, ìåòîä shift ïîëó÷àåò íà âõîä îïèñàíèå ôèãóðû è äâà êîýôôèöèåíòà ñäâèãà, à âîçâðàùàåò íîâóþ ôèãóðó. Ìåòîäû scale è rotate ïîëó÷àò íà âõîä ôèãóðó, òî÷êó, îòíîñèòåëüíî êîòîðîé ïðîèçâîäèòñÿ ïðåîáðàçîâàíèå, è êîýôôèöèåíò ïðåîáðàçîâàíèÿ (ìàñøòàá è óãîë ñîîòâåòñòâåííî), à âîçâðàùàþò îïÿòüòàêè íîâóþ ôèãóðó. Òåïåðü îñòà¼òñÿ îáúÿâèòü âñå îïðåäåë¼ííûå ðàíåå àëãåáðàè÷åñêèå òèïû äàííûõ äëÿ ïðåäñòàâëåíèÿ ãåîìåòðè÷åñêèõ ôèãóð ýêçåìïëÿðàìè íîâîãî êëàññà, èáî ñàìî ïî ñåáå îïðåäåëåíèå êëàññà Figure íå ñîçäà¼ò íèêàêèõ ôóíêöèé.
Ýêçåìïëÿðû êëàññîâ Êàê óæå ñêàçàíî, ñàìî ïî ñåáå ñîçäàíèå êëàññà íå âëå÷¼ò íè÷åãî, ÷òî âëèÿåò íà èñïîëíåíèå ïðîãðàììû. Äëÿ ñîçäàíèÿ ôóíêöèé, ñèãíàòóðû êîòîðûõ îïèñàíû â êëàññå è êîòîðûå áû ðàáîòàëè ñ îïðåäåë¼ííûìè òèïàìè äàííûõ, íåîáõîäèìî îïðåäåëèòü òàêèå äàííûå â êà÷åñòâå ýêçåìïëÿðîâ ñîîòâåòñòâóþùåãî êëàññà. Äëÿ îïðåäåëåíèÿ ýêçåìïëÿðà íåîáõîäèìî âîñïîëüçîâàòüñÿ êëþ÷åâûì ñëîâîì instance. Ïîñëå ýòîãî êëþ÷åâîãî ñëîâà óêàçûâàåòñÿ ñïåöèôèêàöèÿ ýêçåìïëÿðà, êîòîðàÿ ïðàêòè÷åñêè òîæäåñòâåííà òàêîé æå ñïåöèôèêàöèè äëÿ êëàññîâ, çà èñêëþ÷åíèåì òîãî, ÷òî â êà÷åñòâå ñïåöèôèöèðóåìîãî òèïà óêàçûâàåòñÿ
36
Îáúåêòíî-îðèåíòèðîâàííîå è ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå
íå àáñòðàêòíàÿ ïåðåìåííàÿ òèïîâ, à òîò òèï, äëÿ êîòîðîãî îïðåäåëÿåòñÿ ýêçåìïëÿð. Ïîñëå êëþ÷åâîãî ñëîâà where ïåðå÷èñëÿþòñÿ îïðåäåëåíèÿ ìåòîäîâ êëàññà äëÿ êîíêðåòíîãî òèïà. Íàïðèìåð, äëÿ òèïà Point íóæíî îïðåäåëèòü ýêçåìïëÿð êëàññà Figure, ýòî äåëàåòñÿ ïðèìåðíî ñëåäóþùèì îáðàçîì:
instance Figure Point where shift ( Point x y ) dX dY = Point ( x + dX ) ( y + dY ) scale ( Point x y ) ( Point xa ya ) k = Point ( xa + k ∗ ( x − xa ) ) ( ya + k ∗ ( y − ya ) ) rotate ( Point x y ) ( Point xa ya ) k = Point ( xa + r ∗ cos ( alpha + k ) ) ( ya + r ∗ sin ( alpha + k ) )
where
r = sqrt ( ( x − xa )^2 + ( y − ya ) ^ 2 ) alpha = acos ( ( x − xa ) / r ) Êàê âèäíî, íè÷åãî ñëîæíîãî íåò. Ýòî îïðåäåëåíèå ãëàñèò, ÷òî äëÿ òèïà Point îïðåäåëåíû ìåòîäû êëàññà Figure: shift, scale è rotate. Ïîñëå ýòîãî ìîæíî èñïîëüçîâàòü äàííûå ìåòîäû íà îïåðàíäàõ òèïà Point, ïðè ýòîì òðàíñëÿòîð ÿçûêà Haskell ñàìîñòîÿòåëüíî âûáåðåò íåîáõîäèìûé ýêçåìïëÿð, ÷òîáû âûçâàòü ìåòîä íà èñïîëíåíèå. Íàäî îòìåòèòü, ÷òî ñàìè ïî ñåáå àëãåáðàè÷åñêèå òèïû äàííûõ è êëàññû ñîâåðøåííî íå ñâÿçàííûå äðóã ñ äðóãîì åäèíèöû èñõîäíîãî êîäà íà ÿçûêå Haskell. Ýêçåìïëÿðû êëàññîâ ýòî òà ñóùíîñòü, ïðè ïîìîùè êîòîðîé ïðîèñõîäèò ñâÿçûâàíèå êëàññîâ è òèïîâ. Íî è ýêçåìïëÿð òîæå íåçàâèñèìàÿ ïðîãðàììíàÿ ñóùíîñòü, îíà ìîæåò ñóùåñòâîâàòü, à ìîæåò è íå ñóùåñòâîâàòü. Ñóùåñòâîâàíèå ýêçåìïëÿðîâ ïîçâîëÿåò ãîâîðèòü òðàíñëÿòîðó ÿçûêà Haskell, ÷òî ôóíêöèè ìîãóò èñïîëüçîâàòü îáúåêòû îïðåäåë¼ííûõ òèïîâ, åñëè îíè ñîîòâåòñòâóþò îãðàíè÷åíèÿì, ïðîïèñàííûì â ñèãíàòóðàõ ôóíêöèé. Äëÿ òîãî ÷òîáû ðàáîòàòü ñ îïèñàííûìè ðàíåå ãåîìåòðè÷åñêèìè ôèãóðàìè, íåîáõîäèìî ñîçäàòü ñîîòâåòñòâóþùèå ýêçåìïëÿðû êëàññà Figure. Ïðè ýòîì ñëåäóåò ó÷åñòü, ÷òî, èìåÿ â íàëè÷èè ýêçåìïëÿð òèïà Point, îñòàëüíûå ýêçåìïëÿðû îïðåäåëÿþòñÿ óæå äîñòàòî÷íî ëåãêî. Íàäî îáðàòèòü âíèìàíèå, ÷òî äëÿ ýëåìåíòîâ òèïà Point ìîæíî èñïîëüçîâàòü îïðåäåë¼ííûå ìåòîäû shift, scale è rotate. Ñîáñòâåííî, äåëî çà ìàëûì:
instance Figure Circle where shift ( Circle c r ) dX dY = Circle ( shift c dX dY ) r scale ( Circle c r ) pa k = Circle ( scale c pa k ) ( k ∗ r ) rotate ( Circle c r ) pa k = Circle ( rotate c pa k ) r
instance Figure Rectangle where shift ( Rectangle a w h ) dX dY = Rectangle ( shift a dX dY ) w h scale ( Rectangle a w h ) pa k = Rectangle ( scale a pa k ) ( w ∗ k ) ( h ∗ k ) rotate ( Rectangle a w h ) pa k = Rectangle ( rotate a pa k ) w h
instance Figure Polygon where shift ( Polygon pts ) dX dY
Îêîí÷àòåëüíûå çàìå÷àíèÿ
37
= Polygon ( modify pts dX dY )
where
modify [ ] _ _ = [] modify ( p : ps ) dX dY = ( shift p dX dY ) : ( modify ps dX dY ) scale ( Polygon pts ) pa k = Polygon ( modify pts pa k )
where
modify [ ] _ _ modify ( p : ps ) pa k
= [] = ( scale p pa k ) : ( modify ps pa k )
rotate ( Polygon pts ) pa k = Polygon ( modify pts pa k )
where
modify [ ] _ _ modify ( p : ps ) pa k
= [] = ( rotate p pa k ) : ( modify ps pa k )
Âñ¼ ïðîñòî, íî îñòà¼òñÿ íåñêîëüêî ïðîáëåì áîëüøå ýñòåòè÷åñêîãî õàðàêòåðà. Ïåðâîå, ÷òî áðîñàåòñÿ â ãëàçà, ìíîãî ïðàêòè÷åñêè îäèíàêîâûõ ñòðîê êîäà â îïðåäåëåíèè ýêçåìïëÿðà Figure~Polygon. Êîíå÷íî, õîòåëîñü áû âñå ïîäîáíûå ïîâòîðåíèÿ ñâåñòè â åäèíóþ ôóíêöèþ modify, êîòîðàÿ áûëà áû è ïðèíèìàëà áû íà âõîä òîò ìåòîä, êîòîðûé íåîáõîäèìî ïðèìåíèòü ê íàáîðó òî÷åê. Íî òóò íå âñ¼ òàê ïðîñòî. Ê ñîæàëåíèþ, êëàññ Figure ñïðîåêòèðîâàí òàê, ÷òî ó ìåòîäà shift òèï ñîâåðøåííî èíîé, íåæåëè ó îñòàëüíûõ ìåòîäîâ. Ïîýòîìó ïðîñòàÿ ôóíêöèÿ íå ïîìîæåò. Ðåøåíèå äàííîé çàäà÷è îñòàâëÿåòñÿ âäóì÷èâîìó ÷èòàòåëþ. Âòîðàÿ ïðîáëåìà â ýòîì íàáîðå îïðåäåëåíèé êðîåòñÿ â ìåòîäå rotate äëÿ ïðÿìîóãîëüíèêà Rectangle. Ýòîò òèï îïèñàí òàê, ÷òî âðàùàòü ìîæíî òîëüêî îïîðíóþ òî÷êó, à åãî ñòîðîíû âñåãäà îñòàþòñÿ ïàðàëëåëüíû îñÿì êîîðäèíàò (õîòÿ ýòî ÿâíî è íå îïèñàíî ïðè òàêîì îïèñàíèè ìîæíî ïðåäïîëîæèòü, ÷òî ñòîðîíû âîîáùå íàïðàâëåíû òàê, êàê çàáëàãîðàññóäèòñÿ, çäåñü âîïðîñ â èíòåðïðåòàöèè òèïà). Ïîýòîìó åñëè åñòü íåîáõîäèìîñòü âî âðàùåíèè ïðÿìîóãîëüíèêà â âèäå öåëîñòíîé ôèãóðû, íåîáõîäèìî ìåíÿòü ñàì òèï äàííûõ. Ýòà çàäà÷à òàêæå îñòà¼òñÿ äëÿ ñàìîñòîÿòåëüíîãî ðåøåíèÿ.  êà÷åñòâå ïîäñêàçêè äëÿ âòîðîé çàäà÷è ìîæíî óêàçàòü, ÷òî ïðîùå è ëó÷øå âñåãî ïðÿìîóãîëüíèê ïðåäñòàâëÿòü ïðè ïîìîùè äâóõ îïîðíûõ òî÷åê, êîòîðûå íå íàõîäÿòñÿ íà îäíîé ñòîðîíå (ïðîòèâîïîëîæíû ïî äèàãîíàëè).  ýòîì ñëó÷àå, îäíàêî, ïîíàäîáÿòñÿ ôóíêöèè (ãëîáàëüíûå) äëÿ âû÷èñëåíèÿ äëèí ñòîðîí òàêîãî ïðÿìîóãîëüíèêà.
ôóíêöèåé âûñøåãî ïîðÿäêà
Îêîí÷àòåëüíûå çàìå÷àíèÿ Õîòÿ êëàññû ñóùåñòâóþò âî ìíîãèõ äðóãèõ ÿçûêàõ ïðîãðàììèðîâàíèÿ, ïîíÿòèå êëàññà â ÿçûêå Haskell íåñêîëüêî îòëè÷àåòñÿ. Ýòî áûëî óæå ïîêàçàíî â ïðåäûäóùèõ ðàçäåëàõ. Çäåñü æå ñîáðàíû è ñòðóêòóðèðîâàíû âñå îòëè÷èÿ ïîíÿòèÿ ¾êëàññ¿ â ÿçûêå Haskell è â ïðî÷èõ îáúåêòíî-îðèåíòèðîâàííûõ ÿçûêàõ ïðîãðàììèðîâàíèÿ. Èòàê: 1. ßçûê Haskell ðàçäåëÿåò îïðåäåëåíèÿ êëàññîâ è èõ ìåòîäîâ, â òî âðåìÿ êàê òàêèå ÿçûêè, êàê C++ è Java, âìåñòå îïðåäåëÿþò ñòðóêòóðó äàííûõ è ìåòîäû äëÿ å¼ îáðàáîòêè.  îïðåäåëåíèè êëàññà â ÿçûêå Haskell äà¼òñÿ òîëüêî ñèãíàòóðà ìåòîäîâ, êîòîðûå äîëæíû áûòü ðåàëèçîâàíû â ýêçåìïëÿðàõ êëàññà. Âìåñòå ñ ýòèì âîçìîæíî íàïèñàíèå îïðåäåëåíèé òàêèõ ìåòîäîâ, èñïîëüçóåìûõ ïî óìîë÷àíèþ, êîãäà â òèïàõ-ýêçåìïëÿðàõ êëàññà ðåàëèçàöèè ìåòîäà íåò. Âîçìîæíîñòü ðåàëèçîâûâàòü ìåòîäû ïî óìîë÷àíèþ ïðåäîñòàâëÿþò äàëåêî íå âñå îáúåêòíî-îðèåíòèðîâàííûå ÿçûêè ïðîãðàììèðîâàíèÿ.
38
Îáúåêòíî-îðèåíòèðîâàííîå è ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå 2. Ìîæíî ñêàçàòü, ÷òî îïðåäåëåíèÿ ìåòîäîâ êëàññîâ â ÿçûêå Haskell áîëüøå âñåãî ñîîòâåòñòâóþò âèðòóàëüíûì ôóíêöèÿì ÿçûêà C++. Êàæäûé êîíêðåòíûé ýêçåìïëÿð êëàññà äîëæåí ïåðåîïðåäåëÿòü ìåòîäû êëàññà äëÿ èñïîëüçîâàíèÿ èõ íàä ñâîåé ñîáñòâåííîé ñòðóêòóðîé.  ñëó÷àå íåîáõîäèìîñòè è âîçìîæíîñòè ìîæíî âîñïîëüçîâàòüñÿ îïðåäåëåíèÿìè ìåòîäîâ, îïðåäåë¼ííûõ ïî óìîë÷àíèþ. 3. Ñ òî÷êè çðåíèÿ ÿçûêà Java áîëåå âñåãî êëàññû â ÿçûêå Haskell ïîõîæè íà èíòåðôåéñû. Êàê è îïðåäåëåíèå èíòåðôåéñà, êëàññû â ÿçûêå Haskell ïðåäîñòàâëÿþò òîëüêî ïðîòîêîë èñïîëüçîâàíèÿ îáúåêòà âìåñòî îïðåäåëåíèÿ ñàìèõ îáúåêòîâ. Íà ýòî æå íàìåêàåò è âîçìîæíîñòü ìíîæåñòâåííîãî íàñëåäîâàíèÿ êëàññîâ (â ÿçûêå Java ìîæíî ðåàëèçîâàòü â êàêîì-ëèáî êëàññå ñòîëüêî èíòåðôåéñîâ, ñêîëüêî ïîòðåáóåòñÿ, íî íàñëåäîâàòü ìîæíî òîëüêî îäèí êëàññ). Êðîìå òîãî, òèïû â ÿçûêå Haskell ìîãóò áûòü ýêçåìïëÿðàìè ñòîëüêèõ êëàññîâ, ñêîëüêèõ ïîòðåáóåòñÿ, ðàâíî êàê è â ÿçûêå Java. 4. ßçûê Haskell íå ïîääåðæèâàåò ñòèëü ïåðåãðóçêè ôóíêöèè, èñïîëüçóåìûé â C++, êîãäà ôóíêöèè ñ îäíèì è òåì æå èìåíåì ïîëó÷àþò äàííûå ðàçëè÷íûõ òèïîâ äëÿ îáðàáîòêè. Âìåñòî ýòîãî ïðèìåíÿåòñÿ òåõíîëîãèÿ èñïîëüçîâàíèÿ ñèíîíèìîâ èì¼í ôóíêöèé, êîãäà ðàçíûå ôóíêöèè ñ ðàçëè÷íûìè íàèìåíîâàíèÿìè äëÿ îáðàáîòêè ðàçíûõ äàííûõ â îïðåäåë¼ííûõ ñèòóàöèÿõ ìîãóò âûçûâàòüñÿ ïî îäèíàêîâîìó èäåíòèôèêàòîðó. Ýòî êàê ðàç è ðåàëèçóåòñÿ ïðè ïîìîùè êëàññîâ â ÿçûêå Haskell, êîòîðûå ïîçâîëÿþò èñïîëüçîâàòü â ýòîì ÿçûêå ïîëèìîðôèçì ¾ad hoc¿. 5.  êëàññàõ ÿçûêà Haskell íå ñóùåñòâóåò ïîíÿòèÿ êîíòðîëÿ çà äîñòóïîì íåò ïóáëè÷íûõ è çàùèù¼ííûõ ìåòîäîâ, òî åñòü íåò àíàëîãîâ ñëóæåáíûõ ñëîâ public, private è ò. ä. Âñå ìåòîäû â êëàññàõ ÿçûêà Haskell ÿâëÿþòñÿ îòêðûòûìè, áîëåå òîãî, îíè îïðåäåëåíû â êîíòåêñòå ìîäóëÿ, òî åñòü ÿâëÿþòñÿ äåêëàðàöèÿìè ñàìîãî âûñîêîãî óðîâíÿ. Îäíàêî ïðè ýòîì èìååòñÿ âîçìîæíîñòü èìïîðòèðîâàòü èç ìîäóëÿ òîëüêî òå ïðîãðàììíûå ñóùíîñòè, êîòîðûå òðåáóþòñÿ äëÿ ðåøåíèÿ çàäà÷è.
Âñ¼, ÷òî áûëî ðàññìîòðåíî â ïðåäûäóùèõ ðàçäåëàõ, à òàêæå â ïðåäûäóùèõ ðàçäåëàõ íà ýòó òåìó, ïîäâîäèò ê ìûñëè î òîì, ÷òî ïðè ïðîãðàììèðîâàíèè íà ÿçûêå Haskell èñïîëüçóþòñÿ âñåãî ïÿòü âèäîâ äåêëàðàöèé, ïÿòü ñóùíîñòåé: ôóíêöèè, òèïû, êëàññû òèïîâ, ýêçåìïëÿðû êëàññîâ è ìîäóëè. Âñå ýòè ñóùíîñòè ÿâëÿþòñÿ ñàìîñòîÿòåëüíûìè, òîëüêî îïîñðåäîâàííî ñâÿçàííûìè äðóã ñ äðóãîì. Ýòî îñîáåííî êàñàåòñÿ êëàññîâ è èõ ýêçåìïëÿðîâ ýòè ñóùíîñòè íå ñâÿçàíû íè äðóã ñ äðóãîì, íè ñ òèïàìè. Êëàññû è àëãåáðàè÷åñêèå òèïû äàííûõ ìîãóò áûòü îïèñàíû íåçàâèñèìî äðóã îò äðóãà, à ýêçåìïëÿð êëàññà ýòî ñóùíîñòü, ñâÿçûâàþùàÿ êëàññ è òèï. Òî, ÷òî çàïèñûâàåòñÿ â êîíòåêñòå (Class a =>), ÿâëÿåòñÿ âñåãî ëèøü îãðàíè÷åíèåì âèäà ¾äîëæåí ñóùåñòâîâàòü ýêçåìïëÿð óêàçàííîãî êëàññà Class äëÿ çàäàííîãî òèïà a¿. Ýòî çíà÷èò, ÷òî òèïû è èõ ðåàëèçàöèè äëÿ êëàññîâ ñóùåñòâóþò ðàçäåëüíî.  êà÷åñòâå ïðèìåðà ìîæíî ðàññìîòðåòü òàêóþ ñèòóàöèþ. Ïóñòü íåêòî â äàâíèå âðåìåíà ñîçäàë íåêèé òèï äàííûõ D è íåêîòîðóþ î÷åíü ïîëåçíóþ ôóíêöèþ f, êîòîðàÿ â ñâîåé ñèãíàòóðå èìååò îãðàíè÷åíèå (C a), ãäå a òèï îäíîãî èç àðãóìåíòîâ. Ïóñòü ýòè ñóùíîñòè îïðåäåëåíû â ðàçíûõ ìîäóëÿõ, êîòîðûå íèêàê íå ñâÿçàíû äðóã ñ äðóãîì. Ðàçðàáîò÷èêè, ñîçäàâàâøèå ýòè èñõîäíûå ñóùíîñòè, äàæå íå äîãàäûâàëèñü î âçàèìíîì ñóùåñòâîâàíèè. È âäðóã òðåòèé ðàçðàáîò÷èê ïîíÿë, ÷òî åìó íåîáõîäèìî èñïîëüçîâàòü ôóíêöèþ f íàä îáúåêòàìè òèïà D. ×òî äåëàòü? Íåò íèêàêîé íåîáõîäèìîñòè èñêàòü ïðîãðàììèñòà, ñîçäàâøåãî êëàññ C, ÷òîáû îí âêëþ÷èë â åãî îïðåäåëåíèå âîçìîæíîñòü ðàáîòàòü ñ òèïîì D. Äîñòàòî÷íî â ñâî¼ì ìîäóëå ðåàëèçîâàòü ýêçåìïëÿð ýòîãî êëàññà äëÿ òèïà D, ÷òî ïîçâîëèò èñïîëüçîâàòü çíà÷åíèÿ ýòîãî òèïà â ôóíêöèè f àâòîìàòè÷åñêè. Èñõîäíûå ìîäóëè îñòàþòñÿ íåòðîíóòûìè. Îïèñàííîå ñåðü¼çíîå ïðåèìóùåñòâî ñèñòåìû ìîäóëåé, êëàññîâ è èõ ýêçåìïëÿðîâ ÿçûêà Haskell.
Çàêëþ÷åíèå
39
Çàêëþ÷åíèå Òàêèì îáðàçîì â ðåçóëüòàòå ïîëó÷èëñÿ íåêîòîðûé ìîäóëü ñ îïèñàíèåì áàçîâûõ ìåòîäîâ è òèïîâ äëÿ ïðîâåäåíèÿ ãåîìåòðè÷åñêèõ ïðåîáðàçîâàíèé. Ýòîò ìîäóëü ìîæíî èñïîëüçîâàòü â êà÷åñòâå ¾çàòðàâêè¿ äëÿ ïîëíîöåííîé áèáëèîòåêè, ðåøàþùåé ðàçëè÷íûå ãåîìåòðè÷åñêèå çàäà÷è. Ïðè ýòîì íàäî ó÷åñòü, ÷òî ñàìè îïðåäåëåíèÿ èç ýòîãî ìîäóëÿ ÿâëÿþòñÿ äîñòàòî÷íî àáñòðàêòíûìè îíè íå ïðèâÿçàíû ê êàêîéëèáî ïðåäìåòíîé îáëàñòè. Ôóíêöèÿì è ìåòîäàì êëàññîâ áåçðàçëè÷íî, ÷òî îáñ÷èòûâàòü ãðàôè÷åñêèå îáðàçû íà ýêðàíå ìîíèòîðà (â ïèêñåëàõ) ëèáî àíàëèòè÷åñêèå ãåîìåòðè÷åñêèå çàäà÷è ñ êîîðäèíàòàìè ïðîèçâîëüíîé òî÷íîñòè âåçäå ñîçäàííûå ìåòîäû áóäóò ïðèìåíèìû. Ïðè îñîáîì æåëàíèè ìîäóëü äåéñòâèòåëüíî ìîæíî ðàçâèòü â íå÷òî áîëüøåå. Âäóì÷èâîìó æå ÷èòàòåëþ ðåêîìåíäóåòñÿ ïîäóìàòü è ñäåëàòü ïîäîáíûé ìîäóëü ðàáîòû ñ ãåîìåòðè÷åñêèìè ôèãóðàìè, óçëîâûå òî÷êè êîòîðûõ çàäàþòñÿ â ïîëÿðíûõ êîîðäèíàòàõ. Äëÿ ýòîãî ìîæíî èñïîëüçîâàòü ñîçäàííûé ìîäóëü, à òàêæå îïðåäåëåíèå òèïà:
data Floating a => PolarPoint a = PolarPoint {
angle :: a, distance : : a }  ñòàíäàðòíîì ìîäóëå Prelude îïèñàíà áîëüøàÿ èåðàðõèÿ êëàññîâ, êîòîðûå ïîäõîäÿò äëÿ îïðåäåëåíèÿ òèïîâ äàííûõ ðàçëè÷íîé ïðèðîäû îò ïåðå÷èñëèìûõ ìíîæåñòâ äî êîìïëåêñíûõ ÷èñåë è áîëåå ñëîæíûõ îáúåêòîâ. Ìîæíî îáðàòèòüñÿ ê ýòîìó ìîäóëþ äëÿ äîïîëíèòåëüíîãî èçó÷åíèÿ òîãî, ÷òî ïðåäñòàâëÿþò ñîáîé êëàññû â ÿçûêå Haskell.
Ââåäåíèå â λ-èñ÷èñëåíèå äëÿ íà÷èíàþùèõ Ñòàòüÿ áûëà ïîäãîòîâëåíà ê ïóáëèêàöèè â æóðíàëå ¾Ïîòåíöèàë¿, íî îïóáëèêîâàíà íå áûëà.
Äàííîå ýññå îïèñûâàåò îäíî èç ñàìûõ èíòåðåñíåéøèõ íàïðàâëåíèé äèñêðåòíîé ìàòåìàòèêè, íàïðÿìóþ ñâÿçàííîå ñ èíôîðìàòèêîé è ïðîãðàììèðîâàíèåì, òåîðèþ âû÷èñëåíèé. Âìåñòå ñ êîìáèíàòîðíîé ëîãèêîé, êîòîðàÿ áóäåò ðàññìîòðåíà â ñëåäóþùåì ðàçäåëå, λ-èñ÷èñëåíèå èçó÷àåò îáúåêòû è ñïîñîáû èõ êîìáèíèðîâàíèÿ äðóã ñ äðóãîì.  íàñòîÿùåì ðàçäåëå ðàññìàòðèâàåòñÿ íîòàöèÿ λ-èñ÷èñëåíèÿ äëÿ çàïèñè êîìáèíàòîðîâ, áîëåå ïðèáëèæåííàÿ ê ôóíêöèîíàëüíîìó ñòèëþ.
Ââåäåíèå Â ñâî¼ âðåìÿ âèäíûé ëîãèê Áåðòðàí Ðàññåë ïîøàòíóë ñàìè îñíîâû ìàòåìàòèêè, ïðèäóìàâ òàê íàçûâàåìûé ïàðàäîêñ áðàäîáðåÿ, êîòîðûé òðàäèöèîííî ôîðìóëèðóåòñÿ òàê:
 îäíîì ãîðîäå æèâ¼ò áðàäîáðåé. Îäíàæäû îí âûâåñèë íà äâåðè ñâîåé öèðþëüíè îáúÿâëåíèå: ¾Áðåþ òåõ è òîëüêî òåõ æèòåëåé ãîðîäà, êòî íå áðååòñÿ ñàì¿. Ñðàçó æå ó íåêîòîðûõ îñîáî ïðîçîðëèâûõ æèòåëåé ýòîãî ãîðîäà âîçíèê ðåçîííûé âîïðîñ: ¾À ìîæåò ëè ýòîò áðàäîáðåé ïîáðèòü ñàì ñåáÿ?¿ Ïîïûòêà îòâåòèòü íà ýòîò ïðîñòîé âîïðîñ ïðèâåëà ê íåîæèäàííûì ðåçóëüòàòàì. Âåäü åñëè ïåðåâåñòè ýòó èñòîðèþ íà ñòðîãèé ÿçûê ìàòåìàòèêè, òî ìîæíî óâèäåòü, ÷òî ýòà, êàçàëîñü áû, íåâèííàÿ èñòîðèÿ äåéñòâèòåëüíî ñâîäèò íà íåò âñå ìàòåìàòè÷åñêèå ïîñòðîåíèÿ. Äîñòàòî÷íî ëèøü ïîä áðàäîáðååì ïîíèìàòü íåêîòîðîå ìíîæåñòâî, âêëþ÷àþùåå â ñåáÿ âñå ïðî÷èå ìíîæåñòâà, êîòîðûå íå ÿâëÿþòñÿ ñîáñòâåííûìè ïîäìíîæåñòâàìè, êàê îñíîâíîé âîïðîñ èñòîðèè çâó÷èò ñëåäóþùèì îáðàçîì: ¾âêëþ÷àåò ëè ýòî ìíîæåñòâî â êà÷åñòâå ïîäìíîæåñòâà ñàìî ñåáÿ?¿ Äåéñòâèòåëüíî, åñëè ýòî ìíîæåñòâî âêëþ÷àåò ñàìî ñåáÿ â êà÷åñòâå ïîäìíîæåñòâà (áðàäîáðåé áðååòñÿ ñàì), òî îíî ïî ñâîåìó îïðåäåëåíèþ íå ìîæåò âêëþ÷àòü ñàìî ñåáÿ â êà÷åñòâå ïîäìíîæåñòâà (èáî áðàäîáðåé íå áðååò òåõ, êòî áðååòñÿ ñàì). Íî åñëè îíî íå âêëþ÷àåò ñàìî ñåáÿ â êà÷åñòâå ïîäìíîæåñòâà (áðàäîáðåé íå áðååòñÿ ñàì), òî îïÿòü æå, ïî îïðåäåëåíèþ, îíî äîëæíî âêëþ÷àòü â ñåáÿ ñàìî ñåáÿ (âåäü áðàäîáðåé áðååò òåõ, êòî íå áðååòñÿ ñàì). Ýòî ìíîæåñòâî ÿâëÿåòñÿ ïðîòèâîðå÷èâûì ïî ñâîåé ñóòè, à ïîòîìó è ñàìî ïîíÿòèå ìíîæåñòâà â åãî òðàäèöèîííîì íàèâíîì îïðåäåëåíèè ÿâëÿåòñÿ ïðîòèâîðå÷èâûì. Íàèâíîå îïðåäåëåíèå äàë â ñâî¼ âðåìÿ Ãåîðã Êàíòîð, íàçâàâ ìíîæåñòâîì ¾ìíîãîå, ïîíèìàåìîå êàê åäèíîå¿. Òàêîå íåôîðìàëüíîå îïðåäåëåíèå ìíîæåñòâà ñòîÿëî â îñíîâå ìíîãèõ ìàòåìàòè÷åñêèõ òåîðèé, à ïîòîìó íàõîäêà ýòîãî ïàðàäîêñà âåñüìà ñåðü¼çíî óäàðèëà ïî îñíîâàì ìàòåìàòèêè. Íî â ðàìêàõ íàèâíîé òåîðèè ìíîæåñòâ ðàçðåøèòü ýòîò ïàðàäîêñ íåâîçìîæíî, ïîýòîìó ïîñëå åãî ôîðìóëèðîâêè ìíîãèìè ìàòåìàòèêàìè áûëè ñäåëàíû ïîïûòêè
Íåôîðìàëüíîå îïèñàíèå òåîðèè
41
àíòèíîìèÿì
ôîðìàëèçîâàòü òåîðèþ ìíîæåñòâ, ñäåëàâ å¼ óñòîé÷èâîé ê ïîäîáíûì (òàê âïîñëåäñòâèè íàçâàëè ýòîò è ñõîæèå ñ íèì ïàðàäîêñû). Ïàðàäîêñ Ðàññåëà ñòàë ïðè÷èíîé òîãî, ÷òî â ñåðåäèíå 30-õ ãîäîâ XX âåêà Àëîíçî ×¼ð÷ íà÷àë ðàçðàáîòêó ñâîåé ôîðìàëèçàöèè òåîðèè ìíîæåñòâ ñ öåëüþ ðàçðåøèòü ïàðàäîêñ.  ðåçóëüòàòå åãî ðàáîòû íà ñâåò ïîÿâèëàñü íîòàöèÿ, êîòîðàÿ áûëà íàçâàíà èì λ . Ê ñîæàëåíèþ, îíà íå ïîìîãëà ðàçðåøèòü ïàðàäîêñ, íî, ê ñ÷àñòüþ, λ-èñ÷èñëåíèå ñàìî ïî ñåáå ñòàëî íîâûì íàïðàâëåíèåì â ìàòåìàòèêå, îòêðûâ ñåðü¼çíûå ïåðñïåêòèâû â èññëåäîâàíèÿõ âû÷èñëèòåëüíûõ ïðîöåññîâ.
-èñ÷èñëåíèå
Íåôîðìàëüíîå îïèñàíèå òåîðèè Ïîíÿòü λ-èñ÷èñëåíèå íå òàê óæ è ñëîæíî, äîñòàòî÷íî âíèìàòåëüíî èçó÷èòü ðàçðàáîòàííóþ íîòàöèþ. Äëÿ ýòîãî íå íàäî âäóìûâàòüñÿ â ïîñòðîåííóþ ôîðìàëüíóþ ñèñòåìó, à âñåãî ëèøü ïîíÿòü íåôîðìàëüíîå îïèñàíèå λ-èñ÷èñëåíèÿ. Èíòåðåñóþùèéñÿ æå ñóòüþ ÷èòàòåëü ñìîæåò ëåãêî íàéòè ñòðîãîå îïèñàíèå òåîðèè λ-èñ÷èñëåíèÿ â ðàçíûõ èñòî÷íèêàõ (íàïðèìåð, â êíèãàõ [1, 6]). Ñ íåôîðìàëüíîé æå òî÷êè çðåíèÿ λ-èñ÷èñëåíèå èçó÷àåò ôîðìóëû, ïîñòðîåííûå èç λ . Òàêèå ôîðìóëû ìîæíî ïîäâåðãàòü òð¼ì âèäàì ïðåîáðàçîâàíèé, êîòîðûå áóäóò îïèñàíû äàëåå.  ñâîþ î÷åðåäü, λ-òåðìû âûãëÿäÿò äîñòàòî÷íî ïðîñòî:
-òåðìîâ
1) åñëè x íåêîòîðàÿ ïåðåìåííàÿ èëè êîíñòàíòà, òî x λ-òåðì (áàçèñ èíäóêòèâíîãî îïðåäåëåíèÿ); 2) åñëè M è N íåêîòîðûå λ-òåðìû, òî (M N ) λ-òåðì (òåðì-àïïëèêàöèÿ); 3) åñëè x ïåðåìåííàÿ, à M λ-òåðì, òî (λx.M ) λ-òåðì (òåðì-àáñòðàêöèÿ); 4) äðóãèõ λ-òåðìîâ íåò. Êàê âèäíî, ïåðâûé ïóíêò îïðåäåëåíèÿ çàäà¼ò åãî áàçèñ. Âòîðîé ïóíêò îïðåäåëÿåò ïðèëîæåíèå òåðìîâ äðóã ê äðóãó (òàê íàçûâàåìàÿ ). Òðåòèé ïóíêò îïðåäåëåíèÿ îïèñûâàåò òàê íàçûâàåìóþ , â êîòîðîé ïåðåìåííàÿ x ñâÿçûâàåòñÿ ñ λ-òåðìîì M . Ïðèìåðû ïðîñòåéøèõ λ-òåðìîâ:
àáñòðàêöèþ
àïïëèêàöèÿ
• x ïðîñòàÿ ïåðåìåííàÿ; • (λx.x) λ-òåðì òîæäåñòâà; • ((λx.x)y) àïïëèêàöèÿ ïåðåìåííîé y ê λ-òåðìó òîæäåñòâà è ò. ä. Äàííîå îïðåäåëåíèå âåñüìà íàïîìèíàåò îïðåäåëåíèå . Äåéñòâèòåëüíî, â êîìáèíàòîðíîé ëîãèêå îòñóòñòâóåò àáñòðàêöèÿ, à âñ¼ îñòàëüíîå âûãëÿäèò àáñîëþòíî òàê æå (áîëåå ïîäðîáíî êîìáèíàòîðíàÿ ëîãèêà áóäåò îïèñàíà â ñëåäóþùåì ðàçäåëå). Íî åñëè âñïîìíèòü èñòîðèþ ñîçäàíèÿ êîìáèíàòîðíîé ëîãèêè, òî ìîæíî ïîíÿòü, ÷òî Õàñêåëë Êàððè ïðè å¼ ñîçäàíèè ðóêîâîäñòâîâàëñÿ ïðèíöèïîì óäàëåíèÿ èç ðàññìîòðåíèÿ , òî åñòü àáñòðàêöèè. Äðóãèìè ñëîâàìè, λ-òåðìû ïðåäñòàâëÿþò ñîáîé êîìáèíàòîðû, òîëüêî çàïèñàííûå äîñòàòî÷íî ñâîåîáðàçíûì ñïîñîáîì. Äåéñòâèòåëüíî, åñëè ðàññìîòðåòü êîìáèíàòîðíûé S, K, I, òî âûðàæåíèå åãî êîìáèíàòîðîâ ÷åðåç λ-íîòàöèþ áóäåò âûãëÿäåòü òàê:
êîìáèíàòîðà
ñâÿçàííûõ ïåðåìåííûõ
áàçèñ
S ≡ (λx.(λy.(λz.(xz)(yz))))
(S)
K ≡ (λx.(λy.x))
(K)
I ≡ (λx.x)
( I)
42
Ââåäåíèå â λ-èñ÷èñëåíèå äëÿ íà÷èíàþùèõ
×åñòíî ãîâîðÿ, íàëèöî âåñüìà ñîìíèòåëüíîå ïðåèìóùåñòâî, òàê êàê âîñïðèíèìàåìîñòü ïîäîáíûõ çàïèñåé äàëåêà îò èäåàëüíîé.  ïåðâóþ î÷åðåäü â ãëàçà áðîñàåòñÿ äîñòàòî÷íî áîëüøîå êîëè÷åñòâî ñêîáîê, îäíàêî ñ íèì ðàçîáðàòüñÿ ïðîùå âñåãî.  λ-èñ÷èñëåíèè, åñòåñòâåííî, ïðèíÿòî ñîãëàøåíèå î ïðîïóñêå ëèøíèõ ñêîáîê, êîòîðûå ìîæíî âîññòàíîâèòü ïî îïðåäåë¼ííîìó ïðàâèëó. Òàê, â àïïëèêàöèÿõ ñêîáêè âîññòàíàâëèâàþòñÿ ïî àññîöèàòèâíîñòè âïðàâî, òî åñòü çàïèñü ((M N )Q) òîæäåñòâåííà ïðîñòîìó M N Q.  àáñòðàêöèÿõ æå, íàîáîðîò, ñêîáêè ìîæíî âîññòàíîâèòü ïî àññîöèàöèè âëåâî, à ìíîæåñòâåííûå ñèìâîëû (λ) ìîæíî ñâåñòè â îäèí, òîãäà çàïèñü (λx.(λy.x)) áóäåò òîæäåñòâåííà çàïèñè λxy.x.  ýòîì ñëó÷àå áàçîâûå êîìáèíàòîðû â λ-íîòàöèè ïîëó÷àþò ñâîé òðàäèöèîííûé âèä:
S ≡ λxyz.xz(yz)
(S)
K ≡ λxy.x
(K)
I ≡ λx.x
(I)
Íî ÷òî ñ ýòèì äåëàòü äàëüøå? Âåäü óïðîùåíèå çàïèñè íèñêîëüêî íå ñêàçûâàåòñÿ íà ïðèìåíèìîñòè ñàìîé òåîðèè. Äåéñòâèòåëüíî, åñëè â êîìáèíàòîðíîé ëîãèêå èìåëàñü îïåðàöèÿ , òî è â λ-èñ÷èñëåíèè äîëæíî áûòü ÷òî-òî ïîõîæåå. Òàê è åñòü, â λ-èñ÷èñëåíèè èìååòñÿ àáñîëþòíî òàêàÿ æå åäèíñòâåííàÿ îïåðàöèÿ, êîòîðàÿ äåéñòâóåò ïðè àïïëèêàöèè λ-òåðìîâ äðóã ê äðóãó. Åñëè ïîäõîäèòü íåôîðìàëüíî, òî ìîæíî ñêàçàòü, ÷òî ëþáîé λ-òåðì ¾îæèäàåò¿ äëÿ ïðèìåíåíèÿ ê íåìó ñòîëüêèõ îáúåêòîâ (äðóãèõ λ-òåðìîâ), ñêîëüêî ñâÿçàííûõ ïåðåìåííûõ íàõîäèòñÿ â åãî . Òàê, ê ïðèìåðó, λ-òåðì S îæèäàåò òðè îáúåêòà (äëÿ îçíà÷èâàíèÿ ïåðåìåííûõ x, y è z ), λ-òåðì K äâà îáúåêòà è ò. ä. Âñ¼, êàê â êîìáèíàòîðíîé ëîãèêå. Ïðè ïðèìåíåíèè íåêîòîðîãî îáúåêòà ê λ-òåðìó ïðîèñõîäèò ïðèìåíÿåìîãî îáúåêòà âìåñòî ñàìîé ïåðâîé ñâÿçàííîé ïåðåìåííîé. Äðóãèìè ñëîâàìè, åñëè ê λ-òåðìó S ïðèìåíèòü íåêîòîðûé îáúåêò O, òî â ðåçóëüòàòå ýòîãî ïðèìåíåíèÿ îñòàíåòñÿ λ-òåðì: λyz.Oz(yz). Òî åñòü â ñëó÷àå ïðîèçâîëüíîé àáñòðàêöèè (λx.M ) ïðè ïðèìåíåíèè ê íåé íåêîòîðîãî îáúåêòà O â ðåçóëüòàòå ïîëó÷èòñÿ íîâûé λ-òåðì, êîòîðûé âû÷èñëÿåòñÿ ïðè ïîìîùè çàìåíû âñåõ âõîæäåíèé ïåðåìåííîé x â λ-òåðìå M íà îáúåêò O. Äàííûé ôàêò çàïèñûâàåòñÿ ñëåäóþùèì îáðàçîì:
ïðèìåíåíèÿ
ñèãíàòóðå
ïîäñòàíîâêà
(λx.M )O ⇒ M [x ← O]
(3)
Ýòó çàïèñü ëåã÷å âñåãî ïîíÿòü íà ïðîñòåéøèõ ïðèìåðàõ:
• (λx.x)5 ⇒ x[x ← 5] ⇒ 5. • ((λxy.x + y)2)3 ⇒ (x + y)[x ← 2][y ← 3] ⇒ 2 + 3. • (λx.xx)(λz.zz) ⇒ (xx)[x ← (λz.zz)] ⇒ (λz.zz)(λz.zz). È ò. ä.  ýòîì è çàêëþ÷àåòñÿ ñàìà ñóòü ïîäñòàíîâêè. È òåïåðü âèäíî íåêîòîðîå îòëè÷èå λ-èñ÷èñëåíèÿ îò êîìáèíàòîðíîé ëîãèêè.  ýòîé íîòàöèè ÿñíî âèäíî, ñêîëüêî îïåðàíäîâ èìååòñÿ ó êàæäîãî λ-òåðìà, à òàêæå êàêîé íîâûé λ-òåðì è ñêîëüêî îïåðàíäîâ ó íåãî îñòàíåòñÿ â ðåçóëüòàòå . Äðóãèìè ñëîâàìè, êîìáèíàòîðíàÿ ëîãèêà ìîæåò èñïîëüçîâàòüñÿ êàê ñðåäñòâî äëÿ ñîêðàùåíèÿ çàïèñè λ-òåðìîâ, à â îñòàëüíîì ýòè òåîðèè àáñîëþòíî ðàâíîçíà÷íû. Òî åñòü êîìáèíàòîðíàÿ ëîãèêà ââîäèò îïðåäåë¼ííûå íàèìåíîâàíèÿ äëÿ íåêîòîðûõ íàèáîëåå ÷àñòî èñïîëüçóåìûõ λ-òåðìîâ.
÷àñòè÷íîãî ïðèìåíåíèÿ
Íåêîòîðûå äîïîëíåíèÿ
43
Íåêîòîðûå äîïîëíåíèÿ  öåëÿõ âíåñåíèÿ ðàçíîîáðàçèÿ â ñóõóþ òåîðèþ ìîæíî äîïîëíèòü λ-èñ÷èñëåíèå íåêîòîðûìè íå âõîäÿùèìè â áàçîâûé àëôàâèò ñèìâîëàìè.  ïåðâóþ î÷åðåäü áûëî áû âåñüìà èíòåðåñíî ââåñòè â λ-èñ÷èñëåíèå ðàçëè÷íûå ìàòåìàòè÷åñêèå çíàêè, ÷òîáû èìåòü âîçìîæíîñòü çàïèñûâàòü â êà÷åñòâå λ-òåðìîâ ðàçíûå ôîðìóëû. Ýòî ïîçâîëèò ïîâûñèòü ñòåïåíü ïðèìåíèìîñòè äàííîé òåîðèè, äàâ âîçìîæíîñòü çàïèñûâàòü â âèäå λ-òåðìîâ ìàòåìàòè÷åñêèå ôóíêöèè. Íàïðèìåð, êàê âûðàçèòü ÷åðåç λ-íîòàöèþ îáû÷íîå àðèôìåòè÷åñêîå ñëîæåíèå ÷èñåë? Äîñòàòî÷íî ïðîñòî:
(+) ≡ (λxy.x + y)
(4)
 ýòîì ñëó÷àå î÷åíü õîðîøî âèäíî âåñüìà âàæíîå ñâîéñòâî ôóíêöèîíàëüíîãî ñòèëÿ ïðîãðàììèðîâàíèÿ ÷àñòè÷íîå ïðèìåíåíèå. Âåäü â øêîëå, ê ïðèìåðó, èçó÷àþò, ÷òî ó îïåðàöèè ñëîæåíèÿ èìåþòñÿ äâà îïåðàíäà, è äëÿ ïîëó÷åíèÿ îïðåäåë¼ííîãî ðåçóëüòàòà íåîáõîäèìî ïåðåäàòü îïåðàöèè ñëîæåíèÿ èìåííî äâà ÷èñëà.  ïðîòèâíîì ñëó÷àå ïîëó÷àåòñÿ óðàâíåíèå, êîòîðîå âîçìîæíî ðàçðåøèòü òîëüêî ïðè íåêîòîðûõ óñëîâèÿõ.  λ-èñ÷èñëåíèè äàæå ïðè ïðèìåíåíèè îäíîãî îçíà÷åííîãî îïåðàíäà â ôîðìóëå (4) â ðåçóëüòàòå ïîëó÷àåòñÿ âïîëíå îïðåäåë¼ííàÿ ôóíêöèÿ, âûðàæåííàÿ ïðè ïîìîùè λ-òåðìà. Íàïðèìåð:
(λxy.x + y)7 = λy.7 + y Òàêèì îáðàçîì, ïîëó÷åí íîâûé λ-òåðì, ôóíêöèîíàëüíîñòü êîòîðîãî çàêëþ÷àåòñÿ â òîì, ÷òî îí ïðèáàâëÿåò 7 ê ñâîåìó åäèíñòâåííîìó àðãóìåíòó. Ïîäîáíîå ìîæíî äåëàòü ñ ëþáûìè ìàòåìàòè÷åñêèìè ôîðìóëàìè, êîòîðûå õî÷åòñÿ îôîðìèòü â âèäå λ-òåðìîâ, òî åñòü ôóíêöèé ñ âîçìîæíîñòüþ ÷àñòè÷íîãî ïðèìåíåíèÿ. Áîëåå òîãî, àáñîëþòíî òàêèì æå ñïîñîáîì ìîæíî âíåäðÿòü â λ-èñ÷èñëåíèå ðàçíûå êîíñòðóêöèè ÿçûêîâ ïðîãðàììèðîâàíèÿ, ÷òîáû èìåòü âîçìîæíîñòü äëÿ îïèñàíèÿ áîëåå ñëîæíûõ ôóíêöèé (íàïðèìåð, ñ âåòâëåíèåì èëè èòåðàòèâíûìè ïðîöåññàìè). Âîò êàê, ê ïðèìåðó, ìîæåò âûãëÿäåòü ôóíêöèÿ äëÿ âû÷èñëåíèÿ àáñîëþòíîãî çíà÷åíèÿ ñâîåãî àðãóìåíòà:
abs ≡ λx.if (x > 0) then x else (−x) Íåîáõîäèìî îñîáî ïîä÷åðêíóòü, ÷òî â ¾÷èñòîì¿ λ-èñ÷èñëåíèè âñåãî ýòîãî íåò, è ââåä¼ííûå â ýòîì ðàçäåëå äîïîëíåíèÿ ÿâëÿþòñÿ íåêîòîðîé âîëüíîñòüþ.  ñâîþ î÷åðåäü, àïïàðàò λ-èñ÷èñëåíèÿ ïðåäîñòàâëÿåò âñå âîçìîæíîñòè äëÿ êîäèðîâàíèÿ ðàçëè÷íûõ ìàòåìàòè÷åñêèõ îáúåêòîâ (íàòóðàëüíûå ÷èñëà, îïåðàöèè è ôóíêöèè íàä íèìè, áóëåâñêèå çíà÷åíèÿ èñòèííîñòè, ëîãè÷åñêèå îïåðàöèè è ìíîãîå, ìíîãîå äðóãîå íåêîòîðûå ñïîñîáû êîäèðîâàíèÿ áóäóò ðàññìîòðåíû â ÷åòâ¼ðòîì ïîäðàçäåëå).
Ðåäóêöèÿ êàê ñòðàòåãèÿ âû÷èñëåíèé  íà÷àëå ïåðâîãî ïîäðàçäåëà óïîìèíàëèñü òðè âèäà ïðåîáðàçîâàíèé, êîòîðûå ìîãóò ïðèìåíÿòüñÿ ê λ-òåðìàì. Ïî ñóòè, îäèí âèä ïðåîáðàçîâàíèé óæå áûë ðàññìîòðåí ýòî ïîäñòàíîâêà â êà÷åñòâå îïåðàíäà êàêîãî-ëèáî îáúåêòà, òî åñòü ñíÿòèå óðîâíÿ àáñòðàêöèè λ-òåðìà. Ïðèøëî âðåìÿ áîëåå äåòàëüíî ðàññìîòðåòü âñå ïðåîáðàçîâàíèÿ, ÷òîáû òîíüøå ïðî÷óâñòâîâàòü ñìûñë λ-èñ÷èñëåíèÿ. Êàæäîå èç ðàññìàòðèâàåìûõ ïðåîáðàçîâàíèé â ðàìêàõ λ-èñ÷èñëåíèÿ íàçûâàåòñÿ . Òàêèì îáðàçîì, ââîäÿòñÿ òðè òèïà ðåäóêöèè:
ðåäóêöèåé
1) α-ðåäóêöèÿ (èíîãäà íàçûâàåìàÿ α-êîíâåðñèåé) çàìåíà èì¼í ïåðåìåííûõ ñ öåëüþ èçáåæàòü , òî åñòü ñîâïàäåíèÿ èì¼í ïåðåìåííûõ â λ-òåðìå, â êîòîðûé ïðîèçâîäèòñÿ ïîäñòàíîâêà (íàïðèìåð, ïðè ïðèìåíåíèè (λxy.x + y)y âîçíèêíåò êîëëèçèÿ ïî ïåðåìåííîé y , òàê êàê â ðåçóëüòàòå
êîëëèçèè èì¼í
44
Ââåäåíèå â λ-èñ÷èñëåíèå äëÿ íà÷èíàþùèõ ïîëó÷èòñÿ ÿâíî îøèáî÷íûé λ-òåðì (λy.y + y ) äëÿ òîãî ÷òîáû ýòîãî èçáåæàòü, íåîáõîäèìî â èñõîäíîì λ-òåðìå èçìåíèòü èìÿ ïåðåìåííîé y ); 2) β -ðåäóêöèÿ îñíîâíîå ïðåîáðàçîâàíèå λ-òåðìîâ, êîòîðîå óæå íåîäíîêðàòíî ðàññìîòðåíî ðàíåå, çàêëþ÷àåòñÿ â ïîäñòàíîâêå íåêîòîðîãî îáúåêòà â êà÷åñòâå àðãóìåíòà è ñíÿòèè òåì ñàìûì îäíîãî óðîâíÿ àáñòðàêöèè; 3) η -ðåäóêöèÿ äîïîëíèòåëüíîå ïðåîáðàçîâàíèå, êîòîðîå íå íåîáõîäèìî è çàïðåùåíî â íåêîòîðûõ îñîáûõ òèïàõ λ-èñ÷èñëåíèÿ. Åãî ñóòü çàêëþ÷àåòñÿ â ïðåäïîëîæåíèè î òîì, ÷òî λ-òåðìû λx.M x è M òîæäåñòâåííî ðàâíû.  íåêîòîðûõ îñîáåííûõ ñëó÷àÿõ ýòî äîâîëüíî ñèëüíîå ïðåäïîëîæåíèå, íî â îáû÷íîì λ-èñ÷èñëåíèè ïåðâûé λ-òåðì ìîæíî ñâîáîäíî çàìåíÿòü íà âòîðîé. α
β
η
Âñå òèïû ðåäóêöèè â ôîðìóëàõ îáîçíà÷àþòñÿ ïðè ïîìîùè ñòðåëîê ñ óêàçàíèåì òèïà: (→), (→) è (→).  ýòîì ðÿäó äëÿ β -ðåäóêöèè ñäåëàíî èñêëþ÷åíèå: òàê êàê ýòî îñíîâíîé òèï ðåäóêöèè, òî å¼ ìîæíî îáîçíà÷àòü ïðîñòîé ñòðåëêîé (→). Íåñêîëüêî ïîñëåäîâàòåëüíûõ ðåäóêöèé îáû÷íî îáîçíà÷àþòñÿ ñòðåëêîé ñ äâóìÿ íàêîíå÷íèêàìè: (). ×òî æå ïðåäñòàâëÿåò ñîáîé ðåäóêöèÿ? Âäóì÷èâûé ÷èòàòåëü óæå äîëæåí áûë ïîíÿòü, ÷òî ýòî ìîäåëèðîâàíèå ôóíêöèîíàëüíûõ âû÷èñëåíèé.  λ-òåðìû ïîäñòàâëÿþòñÿ îïðåäåë¼ííûå çíà÷åíèÿ, ïîñëå ÷åãî ïðîèçâîäÿòñÿ ñàìè âû÷èñëåíèÿ. Ýòîò ïðîöåññ ïðîèñõîäèò äî ïîëó÷åíèÿ îêîí÷àòåëüíîãî ðåçóëüòàòà (åñëè ýòî âîçìîæíî), êîòîðûé ïðåäñòàâëÿåò ñîáîé òàêîé æå λ-òåðì. Åãî èíòåðïðåòàöèÿ óæå çàâèñèò îò êîíêðåòíîé îáëàñòè ïðèìåíåíèÿ òåîðèè. Ðåäóêöèÿ ââîäèò ìåæäó λ-òåðìàìè îòíîøåíèå ðåäóöèðóåìîñòè, êîòîðîå îáëàäàåò ñâîéñòâàìè , è , òî åñòü ïî ñâîåé ñóòè ÿâëÿåòñÿ îòíîøåíèåì ýêâèâàëåíòíîñòè. Äðóãèìè ñëîâàìè, âñ¼ ìíîæåñòâî âîçìîæíûõ λ-òåðìîâ ðàçáèâàåòñÿ íà êëàññû ýêâèâàëåíòíîñòè, âíóòðè êîòîðûõ λ-òåðìû ìîãóò áûòü ïðåîáðàçîâàíû äðóã ê äðóãó ïðè ïîìîùè ðåäóêöèè. Ïðè ýòîì âî ìíîãèõ òàêèõ êëàññàõ ýêâèâàëåíòíîñòè ñóùåñòâóåò îäèí λ-òåðì, êîòîðûé íå ìîæåò áûòü ïîäâåðãíóò íè β -, íè η -ðåäóêöèè (ëþáîé λ-òåðì ìîæåò áûòü ïîäâåðãíóò α-êîíâåðñèè íåîãðàíè÷åííîå ÷èñëî ðàç). Ãîâîðÿò, ÷òî òàêîé òåðì íàõîäèòñÿ â .  λ-èñ÷èñëåíèè ñóùåñòâóåò îñíîâíàÿ òåîðåìà ( ), êîòîðàÿ óòâåðæäàåò, ÷òî åñëè íîðìàëüíàÿ ôîðìà ñóùåñòâóåò, òî îíà åäèíñòâåííà. Ýòî î÷åíü âàæíàÿ òåîðåìà, êîòîðàÿ, â ïðèíöèïå, îïðåäåëèëà ïðèìåíèìîñòü λ-èñ÷èñëåíèÿ êàê òåîðèè âû÷èñëåíèé. Äîêàçàòåëüñòâî ýòîé òåîðåìû íå î÷åíü ñëîæíîå, íî çàíèìàåò íå îäíó ñòðàíèöó òåêñòà, ïîýòîìó åãî ðàññìîòðåíèå âûõîäèò çà ðàìêè äàííîé êíèãè. Îäíèì èç âàæíûõ ñëåäñòâèé òåîðåìû ×¼ð÷à-Ðîññåðà ÿâëÿåòñÿ òî, ÷òî ïðè íàëè÷èè íîðìàëüíîé ôîðìû íå âàæíî, êàêèì îáðàçîì ïðîâîäèëèñü âû÷èñëåíèÿ äëÿ å¼ ïîëó÷åíèÿ. Ýòî ïðåäîñòàâëÿåò èññëåäîâàòåëÿì âîçìîæíîñòü ðàçðàáîòêè ðàçëè÷íûõ ñòðàòåãèé ðåäóêöèè, êîòîðûå çàêëþ÷àþòñÿ â âûáîðå îïðåäåë¼ííûõ ïðàâèë, êîòîðûì ïîä÷èíÿåòñÿ ïðîöåññ ðåäóêöèè. Èçíà÷àëüíî áûëè ðàçðàáîòàíû äâå ðåäóêöèîííûå ñòðàòåãèè: è . Íîðìàëüíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ çàêëþ÷àåòñÿ â òîì, ÷òî íà êàæäîì øàãå ðåäóêöèè âûáèðàåòñÿ ñàìûé ëåâûé è ñàìûé âíåøíèé λ-òåðì, åñëè âîñïðèíèìàòü åãî áóêâàëüíî è íå ïðèíèìàòü âî âíèìàíèå ñêîáêè. Ðåäóêöèÿ ñàìîãî ëåâîãî λ-òåðìà ïðåäïîëàãàåò, ÷òî â λ-âûðàæåíèè (M N ) ïåðâûì ðåäóöèðóåòñÿ λ-òåðì M . Ðåäóêöèÿ ñàìîãî âíåøíåãî λ-òåðìà ïðåäïîëàãàåò, ÷òî ñíà÷àëà ðåäóöèðóåòñÿ âûðàæåíèå (λx.M )N ïåðåä ðåäóêöèåé λ-òåðìîâ M èëè N . Êðîìå òîãî, åñëè â ïðîöåññå ðåäóêöèè âûðàæåíèÿ èñïîëüçóåòñÿ îïöèîíàëüíàÿ η -ðåäóêöèÿ, òî îíà ïðîâîäèòñÿ ïîñëå âñåõ β -ðåäóêöèé. Ïîä àïïëèêàòèâíîé ðåäóêöèîííîé ñòðàòåãèåé ïîíèìàåòñÿ òàêàÿ ñòðàòåãèÿ, ïðè êîòîðîé íà êàæäîì øàãå ðåäóêöèè âûáèðàåòñÿ òàêîé λ-òåðì, âíóòðè êîòîðîãî íåâîçìîæíî ïðîâåñòè β -ðåäóêöèþ. Íàïðèìåð, â λ-âûðàæåíèè (λx.((λz.zz)x))y ïåðâûì ðåäóöèðóåòñÿ λ-òåðì (λz.zz)x. Äîêàçàíî, ÷òî íîðìàëüíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ ãàðàíòèðóåò ïîëó÷åíèå íîðìàëüíîé ôîðìû λ-òåðìà, åñëè îíà ñóùåñòâóåò. Ñ äðóãîé ñòîðîíû, îáû÷íî àïïëèêàòèâíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ äîñòèãàåò íîðìàëüíîé ôîðìû áûñòðåå (õîòÿ è íå âñåãäà), íî îíà íå ãàðàíòèðóåò ïîëó÷åíèÿ íîðìàëüíîé
èäåìïîòåíòíîñòè ñèììåòðè÷íîñòè òðàíçèòèâíîñòè
íîðìàëüíîé ôîðìå òåîðåìà ×¼ð÷à-Ðîññåðà
íîðìàëüíàÿ àïïëèêàòèâíàÿ
Ðåäóêöèÿ êàê ñòðàòåãèÿ âû÷èñëåíèé
45
ôîðìû â ïðèíöèïå. Íàïðèìåð, ïðè ïîïûòêå ðåäóöèðîâàòü λ-òåðì (λy.x)Ω, ãäå Ω = (λx.xx)(λx.xx), íîðìàëüíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ ïðèâåä¼ò ê ïîëó÷åíèþ íîðìàëüíîé ôîðìû, à àïïëèêàòèâíàÿ íåò.  ïðîãðàììèðîâàíèè íîðìàëüíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ ñîîòâåòñòâóåò . Òî åñòü àðãóìåíò âûðàæåíèÿ íå âû÷èñëÿåòñÿ äî òåõ ïîð, ïîêà ê íåìó íå âîçíèêíåò îáðàùåíèÿ â òåëå âûðàæåíèÿ. Àïïëèêàòèâíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ ñîîòâåòñòâóåò , êîãäà ïåðåä ïåðåäà÷åé ôàêòè÷åñêîãî ïàðàìåòðà â ôóíêöèþ åãî çíà÷åíèå ïðåäâàðèòåëüíî âû÷èñëÿåòñÿ. Äîïîëíèòåëüíî î ñòðàòåãèÿõ âû÷èñëåíèé ìîæíî ïðî÷èòàòü â [9, 20]. Îñòà¼òñÿ ðàññìîòðåòü íåñêîëüêî ïðèìåðîâ ïðîâåäåíèÿ ðåäóêöèè ðàçëè÷íûõ λ-òåðìîâ (ðåäóöèðóåìûé íà êàæäîì øàãå λ-òåðì ïîä÷¼ðêèâàåòñÿ äëÿ íàãëÿäíîñòè). . .
âûçîâó ïî èìåíè
âûçîâó ïî çíà÷åíèþ
Ðåäóêöèÿ λ-òåðìà (λx.xyxx)((λz.z)w): 1)
Íîðìàëüíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ: (λx.xyxx)((λz.z)w) → → ((λz.z)w)y((λz.z)w)((λz.z)w) → → wy((λz.z)w)((λz.z)w) → → wyw((λz.z)w) → → wyww.
2)
Àïïëèêàòèâíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ: (λx.xyxx)((λz.z)w) → → (λx.xyxx)w → → wyww.
Ðåäóêöèÿ λ-òåðìà (λxyz.xz(yz))(λx.xx)(λx.xx)z : 1)
Íîðìàëüíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ: (λxyz.xz(yz))(λx.xx)(λx.xx)z → → (λyz.(λx.xx)z(yz))(λx.xx)z → → (λz.(λx.xx)z((λx.xx)z))z → → (λx.xx)z((λx.xx)z) → → zz((λx.xx)z) → → zz(zz).
2)
Àïïëèêàòèâíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ: (λxyz.xz(yz))(λx.xx)(λx.xx)z → → (λyz.(λx.xx)z(yz))(λx.xx)z → → (λyz.zz(yz))(λx.xx)z → → (λz.zz((λx.xx)z))z → → (λz.zz(zz))z → → zz(zz).
46
Ââåäåíèå â λ-èñ÷èñëåíèå äëÿ íà÷èíàþùèõ
Ðåäóêöèÿ λ-òåðìà (λy.x)Ω: 1)
Íîðìàëüíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ: (λy.x)Ω → → (λy.x)[y ← Ω] → → x.
2)
Àïïëèêàòèâíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ: (λy.x)Ω → → (λy.x)((λx.xx)(λx.xx)) → → (λy.x)((λx.xx)(λx.xx)) → → ...
Ïîñëåäíèé ïðèìåð êàê ðàç è ïîêàçûâàåò, ÷òî íîðìàëüíàÿ ðåäóêöèîííàÿ ñòðàòåãèÿ ïîçâîëÿåò ïîëó÷èòü íîðìàëüíóþ ôîðìó, â òî âðåìÿ êàê àïïëèêàòèâíàÿ ñòðàòåãèÿ ¾çàöèêëèâàåòñÿ¿ íà ðåäóêöèè îäíîãî è òîãî æå λ-òåðìà.
Ïðèìåðû êîäèðîâàíèÿ äàííûõ è ôóíêöèé Êàê óæå ãîâîðèëîñü, àïïàðàò λ-èñ÷èñëåíèÿ ïîçâîëÿåò âíóòðè âåñüìà îãðàíè÷åííûõ ðàìîê êîäèðîâàòü ðàçëè÷íûå òèïû äàííûõ è îïåðàöèè íàä íèìè.  ñëåäóþùåì ðàçäåëå, êîòîðûé ïîñâÿù¼í êîìáèíàòîðíîé ëîãèêå, áóäóò ïðèâåäåíû ðàñøèðåííûå ïðèìåðû òàêîãî êîäèðîâàíèÿ ïðè ïîìîùè êîìáèíàòîðîâ. Çäåñü æå ìîæíî ïðèâåñòè ëèøü íåêîòîðûå ïðîñòûå ïðèìåðû êîäèðîâàíèÿ èíôîðìàöèè ïîñðåäñòâîì λ-òåðìîâ. Îäíàêî èç-çà òîãî, ÷òî â λ-èñ÷èñëåíèè èñïîëüçóþòñÿ ñâÿçàííûå ïåðåìåííûå, ìíîãîå êîäèðóåòñÿ íåñêîëüêî èíûì ñïîñîáîì. Äëÿ ýòèõ öåëåé âïîëíå äîñòàòî÷íî ðàññìîòðåòü òîëüêî , òàê êàê ýòîò ôîðìàëèçì ïîìîãàåò ïîëíîñòüþ ïîíÿòü òî, êàê ïðè ïîìîùè λ-èñ÷èñëåíèÿ êîäèðóþòñÿ ðàçëè÷íûå äàííûå è ôóíêöèè äëÿ èõ îáðàáîòêè. Ïîñëå òîãî êàê ñòàëî ÿñíî, ÷òî λ-èñ÷èñëåíèå ÿâëÿåòñÿ âåñüìà èíòåðåñíîé íàóêîé, Àëîíçî ×¼ð÷ íà÷àë èçó÷åíèå ðàçëè÷íûõ àñïåêòîâ ýòîãî íàïðàâëåíèÿ íàó÷íîé ìûñëè.  ïåðâóþ î÷åðåäü îí ïîïûòàëñÿ âûðàçèòü ÷åðåç λ-òåðìû ðàçëè÷íûå ìàòåìàòè÷åñêèå îáúåêòû. Îäíèì èç áàçîâûõ îáúåêòîâ èçó÷åíèÿ ìàòåìàòèêè ÿâëÿåòñÿ íàòóðàëüíîå ÷èñëî, ïîýòîìó áûëà ïðîèçâåäåíà ïîïûòêà çàêîäèðîâàòü òàêèå ÷èñëà. Íåîáõîäèìî íàïîìíèòü, ÷òî äëÿ êîäèðîâàíèÿ ÷èñåë èëè ïîäîáíûõ èì îáúåêòîâ ìîæíî èñïîëüçîâàòü ëþáîé ñïîñîá âûðàæåíèÿ, ãëàâíîå, ÷òîáû ïîòîì íà ïîñòðîåííûõ λ-òåðìàõ ìîæíî áûëî áû îïðåäåëèòü ïðèåìëåìûå îïåðàöèè, òîæäåñòâåííûå òåì, ÷òî èìåþòñÿ äëÿ ÷èñåë. Ïîýòîìó, ñîáñòâåííî, ñïîñîáîâ êîäèðîâàíèÿ ÷èñåë ñóùåñòâóåò ìíîæåñòâî. Ïåðâûì æå íà ýòîì ïîïðèùå áûë À. ×¼ð÷, ñîçäàâ ñëåäóþùèå îïðåäåëåíèÿ:
íóìåðàëû ×¼ð÷à
0 ≡ λf x.x. 1 ≡ λf x.f x. 2 ≡ λf x.f (f x). ... n ≡ λf x. f (. . . (f x) . . .). | {z } nðàç
Êàæäûé íóìåðàë ×¼ð÷à ÿâëÿåòñÿ èòåðàòîðîì, êîòîðûé ñîîòâåòñòâóþùåå ÷èñëî ðàç ïðèìåíÿåò ôóíêöèþ f ê ðåçóëüòàòó ïðåäûäóùåãî ïðèìåíåíèÿ ýòîé ôóíêöèè. Ïîýòîìó çäåñü âèäíî, ÷òî òàêèå íóìåðàëû ñàìè ïî ñåáå ÿâëÿþòñÿ ôóíêöèÿìè âûñøåãî ïîðÿäêà, òî åñòü ôóíêöèîíàëàìè, êîòîðûå ðàáîòàþò
Ïðèìåðû êîäèðîâàíèÿ äàííûõ è ôóíêöèé
47
ñ äðóãèìè ôóíêöèÿìè, ïðèíèìàÿ èõ â êà÷åñòâå ñâîåãî ïåðâîãî àðãóìåíòà. Ýòî ïîçâîëèëî ñäåëàòü ñàìè íóìåðàëû äîñòàòî÷íî àáñòðàêòíûìè è íå ñâÿçàííûìè ñ êàêîé-ëèáî ïðåäìåòíîé îáëàñòüþ.  êàæäîé êîíêðåòíîé îáëàñòè ïðèìåíåíèÿ ìîæíî áóäåò ïåðåäàòü òàêèì íóìåðàëàì îïðåäåë¼ííóþ ôóíêöèþ, êîòîðàÿ â êîíå÷íîì èòîãå ïîñòðîèò ñàìî ÷èñëî. Íàïðèìåð, â àðèôìåòèêå äëÿ ïîñòðîåíèÿ ÷èñåë íóìåðàëàì ìîãóò ïåðåäàâàòüñÿ â êà÷åñòâå âõîäíûõ ïàðàìåòðîâ ôóíêöèÿ (+1) è íà÷àëüíîå çíà÷åíèå ïåðåìåííîé x 0. Òî åñòü âèäíî, ÷òî íóìåðàëû ×¼ð÷à ýòî êîäèðîâàíèå íàòóðàëüíûõ ÷èñåë áîëåå âûñîêîãî óðîâíÿ àáñòðàêöèè, íåæåëè ñàìè íàòóðàëüíûå ÷èñëà. Âíóòðè íóìåðàëîâ çàëîæåíà ôóíêöèîíàëüíîñòü äëÿ âû÷èñëåíèÿ îáúåêòîâ, ñõîæèõ ñ íàòóðàëüíûìè ÷èñëàìè, êîòîðûå, â ñâîþ î÷åðåäü, çàâèñÿò îò îáëàñòè ïðèìåíåíèÿ íóìåðàëîâ.  êà÷åñòâå áàçîâûõ îïåðàöèé íàä íóìåðàëàìè ×¼ð÷à ââîäÿòñÿ ôóíêöèè äëÿ ñëîæåíèÿ, óìíîæåíèÿ è âîçâåäåíèÿ â ñòåïåíü. Òàêèå ôóíêöèè ìîãóò áûòü îïðåäåëåíû íåïîñðåäñòâåííî: 1) add ≡ λmnf x.mf (nf x) 2) mlt ≡ λmnf x.m(nf )x 3) exp ≡ λmnf x.nmf x  ýòèõ λ-òåðìàõ ïîä ïåðåìåííûìè m è n ïîíèìàþòñÿ îïåðàíäû, íà ìåñòî êîòîðûõ îæèäàåòñÿ ïîäñòàíîâêà äâóõ íóìåðàëîâ ×¼ð÷à, ó÷àñòâóþùèõ â îïåðàöèè. Ñîáñòâåííî, ïðîâåðêà ýòèõ îïðåäåëåíèé òðèâèàëüíà è îñòàâëÿåòñÿ äëÿ ñàìîñòîÿòåëüíîé ïðîðàáîòêè (äîñòàòî÷íî ëèøü óáðàòü äâà óðîâíÿ àáñòðàêöèè, ïîäñòàâèâ âìåñòî ïåðåìåííûõ m è n äâà íóìåðàëà m è n è çàîäíî âñïîìíèâ èõ îïðåäåëåíèÿ â âèäå λ-òåðìîâ). Ïðè ýòîì íàäî ïîìíèòü, ÷òî äàííûå ôóíêöèè îïðåäåëåíû òîëüêî íà íóìåðàëàõ ×¼ð÷à. Äëÿ ëþáûõ ïðîèçâîëüíûõ λ-òåðìîâ M è N ýòè ôóíêöèè áóäóò ðàáîòàòü íåêîððåêòíî. Îäíàêî ýòèõ ôóíêöèé îáû÷íî íå õâàòàåò äëÿ ðàáîòû ñ íàòóðàëüíûìè ÷èñëàìè. Äëÿ áîëåå óñïåøíîãî èñïîëüçîâàíèÿ íóìåðàëîâ ×¼ð÷à íåîáõîäèìî îïðåäåëèòü äîïîëíèòåëüíûå ôóíêöèè, êîòîðûå ïîçâîëÿëè áû âûïîëíÿòü áîëåå ñëîæíûå äåéñòâèÿ, íàïðèìåð âû÷èòàíèå (ýòî äåéñòâèå îñëîæíåíî òåì, ÷òî ìîæåò âûâåñòè çà ðàìêè íàòóðàëüíûõ ÷èñåë, ðàâíî êàê è îïåðàöèè äåëåíèÿ, èçâëå÷åíèÿ êîðíÿ è âçÿòèÿ ëîãàðèôìà). Äëÿ òîãî ÷òîáû ïîäãîòîâèòüñÿ ê ñîçäàíèþ ïîäîáíûõ ¾ñëîæíûõ¿ ôóíêöèé, íåîáõîäèìî ðàçðàáîòàòü âñïîìîãàòåëüíûå λ-òåðìû, ÷òîáû áûëà âîçìîæíîñòü îñóùåñòâëÿòü ðàçíîãî ðîäà ïðîâåðêè.  ïåðâóþ î÷åðåäü íåîáõîäèìû ôóíêöèè äëÿ âû÷èñëåíèÿ ñëåäóþùåãî íóìåðàëà îòíîñèòåëüíî çàäàííîãî, à òàêæå äëÿ ïðîâåðêè çàäàííîãî íóìåðàëà íà ðàâåíñòâî íóëåâîìó íóìåðàëó 0. Îïðåäåëåíèÿ ýòèõ ôóíêöèé âûãëÿäÿò òàê1 : 1) nxt ≡ λnf x.f (nf x) 2) iszero ≡ λn.n(λx.false)true Îïÿòü æå, äîêàçàòåëüñòâî ýòèõ âûðàæåíèé ïðåäñòàâëÿåòñÿ äåëîì äîñòàòî÷íî ïðîñòûì, ïîýòîìó â ýòîé êíèãå ïðèâîäèòüñÿ íå áóäåò. Çäåñü æå ãëàâíûì ÿâëÿåòñÿ òî, ÷òî äëÿ ëþáûõ íóìåðàëîâ ×¼ð÷à áåçóñëîâíî âûïîëíÿþòñÿ ñëåäóþùèå ðåäóêöèîííûå öåïî÷êè (îïÿòü ñëåäóåò íàïîìíèòü, ÷òî íà äðóãèõ λ-òåðìàõ, êðîìå íóìåðàëîâ ×¼ð÷à, ýòè ôóíêöèè ìîãóò âåñòè ñåáÿ íåêîððåêòíî):
nxt n n + 1 1
Èñïîëüçóåìûå â äàííûõ âûðàæåíèÿõ êîìáèíàòîðû true è false îïðåäåëÿþòñÿ ñòàíäàðòíûì îáðàçîì: true ≡ λxy.x false ≡ λxy.y
Õîòÿ, ñ äðóãîé ñòîðîíû, ýòè îïðåäåëåíèÿ ñîâåðøåííî íå ðåëåâàíòíû ê ðàññìîòðåíèþ ôóíêöèè iszero, òàê êàê å¼ çàäà÷à çàêëþ÷àåòñÿ â òîì, ÷òîáû âîçâðàòèòü èñòèííîå çíà÷åíèå, åñëè ïåðåäàííûé åé íà âõîä íóìåðàë ðàâåí 0, è ëîæíîå çíà÷åíèå â ïðîòèâíîì ñëó÷àå. Ïîýòîìó ñïîñîá êîäèðîâàíèÿ áóëåâûõ çíà÷åíèé èñòèííîñòè ðîëè íå èãðàåò.
48
Ââåäåíèå â λ-èñ÷èñëåíèå äëÿ íà÷èíàþùèõ
iszero 0 true iszero n + 1 false Íî íà ýòîì ïðîñòûå îïðåäåëåíèÿ çàêàí÷èâàþòñÿ. Êàê òîëüêî ïîÿâëÿåòñÿ çàäà÷à ïîëó÷åíèÿ îïðåäåëåíèÿ ôóíêöèè, êîòîðàÿ äëÿ çàäàííîãî íóìåðàëà ×¼ð÷à íàõîäèò ïðåäûäóùèé íóìåðàë, íà÷èíàþòñÿ äîñòàòî÷íî ñåðü¼çíûå ñëîæíîñòè. À òåì áîëåå ýòî êàñàåòñÿ îïåðàöèè âû÷èòàíèÿ. Âåäü, êàê óæå áûëî ñêàçàíî, âû÷èòàíèå ìîæåò âûâåñòè çà ðàìêè íàòóðàëüíûõ ÷èñåë, â ñëó÷àå åñëè èç ìåíüøåãî íóìåðàëà âû÷èòàòü áîëüøèé. À îòðèöàòåëüíûå íóìåðàëû íå îïðåäåëåíû, òàê êàê íåâîçìîæíî ïðîâåñòè èòåðàòèâíîå ïðèìåíåíèå ôóíêöèè îòðèöàòåëüíîå ÷èñëî ðàç. Ïîýòîìó ïðè îïðåäåëåíèè ôóíêöèè äëÿ âû÷èòàíèÿ íåîáõîäèìî ââîäèòü îãðàíè÷åíèÿ. Ñïåðâà æå íàäî ðàçîáðàòüñÿ ñ ïîëó÷åíèåì ïðåäûäóùåãî íóìåðàëà äëÿ çàäàííîãî. Äëÿ ðåøåíèÿ ýòîé çàäà÷è íàä íóìåðàëàìè ×¼ð÷à äîñòàòî÷íî ñíà÷àëà ïðåäñòàâèòü ñåáå çàäà÷ó ìåíåå ñëîæíóþ, à èìåííî ïîëó÷åíèå ïðåäûäóùåãî íàòóðàëüíîãî ÷èñëà ñ èñïîëüçîâàíèåì òîëüêî îïåðàöèè ñëîæåíèÿ. Çëûå ÿçûêè ïîãîâàðèâàþò, ÷òî À. ×¼ð÷ íå ñìîã ñïðàâèòüñÿ ñ ýòîé çàäà÷åé. Íî íà ñàìîì äåëå îíà íå òàê ñëîæíà, êàê ýòî ìîæåò ïîêàçàòüñÿ íà ïåðâûé âçãëÿä. Âîò êàê ìîæåò âûãëÿäåòü ïîäîáíàÿ ôóíêöèÿ íà ÿçûêå Haskell:
decrement : : Num a => a −> a decrement n = dcr n 0
where
dcr 0 _ = 0 dcr n k = i f ( ( k + 1 ) == n ) then k el se dcr n ( k + 1 ) Äðóãèìè ñëîâàìè, äëÿ ïîëó÷åíèÿ ïðåäûäóùåãî íàòóðàëüíîãî ÷èñëà äëÿ íåêîòîðîãî çàäàííîãî íåîáõîäèìî îðãàíèçîâàòü öèêë, â êîòîðîì ïîñòåïåííî ïðèáàâëÿòü åäèíèöó è ñðàâíèâàòü ðåçóëüòàò ñ èñõîäíûì ÷èñëîì. Çàäà÷à äåéñòâèòåëüíî íå òàê ñëîæíà, êàê ýòî ìîæåò ïîêàçàòüñÿ. Îáû÷íî íîâè÷êîâ ïóãàåò å¼ ôîðìóëèðîâêà.  ñëó÷àå ñ íóìåðàëàìè ×¼ð÷à äåëî îáñòîèò íåñêîëüêî ñëîæíåå, âåäü íóìåðàë ýòî áîëåå àáñòðàêòíîå ïîíÿòèå, ÷åì ïðîñòî íàòóðàëüíîå ÷èñëî. Ïîëó÷åíèå ïðåäûäóùåãî íóìåðàëà íåîáõîäèìî âûïîëíÿòü, ïî ñóòè, äëÿ èòåðàòîðà, òî åñòü íåîáõîäèìî èç èòåðàòîðà n + 1 ïîëó÷èòü èòåðàòîð n. Ýòî ìîæíî ñäåëàòü ïðè ïîìîùè íåêîòîðîé âñïîìîãàòåëüíîé ôóíêöèè g , êîòîðàÿ ñâÿçûâàåòñÿ ñ èñõîäíûìè f è x, ïðèëàãàåìûìè ê íóìåðàëó n, ñëåäóþùèì ñîîòíîøåíèåì:
n+1gy nf x
(5)
Ïåðâîå, ÷òî ïðèõîäèò â ãîëîâó ïðè ïðîåêòèðîâàíèè òàêîé ôóíêöèè g , ýòî ðàáîòà ñ ïàðîé àðãóìåíòîâ, ïðè ýòîì íà ïåðâîé ïîçèöèè â òàêîé ïàðå ñòîèò íóìåðàë, êîòîðûé íà åäèíèöó áîëüøå âòîðîãî ýëåìåíòà ïàðû:
n + 1 g (x, x) (n + 1 f x, n f x)
(6)
Ïîäîáíîé ðåäóêöèè ìîæíî äîñòè÷ü, åñëè âçÿòü â êà÷åñòâå ôóíêöèè g ñëåäóþùåå âûðàæåíèå:
g (x, x) = (f x, x)
(7)
 ýòîì ñëó÷àå äëÿ ïîëó÷åíèÿ ïðåäûäóùåãî íóìåðàëà äëÿ çàäàííîãî äîñòàòî÷íî âçÿòü âòîðîé ýëåìåíò ïàðû, êîòîðàÿ ïîëó÷åíà ïðè ïîìîùè ïðèìåíåíèÿ ôóíêöèè g . Äðóãèìè ñëîâàìè, ôóíêöèÿ pre äëÿ ïîëó÷åíèÿ ïðåäûäóùåãî íóìåðàëà ×¼ð÷à âûãëÿäèò òàê:
Ïðèìåðû êîäèðîâàíèÿ äàííûõ è ôóíêöèé
49
pre n + 1 = snd (n + 1 g(pair x x)) Ýòà çàïèñü íå î÷åíü ïîõîæà íà óæå èçó÷åííûå λ-òåðìû. ż äåéñòâèòåëüíî íåîáõîäèìî ïðåîáðàçîâàòü â îáû÷íûé λ-òåðì. Ýòî ìîæíî ñäåëàòü ñëåäóþùèì îáðàçîì, ââåäÿ ñâÿçàííûå ïåðåìåííûå äëÿ íóìåðàëà, ôóíêöèè g è ïåðåìåííîé x:
pre ≡ λngx.snd (ng (pair x x))
(8)
 ýòîé ôîðìóëå, êàê âèäíî, ðåøåíà ïðîáëåìà, îáîçíà÷åííàÿ â ôîðìóëå (6). Äåéñòâèòåëüíî, ïîêà íå ïðèíèìàÿ â ðàñ÷¼ò λ-òåðìû pair è snd, êîòîðûå íèãäå íå ââåäåíû, ìîæíî óâèäåòü, ÷òî ôóíêöèÿ pre äåéñòâèòåëüíî âîçâðàùàåò ïðåäûäóùèé íóìåðàë. Áîëåå òîãî, ôîðìóëà (8) ðàáîòàåò è äëÿ íóìåðàëà 0, â ÷¼ì ìîæíî óáåäèòüñÿ íåïîñðåäñòâåííî, ïîäñòàâèâ ýòîò íóìåðàë íà ìåñòî ïåðâîãî îïåðàíäà. Íî îñòà¼òñÿ îäíà ïðîáëåìà ôóíêöèÿ g äî ñèõ ïîð íå âûðàæåíà ÷åðåç ôóíêöèþ f , êàê ýòî äîëæíî áûòü íà ñàìîì äåëå, ïîýòîìó ýòà ôóíêöèÿ îñòà¼òñÿ íåèçâåñòíûì ÷ëåíîì ôîðìóëû. Îäíàêî ýòà ïðîáëåìà ðåøàåòñÿ ïðîñòî, òàê êàê â ôîðìóëå (7) óæå äàíî âûðàæåíèå îäíîé ôóíêöèè ÷åðåç äðóãóþ. Îñòàëîñü çàïèñàòü ýòó ôîðìóëó â âèäå λ-òåðìà. Ýòî ìîæíî ñäåëàòü ñëåäóþùèì îáðàçîì:
g ≡ λf p.pair (f (fst p)) (fst p)
(9)
Òàêèì îáðàçîì, îñòàëîñü çàïèñàòü îêîí÷àòåëüíîå ðåøåíèå äëÿ ôóíêöèè pre:
pre ≡ λnf x.snd (n (g f ) (pair x x))
(10)
Ñîáñòâåííî, ïðîâåðêà ýòîãî âûðàæåíèÿ ÿâëÿåòñÿ äåëîì äîñòàòî÷íî èíòåðåñíûì, òàê êàê ïîçâîëÿåò ïîíÿòü ñìûñë âñåãî âûøåèçëîæåííîãî. ×èòàòåëþ ðåêîìåíäóåòñÿ ñàìîñòîÿòåëüíî ïðîâåðèòü ôóíêöèþ pre äëÿ íóìåðàëîâ 0, 1 è 2, ïîñëå ÷åãî ðàññìîòðåòü íóìåðàë n + 1 â ïðèëîæåíèè ê ýòîé ôóíêöèè. ×òî èíòåðåñíî, ïîëó÷åííóþ ôóíêöèþ pre ìîæíî ëåãêî ïðåäñòàâèòü â âèäå ôóíêöèè íà ÿçûêå Haskell, òàê êàê â ýòîì ÿçûêå åñòü ñðåäñòâà äëÿ ïðÿìîãî îòîáðàæåíèÿ λ-òåðìîâ. Ýòî, ê ïðèìåðó, ìîæíî ñäåëàòü òàê:
pre = \ n f x −> snd ( n ( g f ) ( x , x ) )
where
g = \ f p −> ( f ( fst p ) , ( fst p ) ) Îäíàêî ýòî íå áóäåò ôóíêöèåé, êîòîðàÿ âû÷èñëÿåò äåêðåìåíò íàòóðàëüíûõ ÷èñåë, êàê ýòîãî ìîæíî áûëî áû îæèäàòü. Îíà äåéñòâèòåëüíî áóäåò ðàáîòàòü ñ íóìåðàëàìè ×¼ð÷à, îæèäàÿ ïåðâûì àðãóìåíòîì èìåííî òàêèå îáúåêòû, êîòîðûå, êàê íàäî ïîìíèòü, ÿâëÿþòñÿ ôóíêöèÿìè âûñøåãî ïîðÿäêà. Åñëè ïûòàòüñÿ ïðåîáðàçîâàòü ýòó ôóíêöèþ ê òàêîé, ÷òî ðàáîòàåò ñ íàòóðàëüíûìè ÷èñëàìè, òî íåîáõîäèìî ìíîãîå óïðîñòèòü. Åñëè âñïîìíèòü, òî ïðè ïåðåõîäå ê àðèôìåòè÷åñêèì îïåðàöèÿì íåîáõîäèìî ôóíêöèþ f ïðåîáðàçîâàòü â ôóíêöèþ (+ 1), à ïåðåìåííóþ x ñäåëàòü ðàâíîé 0. Ïîýòîìó ïåðâûì øàãîì ê ïðåîáðàçîâàíèþ áóäåò çàïèñü óêàçàííûõ âåëè÷èí íåïîñðåäñòâåííî â òåëî ôóíêöèè pre:
pre = \n -> snd (n (g (+ 1)) (0, 0)) where g = \f p -> (f (fst p), (fst p)) Äàëüøå ìîæíî óâèäåòü, ÷òî ëîêàëüíàÿ ôóíêöèÿ g èñïîëüçóåòñÿ òîëüêî â îäíîì ìåñòå, ïîýòîìó å¼ âûäåëåíèå â êà÷åñòâå ëîêàëüíîãî îïðåäåëåíèÿ áåññìûñëåííî, à å¼ òåëî ìîæíî ïîäñòàâèòü íåïîñðåäñòâåííî â ôóíêöèþ pre:
50
Ââåäåíèå â λ-èñ÷èñëåíèå äëÿ íà÷èíàþùèõ
pre = \n -> snd (n (\p -> ((+ 1) (fst p), (fst p))) (0, 0)) Ê ñîæàëåíèþ, ýòî íå ïðèáàâèëî ÿñíîñòè â îïðåäåëåíèå. Íî îïðåäåë¼ííûé øàã ê óïðîùåíèþ ñäåëàí. Òåïåðü îñòàëîñü ñäåëàòü òàê, ÷òîáû ôóíêöèÿ pre ïðèíèìàëà íà âõîä íàòóðàëüíîå ÷èñëî, à íå íóìåðàë ×¼ð÷à. Äëÿ ýòîãî íàäî çàìåòèòü, ÷òî â äàííîì ñëó÷àå àðãóìåíò n ïðîñòî ÿâëÿåòñÿ èòåðàòîðîì, êîòîðûé ïðèìåíÿåò n ðàç ñëåäóþùóþ ôóíêöèþ ê àðãóìåíòó. Äëÿ ñõîæèõ öåëåé â ñòàíäàðòíîì ìîäóëå Prelude îïðåäåëåíà ôóíêöèÿ until, êîòîðàÿ öèêëè÷åñêè ïðèìåíÿåò ôóíêöèþ ê ðåçóëüòàòó ïðåäûäóùåãî ïðèìåíåíèÿ, ïîêà íå áóäåò äîñòèãíóòî óñëîâèå, îïðåäåëÿåìîå íåêîòîðûì ïðåäèêàòîì.  äàííîì ñëó÷àå íåîáõîäèìî ïðîâåðÿòü íà ðàâåíñòâî âõîäíîìó ïàðàìåòðó ôóíêöèè pre, êîòîðûé óæå äîëæåí ñòàòü íàòóðàëüíûì ÷èñëîì. Ïîýòîìó ïðàêòè÷åñêè îêîí÷àòåëüíîå îïðåäåëåíèå ôóíêöèè pre áóäåò âûãëÿäåòü ñëåäóþùèì îáðàçîì:
pre n = snd ( until ((== n ) . fst ) ( ( \ p −> ((+ 1 ) ( fst p ) , ( fst p ) ) ) ) (0 , 0)) Îñòàëîñü íåìíîãî ¾ïðè÷åñàòü¿ îïðåäåëåíèå, óáðàâ èç íåãî íå î÷åíü ïðèÿòíûé íà âèä λ-òåðì è çàìåíèâ åãî íåêîòîðîé ëîêàëüíîé ôóíêöèåé, êîòîðàÿ èñïîëüçóåò ìîùíûé ìåõàíèçì . Êðîìå òîãî, ìîæíî óáðàòü ëèøíèå ñêîáêè, ïðèìåíèâ òàê íàçûâàåìûé îïðåäåëåíèÿ ôóíêöèé.  èòîãå ïîëó÷èòñÿ ñëåäóþùåå îïðåäåëåíèå:
ñîïîñòàâëåíèÿ ñ îáðàçöîì áåñòî÷å÷íûé ñòèëü
pre :: Num a => a -> a pre n = snd $ until ((== n) . fst) dcr (0, 0) where dcr (n, _) = (n + 1, n) Êàê âèäíî, òèï ýòîé ôóíêöèè óæå ïîëíîñòüþ óäîâëåòâîðÿåò ïåðâîíà÷àëüíûì öåëÿì ïîëó÷åíèå äåêðåìåíòà íàòóðàëüíîãî ÷èñëà. È îíà äåéñòâèòåëüíî âû÷èñëÿåò ïðåäûäóùåå ÷èñëî äëÿ çàäàííîãî íàòóðàëüíîãî, ïðè÷¼ì äëÿ ÷èñëà 0 âîçâðàùàåòñÿ ðåçóëüòàò 0, ïîýòîìó ôóíêöèÿ íå âûâîäèò çà ïðåäåëû ìíîæåñòâà íàòóðàëüíûõ ÷èñåë. Îñòà¼òñÿ ðàññêàçàòü íåñêîëüêî ñëîâ î êîìáèíàòîðàõ pair, fst è snd, à òàêæå îá îäíîèì¼ííûõ ôóíêöèÿõ fst è snd èç ñòàíäàðòíîãî ìîäóëÿ Prelude. ×òî êàñàåòñÿ êîìáèíàòîðîâ, òî, êàê óæå ãîâîðèëîñü, êîäèðîâêà ýòèõ ôóíêöèé ïðè ïîìîùè λ-òåðìîâ ñîâåðøåííî íå âàæíà, ãëàâíîå, ÷òîáû âûïîëíÿëîñü óñëîâèå ðåäóöèðóåìîñòè ñëåäóþùèõ öåïî÷åê:
fst (pair x y) x snd (pair x y) y Ýòî óñëîâèå ïðîùå âñåãî âûïîëíèòü ïðè ïîìîùè ñëåäóþùèõ îïðåäåëåíèé (ïðè ýòîì êîìáèíàòîðû true è false îïðåäåëÿþòñÿ òàê æå, êàê è â ïðîøëûé ðàç): 1) pair ≡ λxyf.f xy 2) fst ≡ λp.p true 3) snd ≡ λp.p false
Çàêëþ÷åíèå
51
 ñòàíäàðòíîì æå ìîäóëå Prelude îïðåäåëåíû ôóíêöèè äëÿ ðàáîòû ñ ïàðàìè, êîòîðûå ïðåäñòàâëÿþò ñîáîé êîðòåæè èç äâóõ ýëåìåíòîâ. Ýòè ôóíêöèè è áûëè èñïîëüçîâàíû ïðè ïîñòðîåíèè ôóíêöèè pre. Çäåñü òàêæå ÿâëÿåòñÿ ãëàâíûì òî, ÷òî âûïîëíÿþòñÿ ñëåäóþùèå óñëîâèÿ:
fst (x, y) = x snd (x, y) = y Ýòè ôóíêöèè èìåííî òàê è îïðåäåëÿþòñÿ â ñòàíäàðòíîì ìîäóëå Prelude. Òåïåðü âñ¼ ãîòîâî äëÿ òîãî, ÷òîáû îïðåäåëèòü ôóíêöèþ äëÿ âû÷èñëåíèÿ ðàçíîñòè äâóõ íóìåðàëîâ ×¼ð÷à, ïðè÷¼ì òàêèì îáðàçîì, ÷òî åñëè âû÷èñëÿåòñÿ ðàçíîñòü áîëüøåãî íóìåðàëà èç ìåíüøåãî, òî äîëæåí âîçâðàòèòüñÿ íóìåðàë 0. Êàêîâà ñóòü îïåðàöèè âû÷èòàíèÿ?  çàïèñè (m − n) ãîâîðèòñÿ, ÷òî íåîáõîäèìî èç ÷èñëà m âû÷åñòü åäèíèöó n ðàç. Ñîáñòâåííî, ýòî è åñòü êëþ÷ ê îïðåäåëåíèþ îïåðàöèè âû÷èòàíèÿ ÷åðåç λ-òåðì:
sub ≡ λmn.n pre m
(11)
Ïóòü íàìå÷åí. Ïîëíîñòüþ îñîçíàâ íîâîå çíàíèå, ìîæíî äâèãàòüñÿ äàëåå. Ôîðìàëèçì λ-èñ÷èñëåíèÿ ïîçâîëÿåò âûðàçèòü ïðàêòè÷åñêè âñ¼. Èçó÷àÿ íóìåðàëû ×¼ð÷à, ìîæíî ïîïûòàòüñÿ âûðàçèòü îïåðàöèè äëÿ öåëî÷èñëåííîãî äåëåíèÿ è âçÿòèÿ îñòàòêà ïðè äåëåíèè îäíîãî ÷èñëà íà äðóãîå. Òàêèì æå îáðàçîì ìîæíî çàêîäèðîâàòü âñå ôóíêöèè, ðàáîòàþùèå ñ íàòóðàëüíûìè ÷èñëàìè. À çàòåì ìîæíî ðàñøèðèòü ãðàíèöû ðàññìîòðåíèÿ è ïåðåéòè ê äðóãèì ÷èñëåííûì ìíîæåñòâàì. Áîëåå òîãî, λ-èñ÷èñëåíèå ìîæåò âûðàçèòü â ñâîèõ òåðìèíàõ ìíîãèå íàïðàâëåíèÿ äèñêðåòíîé ìàòåìàòèêè èñ÷èñëåíèÿ âûñêàçûâàíèé è ïðåäèêàòîâ ïåðâîãî ïîðÿäêà, òåîðèþ ìíîæåñòâ è, êîíå÷íî æå, . Ìîæíî áîëüøå ñêàçàòü, ÷òî ìíîãèå (åñëè íå âñå) ôóíêöèîíàëüíûå ÿçûêè ïðîãðàììèðîâàíèÿ ÿâëÿþòñÿ íàäñòðîéêàìè íàä λ-èñ÷èñëåíèåì, ¾îá¼ðòûâàÿ¿ åãî â óäîáíûé ñèíòàêñèñ è äîáàâëÿÿ íåêîòîðûå âîçìîæíîñòè. Ýòî óòâåðæäåíèå îòíîñèòñÿ è ê ÿçûêó Haskell, ÿäðîì êîòîðîãî ÿâëÿåòñÿ òèïèçèðîâàííîå λ-èñ÷èñëåíèå. Ïîýòîìó ïîíèìàíèå ñóòè λ-èñ÷èñëåíèÿ ïîçâîëèò ãëóáæå îñâîèòü ñàìî ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå è ëþáîé ôóíêöèîíàëüíûé ÿçûê.
ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå
Çàêëþ÷åíèå À ÷òî æå ñ ïàðàäîêñîì Ðàññåëà? Àëîíçî ×¼ð÷ íà÷àë ðàçðàáàòûâàòü λ-èñ÷èñëåíèå äëÿ èçìåíåíèÿ íîòàöèè êëàññè÷åñêîé òåîðèè ìíîæåñòâ, ïîëàãàÿ, ÷òî òàêèì ñïîñîáîì îí ñìîæåò íàéòè ðàçðåøåíèå ýòîãî ïàðàäîêñà. Òàê, ëþáàÿ õàðàêòåðèñòè÷åñêàÿ ôóíêöèÿ èç òåîðèè ìíîæåñòâ áûëà çàêîäèðîâàíà ïðè ïîìîùè íåêîòîðîãî λ-òåðìà, êîòîðûå îáîçíà÷àþòñÿ çàãëàâíûìè áóêâàìè: M , N è ò. ä. Ôàêò òîãî, ÷òî îäíî ìíîæåñòâî ÿâëÿåòñÿ ïîäìíîæåñòâîì äðóãîãî, òî åñòü M ⊆ N , êîäèðóåòñÿ ïðè ïîìîùè àïïëèêàöèè M N . Íàêîíåö, àáñòðàêöèÿ êîäèðóåò ìíîæåñòâî âñåõ ýëåìåíòîâ x, óäîâëåòâîðÿþùèõ íåêîòîðîìó ïðåäèêàòó P , òî åñòü {x | P } êîäèðóåòñÿ êàê λx.P . Ýòà íîòàöèÿ ïîçâîëÿåò çàêîäèðîâàòü ïàðàäîêñ Ðàññåëà ñëåäóþùèì îáðàçîì:
R = λx.not (xx)
(12)
 ýòîì ñëó÷àå îñíîâíîé âîïðîñ ïàðàäîêñà êîäèðóåòñÿ êàê RR, òî åñòü (λx.not (xx))(λx.not (xx)). Åñëè ïîïûòàòüñÿ ðåäóöèðîâàòü ýòîò λ-òåðì, òî ñòàíåò ïîíÿòíî, ÷òî ó íåãî íåò íîðìàëüíîé ôîðìû. Ðåäóêöèÿ áóäåò äëèòüñÿ äî áåñêîíå÷íîñòè. Äðóãèìè ñëîâàìè, ìàòåìàòè÷åñêàÿ íîòàöèÿ λ-èñ÷èñëåíèÿ ïîâòîðèëà ðàññóæäåíèÿ íà åñòåñòâåííîì ÿçûêå, êîòîðûå ïðèâåäåíû âî ââåäåíèè ê ðàçäåëó. Ïàðàäîêñ ðàçðåøèòü íå óäàëîñü. Íî, êàê áûëî ïîêàçàíî â ýòîì ðàçäåëå, λ-èñ÷èñëåíèå ñåðü¼çíî ïîâëèÿëî íà äàëüíåéøåå ðàçâèòèå êîìïüþòåðíîé íàóêè â ÷àñòíîñòè è äèñêðåòíîé ìàòåìàòèêè â öåëîì.
Êîìáèíàòîðû? Ýòî ïðîñòî! Ñòàòüÿ áûëà îïóáëèêîâàíà â 07 (19) æóðíàëà ¾Ïîòåíöèàë¿ â èþëå 2006 ãîäà.
Äàííîå ýññå îïèñûâàåò îñíîâû êîìáèíàòîðíîé ëîãèêè ìàòåìàòè÷åñêîé íàóêè î âû÷èñëåíèÿõ, â êîòîðîé ëþáûå îáúåêòû èçó÷åíèÿ âûðàæàþòñÿ ïðè ïîìîùè äâóõ áàçîâûõ îáúåêòîâ S è K (èëè äàæå îäíîãî áàçîâîãî îáúåêòà X), íàçûâàåìûõ êîìáèíàòîðàìè, è îäíîé îïåðàöèè íàä íèìè îïåðàöèè ïðèìåíåíèÿ îäíîãî êîìáèíàòîðà ê äðóãîìó. Áîëüøèíñòâî ïðèìåðîâ èç äàííîãî ýññå áûëè ðàññìîòðåíû â ïðåäûäóùåì ýññå, çäåñü æå ïðèâîäÿòñÿ â êà÷åñòâå äîïîëíåíèÿ â öåëÿõ ïîêàçàòü ñõîäñòâà è ðàçëè÷èÿ ìåæäó äâóìÿ ¾ðîäñòâåííûìè¿ ôîðìàëèçìàìè.
Ââåäåíèå Êîìáèí àòîðíàÿ ëîãèêà (îò ñëîâà ¾êîìáèíàòîð¿, à íå ¾êîìáèíàòîðèêà¿) ýòî íàïðàâëåíèå â ìàòåìàòè÷åñêîé ëîãèêå, ðàçðàáîòàííîå â ïåðâîé ïîëîâèíå XX âåêà àìåðèêàíñêèìè ëîãèêàìè Ìîçåñîì ؼíôèíêåëåì è Õàñêåëëîì Êàððè â êà÷åñòâå íàóêè î âû÷èñëèòåëüíûõ ïðîöåññàõ [21, 17]. Õîòÿ ïåðâîíà÷àëüíî ýòîò âèä ëîãèêè ïðåòåíäîâàë òîëüêî íà òî, ÷òîáû óäàëèòü èç ëîãè÷åñêèõ âûñêàçûâàíèé ïåðåìåííûå, ÷åðåç íåêîòîðîå âðåìÿ â (computer science) áûëè ïîëó÷åíû ïðèêëàäíûå ðåçóëüòàòû, êîòîðûå ïîêàçàëè, ÷òî êîìáèíàòîðíóþ ëîãèêó ìîæíî èñïîëüçîâàòü äëÿ ïðîâåäåíèÿ âû÷èñëåíèé. Íà êîìáèíàòîðíóþ ëîãèêó ìîæíî ñìîòðåòü êàê íà íåêîòîðîå óïðîùåíèå λ-èñ÷èñëåíèÿ2 , â êîòîðîì íåò ñèìâîëà (λ), à âñå ôóíêöèîíàëüíûå àáñòðàêöèè ïðåäñòàâëåíû îãðàíè÷åííûì íàáîðîì ñèìâîëîâ, íàçûâàåìûõ ¾êîìáèíàòîðàìè¿. Òàêèå êîìáèíàòîðû íå ñîäåðæàò ïåðåìåííûõ, ÿâëÿþòñÿ , òî åñòü â êà÷åñòâå àðãóìåíòîâ ìîãóò ïðèíèìàòü íà âõîä äðóãèå ôóíêöèè (òàêèå æå êîìáèíàòîðû), à òàêæå îïèñûâàþò îïðåäåë¼ííûå ïðàâèëà ïðåîáðàçîâàíèÿ îáúåêòîâ, ïîäàííûõ èì íà âõîä â êà÷åñòâå àðãóìåíòîâ. Äðóãèìè ñëîâàìè, êîìáèíàòîðíàÿ ëîãèêà ýòî ôîðìàëèçì äëÿ ïðåäñòàâëåíèÿ ôóíêöèîíàëüíûõ çàâèñèìîñòåé ìåæäó âõîäíûìè è âûõîäíûìè ïàðàìåòðàìè, îáëàäàþùèé âåñüìà îãðàíè÷åííûì àëôàâèòîì äëÿ êîäèðîâàíèÿ ëþáûõ äàííûõ è îïåðàöèé íàä íèìè.  ïîñëåäóþùèõ ïîäðàçäåëàõ ýòîò ôîðìàëèçì áóäåò ïîäðîáíî ðàññìîòðåí.
êîìïüþòåðíîé íàóêå
âûñøåãî ïîðÿäêà
ôóíêöèÿìè
Ôîðìàëüíàÿ òåîðèÿ Äëÿ òîãî ÷òîáû íå áûòü ãîëîñëîâíûì, íåîáõîäèìî ÷¼òêî îïèñàòü áàçîâûå îáúåêòû êîìáèíàòîðíîé ëîãèêè, êîòîðûå ó÷àñòâóþò â ôîðìàëüíîé ñèñòåìå, îïðåäåëÿþùåé ñàìó êîìáèíàòîðíóþ ëîãèêó. Ñîãëàñíî ìàòåìàòè÷åñêîé ïðàêòèêè, íåîáõîäèìî îïðåäåëèòü ñëåäóþùèå ýëåìåíòû ôîðìàëüíîé ñèñòåìû: 1) àëôàâèò;
-èñ÷èñëåíèå ýòî íàóêà î âû÷èñëåíèÿõ, ïåðâîíà÷àëüíî ðàçðàáîòàííàÿ Àëîíçî ×¼ð÷åì äëÿ ðàçðåøåíèÿ àíòèíîìèè Á. Ðàññåëà î ìíîæåñòâå âñåõ ìíîæåñòâ, íå âêëþ÷àþùèõ ñàìèõ ñåáÿ â êà÷åñòâå ïîäìíîæåñòâà. Ðàññìîòðåíèå ýòîãî íàïðàâëåíèÿ ëîãèêè ïðîèçâåäåíî â ïðåäûäóùåì ýññå. 2 λ
Ôîðìàëüíàÿ òåîðèÿ
53
2) óòâåðæäåíèÿ (ìíîæåñòâî ïðàâèëüíî ïîñòðîåííûõ ôîðìóë); 3) àêñèîìû; 4) ïðàâèëà âûâîäà. Ïîä àëôàâèòîì ïîíèìàåòñÿ íàáîð ñèìâîëîâ, äîïóñòèìûõ â íîòàöèè çàïèñåé òåðìîâ â êîìáèíàòîðíîé ëîãèêå.  îáùåì âèäå ïðè ïîìîùè íîòàöèè êîìáèíàòîðíîé ëîãèêè ìîæíî çàïèñûâàòü îáúåêòû íåñêîëüêèõ òèïîâ êîíñòàíòû, ïåðåìåííûå, òåðìû è ñïåöèàëüíûå çíàêè. Êîíñòàíòû îáîçíà÷àþòñÿ ìàëûìè áóêâàìè ëàòèíñêîãî àëôàâèòà, âîçìîæíî ñ èíäåêñàìè. Îáû÷íî äëÿ îáîçíà÷åíèÿ êîíñòàíò áåðóòñÿ ñèìâîëû ñ íà÷àëà àëôàâèòà. Ïåðåìåííûå îáîçíà÷àþòñÿ òàêæå ìàëûìè áóêâàìè, âîçìîæíî ñ èíäåêñàìè, íî ïðè ýòîì îíè îáû÷íî âûáèðàþòñÿ ñ êîíöà àëôàâèòà: c1 , c2 êîíñòàíòû; x, y ïåðåìåííûå. Îäíàêî äëÿ âûäåëåíèÿ êîíñòàíòíûõ îáúåêòîâ èíîãäà áóäåò èñïîëüçîâàòüñÿ èíîé ñïîñîá çàïèñè. Òàêîé ñïîñîá çàêëþ÷àåòñÿ â âûäåëåíèè íàèìåíîâàíèé êîíñòàíò ïîëóæèðíûì íà÷åðòàíèåì ýòà çàïèñü áóäåò èñïîëüçîâàòüñÿ, åñëè íàèìåíîâàíèå êîíñòàíòû ñîñòîèò áîëåå ÷åì èç îäíîãî ñèìâîëà: if , true, pair è ò. ä. Êîìáèíàòîðíûå òåðìû (èëè ïðîñòî ¾âûðàæåíèÿ¿) áóäóò îáîçíà÷àòüñÿ çàãëàâíûìè áóêâàìè ëàòèíñêîãî àëôàâèòà, âîçìîæíî òàêæå ñ èíäåêñàìè: M , N è ò. ä. Êîìáèíàòîðû, ÿâëÿþùèåñÿ òåðìàìè, òàêæå îáîçíà÷àþòñÿ çàãëàâíûìè áóêâàìè ëàòèíñêîãî àëôàâèòà, ïðè ýòîì îíè çàïèñûâàþòñÿ â ïðÿìîì ïîëóæèðíîì íà÷åðòàíèè. Èç ñïåöèàëüíûõ ñèìâîëîâ â êîìáèíàòîðíîé ëîãèêå èñïîëüçóþòñÿ âñåãî òðè: ýòî ñêîáêè ¾(¿ è ¾)¿, à òàêæå çíàê ðàâåíñòâà (=). Ïîñëåäíèé îáîçíà÷àåò îòíîøåíèå êîíâåðòèðóåìîñòè òåðìîâ äðóã â äðóãà, òî åñòü âîçìîæíîñòü ïðåîáðàçîâàíèÿ òàêèõ òåðìîâ èç îäíîãî â äðóãîé. Ñ òî÷êè çðåíèÿ âû÷èñëèòåëüíûõ ïðîöåññîâ, îòíîøåíèå êîíâåðòèðóåìîñòè îïðåäåëÿåò ñàì ïðîöåññ âû÷èñëåíèÿ çíà÷åíèÿ ôóíêöèè, ïðåäñòàâëåííîé êîìáèíàòîðíûì òåðìîì. Ìíîæåñòâî ïðàâèëüíî ïîñòðîåííûõ ôîðìóë â êîìáèíàòîðíîé ëîãèêå âûãëÿäèò î÷åíü ïðîñòî. Åãî ñîñòàâëÿþò âûðàæåíèÿ âèäà M = N , ãäå M è N êîìáèíàòîðíûå òåðìû. Ïðè ýòîì ñàìè êîìáèíàòîðíûå òåðìû ñòðîÿòñÿ ïî èíäóêöèè: 1) åñëè c êîíñòàíòà, òî c êîìáèíàòîðíûé òåðì; 2) åñëè x ïåðåìåííàÿ, òî x êîìáèíàòîðíûé òåðì; 3) åñëè M è N êîìáèíàòîðíûå òåðìû, òî (M N ) êîìáèíàòîðíûé òåðì; 4) äðóãèõ êîìáèíàòîðíûõ òåðìîâ íåò.  ýòîì èíäóêòèâíîì îïðåäåëåíèè âûðàæåíèå (M N ) îáîçíà÷àåò îïåðàöèþ àïïëèêàöèè, åäèíñòâåííóþ îïåðàöèþ êîìáèíàòîðíîé ëîãèêè. Àïïëèêàöèÿ îïèñûâàåò ïðèìåíåíèå ôóíêöèè (â äàííîì ïðèìåðå òåðì M ) ê å¼ àðãóìåíòó èëè àðãóìåíòàì (â äàííîì ïðèìåðå òåðì N ). Êàê âèäíî, ñîçäàíèå êîìáèíàòîðíûõ òåðìîâ ïîâëå÷¼ò çà ñîáîé ëàâèíîîáðàçíîå âíåäðåíèå â çàïèñü òàêèõ òåðìîâ ñêîáîê. Äëÿ òîãî ÷òîáû óìåíüøèòü êîëè÷åñòâî ñêîáîê â çàïèñÿõ êîìáèíàòîðíûõ òåðìîâ, ââîäÿòñÿ ñîãëàøåíèÿ î ñêîáêàõ, êîòîðûå çàêëþ÷àþòñÿ â òîì, ÷òî ïðîïóùåííûå ñêîáêè âîññòàíàâëèâàþòñÿ ïî àññîöèàòèâíîñòè âëåâî:
XY = (XY ) XY Z = ((XY )Z)  êà÷åñòâå àêñèîì, âõîäÿùèõ â ìíîæåñòâî ïðàâèëüíî ïîñòðîåííûõ ôîðìóë, îáû÷íî âûäåëÿþòñÿ ñëåäóþùèå:
Ix = x
(I)
54
Êîìáèíàòîðû? Ýòî ïðîñòî!
Kxy = x
(K)
Sxyz = xz(yz)
(S)
Äàííûå àêñèîìû íå íàäî äîêàçûâàòü, èõ íàëè÷èå ïðîñòî ïîñòóëèðóåòñÿ. Ýòè àêñèîìû îïðåäåëÿþò òðè áàçîâûõ êîìáèíàòîðà, èñïîëüçóþùèõñÿ äëÿ âûâîäà (âû÷èñëåíèé) íîâûõ êîìáèíàòîðîâ. Òðàäèöèîííî áàçèñ S, K, I ÿâëÿåòñÿ òåì íàáîðîì ïåðâîíà÷àëüíûõ êîìáèíàòîðîâ, ÷åðåç êîòîðûé âûðàæàþòñÿ âñå ïðî÷èå êîìáèíàòîðû. Îäíàêî ýòî íå ìèíèìàëüíûé áàçèñ, èáî íàëè÷èå êîìáèíàòîðà I íå îáÿçàòåëüíî â í¼ì, òàê êàê åãî ìîæíî âûðàçèòü ÷åðåç êîìáèíàòîðû S è K3 : S
K
SKKx = Kx(Kx) = x ≡ Ix Äðóãèìè ñëîâàìè, êîìáèíàòîðíûé áàçèñ ýòî íàáîð êîìáèíàòîðîâ, ÷åðåç êîòîðûå ïðè ïîìîùè îòíîøåíèÿ êîíâåðòèðóåìîñòè (=) ìîæíî âûðàçèòü âñå îñòàëüíûå êîìáèíàòîðû. Äâóõêîìáèíàòîðíûì áàçèñîì ÿâëÿåòñÿ íàáîð èç êîìáèíàòîðîâ S è K, íî îáû÷íî åãî äîïîëíÿþò êîìáèíàòîðîì I äëÿ óïðîùåíèÿ çàïèñè âûðàæàåìûõ êîìáèíàòîðíûõ òåðìîâ. Îäíàêî ðàçíîîáðàçíûõ áàçèñîâ ìîæåò áûòü áåñ÷èñëåííîå ìíîæåñòâî, è ðàçíûå èññëåäîâàòåëè ââîäèëè ðàçíûå áàçèñû äëÿ ñâîèõ öåëåé.  ñëåäóþùåì ðàçäåëå áóäóò ðàññìîòðåíû íåêîòîðûå ïðèìåðû òàêèõ áàçèñîâ. Îñòà¼òñÿ ðàññìîòðåòü ïðàâèëà âûâîäà, êîòîðûå èñïîëüçóþòñÿ â ðàìêàõ êîìáèíàòîðíîé ëîãèêè äëÿ ïðåîáðàçîâàíèÿ îäíèõ òåðìîâ â äðóãèå è îïèñûâàþò îòíîøåíèå êîíâåðòèðóåìîñòè (=). Äàííûå ïðàâèëà âûâîäà, ïî ñâîåé ñóòè, îïèñûâàþò ýòî îòíîøåíèå, çàäàâàÿ åãî õàðàêòåðèñòèêè.
a=a
(ρ)
(a = b) ⇒ (b = a)
(σ )
(a = b) ∧ (b = c) ⇒ (a = c)
(τ )
(a = b) ⇒ (ca = cb)
(µ)
(a = b) ⇒ (ac = bc)
(ν )
Êàê âèäíî, ïåðâûå òðè ïðàâèëà ÿâëÿþòñÿ îïèñàíèåì ñâîéñòâ ðåôëåêñèâíîñòè, ñèììåòðè÷íîñòè è òðàíçèòèâíîñòè. Íàáîð ýòèõ ñâîéñòâ ÿâëÿåò ñîáîé õàðàêòåðèñòèêè îòíîøåíèÿ ýêâèâàëåíòíîñòè, òî åñòü îòíîøåíèå êîíâåðòèðóåìîñòè (=) äåëèò âñ¼ ìíîæåñòâî êîìáèíàòîðíûõ òåðìîâ íà íåêîòîðûå êëàññû ýêâèâàëåíòíîñòè, îòíîñèòåëüíî êîòîðûõ ìîæíî ñêàçàòü, ÷òî íàõîäÿùèåñÿ â íèõ òåðìû êîíâåðòèðóåìû äðóã â äðóãà (ýêâèâàëåíòíû äðóã äðóãó). Äîïîëíèòåëüíî íàäî îòìåòèòü, ÷òî äàëåå ïîä èìåíåì êîìáèíàòîðà áóäåò ïîíèìàòüñÿ ñèìâîë, åãî îáîçíà÷àþùèé, ïîä êîìáèíàòîðà áóäåò ïîíèìàòüñÿ ëåâàÿ ÷àñòü ïðàâèëà, à ïîä ïðàâàÿ ÷àñòü ïðàâèëà, îïèñûâàþùåãî ñàì êîìáèíàòîð.
õàðàêòåðèñòèêîé
ñèãíàòóðîé
Áîëåå òîãî, ñàìè êîìáèíàòîðû S è K ìîæíî âûðàçèòü ÷åðåç îäèí êîìáèíàòîð X (K ≡ XX, S ≡ XK ≡ X(XX)), òàê ÷òî ìèíèìàëüíûé áàçèñ â êîìáèíàòîðíîé ëîãèêå ñîñòîèò èç îäíîãî êîìáèíàòîðà. Ïîäðîáíî îá ýòîì ìîæíî ïî÷èòàòü â [18]. 3
Ïðèìåðû ñëîæíûõ êîìáèíàòîðîâ
55
Ïðèìåðû ñëîæíûõ êîìáèíàòîðîâ Âïîëíå åñòåñòâåííî, ÷òî ñîçäàòåëè êîìáèíàòîðíîé ëîãèêè íå îãðàíè÷èëèñü èñïîëüçîâàíèåì äâóõ áàçîâûõ êîìáèíàòîðîâ S è K. Õîòÿ îíè è ñîñòàâëÿþò ìèíèìàëüíûé áàçèñ, íî çàïèñü ôóíêöèé òîëüêî ÷åðåç íèõ óâåëè÷èâàåò ãðîìîçäêîñòü îïðåäåëåíèé ñ ðîñòîì ñëîæíîñòè ôóíêöèé. Ïîýòîìó äëÿ óïðîùåíèÿ çàïèñè îïðåäåëåíèé áîëåå ñëîæíûõ êîìáèíàòîðîâ è êîìáèíàòîðíûõ òåðìîâ áûëè ðàçðàáîòàíû äîïîëíèòåëüíûå êîìáèíàòîðû, èç êîòîðûõ òàêæå ìîæíî ñîñòàâëÿòü áàçèñû. Ê òàêèì êîìáèíàòîðàì îòíîñÿòñÿ ñëåäóþùèå: 1) Bxyz = x(yz). 2) Cxyz = xzy . 3) Wxy = xyy . Äàííûå êîìáèíàòîðû âåñüìà ñóùåñòâåííî ñîêðàùàþò íåêîòîðûå ïðåîáðàçîâàíèÿ4 . Ðàäè ýòîãî ìíîãèå êîìáèíàòîðû äàæå ïîëó÷èëè ñâîè ñîáñòâåííûå íàèìåíîâàíèÿ. Òàê, êîìáèíàòîð I íàçûâàåòñÿ ¾êîìáèíàòîðîì òîæäåñòâà¿, êîìáèíàòîð K ¾êàíöåëÿòîð¿, êîìáèíàòîð S ¾êîííåêòîð¿, êîìáèíàòîð B ¾êîìïîçèòîð¿, êîìáèíàòîð C ¾ïåðìóòàòîð¿ è êîìáèíàòîð W ¾äóáëèêàòîð¿. Îäíàêî âïîëíå ïîíÿòíî, ÷òî âñå ïåðå÷èñëåííûå êîìáèíàòîðû ìîæíî âûðàçèòü äðóã ÷åðåç äðóãà. Ñëåäóþùèå ôîðìóëû ïîêàçûâàþò âûðàæåíèå íîâûõ êîìáèíàòîðîâ ÷åðåç óæå èçâåñòíûå:
B ≡ S(KS)K C ≡ S((S(KS)K)(S(KS)K)S)(KK) W ≡ SS(K(SKK)) Âäóì÷èâîìó ÷èòàòåëþ ïðåäëàãàåòñÿ ñàìîñòîÿòåëüíî ïðîâåðèòü äàííûå ôîðìóëû. Äëÿ ýòîãî äîñòàòî÷íî âîñïîëüçîâàòüñÿ àêñèîìàìè äëÿ êîìáèíàòîðîâ S è K è ïîäñòàâèòü â ôîðìóëû ïåðåìåííûå â çàäàííîì êîëè÷åñòâå (ñîãëàñíî îïðåäåëåíèé). Îäíàêî âîçíèêàåò âîïðîñ: íà îñíîâàíèè ÷åãî ïîëó÷åíû ïåðå÷èñëåííûå âûðàæåíèÿ êîìáèíàòîðîâ B, C è W ÷åðåç áàçèñíûå, êàê ñîçäàòü òàêèå âûðàæåíèÿ ñàìîñòîÿòåëüíî? Ìîæíî ïîïûòàòüñÿ îòâåòèòü íà ýòîò âîïðîñ, ñàìîñòîÿòåëüíî íàéäÿ âûðàæåíèå êîìáèíàòîðà I êàê ñàìîãî ïðîñòîãî. Ýòî ìîæíî ïðîäåëàòü íà îñíîâàíèè ñëåäóþùèõ ðàññóæäåíèé... Âûðàæåíèå êîìáèíàòîðà I ìîæåò íà÷èíàòüñÿ ëèáî ñ êîìáèíàòîðà S, ëèáî ñ êîìáèíàòîðà K. Ïðè ïîìîùè öèôð â ñëåäóþùèõ çàïèñÿõ áóäóò îáîçíà÷àòüñÿ íåäîñòàþùèå îáúåêòû, êîòîðûå åù¼ íåîáõîäèìî íàéòè.  ýòîì ñëó÷àå äâà âîçìîæíûõ ïóòè ïîèñêà âûðàæåíèÿ äëÿ êîìáèíàòîðà I âûãëÿäÿò òàê: K
1) K1x = 1 ̸= x. S
2) S12x = 1x(2x) = . . . Çäåñü âèäíî, ÷òî ïåðâàÿ àëüòåðíàòèâà íå ïîäõîäèò àâòîìàòè÷åñêè, òàê êàê êàíöåëÿòîð K îòìåíÿåò ïåðåìåííóþ x, êîòîðàÿ äîëæíà ïîÿâèòüñÿ â ñàìîì êîíöå. Ñîîòâåòñòâåííî, äàëåå íàäî ðàññìàòðèâàòü òîëüêî âòîðóþ àëüòåðíàòèâó è èñêàòü ñïîñîá âûðàæåíèÿ íåèçâåñòíûõ îáúåêòîâ 1 è 2. Îíè òàêæå ìîãóò áûòü ëèáî êîìáèíàòîðîì S, ëèáî êîìáèíàòîðîì K. Ñîîòâåòñòâåííî, ïîäñòàâëÿÿ ýòè êîìáèíàòîðû âìåñòî íåèçâåñòíîãî îáúåêòà 1, ìîæíî ïîëó÷èòü:
Êñòàòè, ïåðâîíà÷àëüíî Õ. Êàððè ââ¼ë â ñâîåé ðàáîòå èìåííî êîìáèíàòîðû B è C.  äàëüíåéøåì ïåðâîíà÷àëüíûé áàçèñ áûë óïðîù¼í. 4
56
Êîìáèíàòîðû? Ýòî ïðîñòî! K
1) Kx(2x) = x. 2) Sx(2x) = ?. Êàê âèäíî, ïåðâàÿ àëüòåðíàòèâà óæå äàëà íåîáõîäèìûé ðåçóëüòàò, à âî âòîðîé àëüòåðíàòèâå íå õâàòàåò îïåðàíäîâ ó êîìáèíàòîðà S. Ïîýòîìó âòîðóþ àëüòåðíàòèâó ìîæíî íå ðàññìàòðèâàòü, à âåðíóòüñÿ òîëüêî ê ïåðâîé.  íåé îñòà¼òñÿ íåèçâåñòíûé îáúåêò 2, êîòîðûé íå ó÷àñòâóåò â öåïî÷êå âûâîäà, òàê êàê óíè÷òîæàåòñÿ êàíöåëÿòîðîì. Ïîýòîìó âìåñòî íåãî ìîæåò ñòîÿòü ëþáîé êîìáèíàòîð, íàïðèìåð âñ¼ òîò æå K. Òàê è ïîëó÷àåòñÿ, ÷òî âûðàæåíèå êîìáèíàòîðà òîæäåñòâà òàêîâî:
I ≡ SKK Ýòîò ïðèìåð òàêæå ïîêàçàë, ÷òî ñïîñîáîâ ðàçëîæåíèÿ îáúåêòîâ â êîìáèíàòîðíîì áàçèñå ñóùåñòâóåò áåñêîíå÷íîå ìíîæåñòâî, ïîýòîìó âñåãäà èìååò ñìûñë ãîâîðèòü î ¾ìèíèìàëüíîì¿ ðàçëîæåíèè, òî åñòü òàêîì, â çàïèñè êîòîðîãî èñïîëüçóåòñÿ ìèíèìàëüíîå ÷èñëî êîìáèíàòîðîâ è ñêîáîê. Íî îïèñàííûé ïðîöåññ íå òàê ïðîñò, êàê ìîæåò ïîêàçàòüñÿ íà ñàìîì äåëå. Äîñòàòî÷íî ïîïðîáîâàòü ðàçëîæèòü ïîäîáíûì îáðàçîì îòíîñèòåëüíî ïðîñòîé êîìáèíàòîð B, ÷òîáû ïîíÿòü, ÷òî â ïðîöåññå òàêîãî ðàññìîòðåíèÿ àëüòåðíàòèâ äåðåâî ðåøåíèé ðàñò¼ò ïîäîáíî ñíåæíîìó êîìó. Ïîýòîìó ðàäè îáëåã÷åíèÿ ïðîöåññà âûðàæåíèÿ îáúåêòîâ ñ çàäàííûìè êîìáèíàòîðíûìè õàðàêòåðèñòèêàìè áûëè ñîçäàíû ñïåöèàëüíûå ïðàâèëà. Äàííûå ïðàâèëà îòíîñÿòñÿ ê âûðàæåíèþ â áàçèñå S, K, I: 1) T[v] ⇒ v , ãäå v ïåðåìåííàÿ. 2) T[(E1 E2 )] ⇒ (T[E1 ]T[E2 ]). 3) T[λx.x] ⇒ I. 4) T[λx.E] ⇒ K T[E], åñëè x íåñâîáîäíà â E . 5) T[λx.λy.E] ⇒ T[λx.T[λy.E]], åñëè x ñâîáîäíà â E . 6) T[λx.(E1 E2 )] ⇒ S T[λx.E1 ]T[λx.E2 ].  ýòèõ ïðàâèëàõ èñïîëüçóåòñÿ λ-íîòàöèÿ, êîòîðàÿ ïðèíÿòà â λ-èñ÷èñëåíèè. Ïðèâåñòè êîìáèíàòîð ñ åãî ñèãíàòóðîé è õàðàêòåðèñòèêîé ê λ-íîòàöèè äîâîëüíî ïðîñòî íàäî âìåñòî ñèìâîëà, îáîçíà÷àþùåãî ñàì êîìáèíàòîð, èñïîëüçîâàòü ñèìâîë (λ), à âìåñòî ñèìâîëà (=) èñïîëüçîâàòü òî÷êó (.).  ñëåäóþùåì ðàçäåëå ïðèâåäåíû îïðåäåëåíèÿ òèïîâ äàííûõ è ôóíêöèé íà ÿçûêå Haskell, êîòîðûå îñóùåñòâëÿþò ïåðåâîä çàäàííîãî êîìáèíàòîðà â áàçèñ S, K, I. Îäíàêî äëÿ çàêðåïëåíèÿ ìàòåðèàëà ÷èòàòåëþ ïðåäëàãàåòñÿ ñàìîñòîÿòåëüíî âûðàçèòü â áàçèñå S, K, I ñëåäóþùèå êîìáèíàòîðû ñ òàêèìè õàðàêòåðèñòèêàìè5 : 1) Ψabcd = a(bc)(bd). 2) C[2] abcd = acdb. 3) C[2] abcd = adbc. 4) B2 abcd = a(bcd). 5) C[3] abcde = acdeb. 6) C[3] abcde = aebcd. 7) B3 abcde = a(bcde). 8) Φabcd = a(bd)(cd).
Äëÿ ðåøåíèÿ ýòèõ çàäà÷ ìîæåò ïîòðåáîâàòüñÿ äîïîëíèòåëüíàÿ ëèòåðàòóðà, â êîòîðîé îïèñûâàåòñÿ òàê íàçûâàåìàÿ ïðåäíàçíà÷åííàÿ äëÿ âûðàæåíèÿ èñ÷èñëåíèÿ âûñêàçûâàíèé ïåðâîãî ïîðÿäêà ÷åðåç êîìáèíàòîðû íàïðèìåð, [3]. 5
èëëàòèâíàÿ êîìáèíàòîðíàÿ ëîãèêà,
Ìîäóëü íà ÿçûêå Haskell äëÿ ïðåîáðàçîâàíèÿ êîìáèíàòîðîâ
57
Ìîäóëü íà ÿçûêå Haskell äëÿ ïðåîáðàçîâàíèÿ êîìáèíàòîðîâ  ýòîì ðàçäåëå ïðèâîäèòñÿ òåêñò ïðîãðàììû íà ÿçûêå Haskell, êîòîðàÿ ïðåîáðàçóåò çàäàííûé êîìáèíàòîð â áàçèñ S, K, I. Äëÿ òîãî ÷òîáû ïîíèìàòü ïðèâåä¼ííûå îïðåäåëåíèÿ, íåîáõîäèìî áûòü çíàêîìûì ñ ñèíòàêñèñîì ýòîãî ÿçûêà íà óðîâíå, äîñòàòî÷íîì äëÿ îïðåäåëåíèÿ òèïîâ è ôóíêöèé. Ðàññìîòðåíèå ýòèõ òåì âûõîäèò çà ðàìêè ýòîé êíèãè, ïîýòîìó çàèíòåðåñîâàííîãî ÷èòàòåëÿ ìîæíî îòîñëàòü ê ñïåöèàëèçèðîâàííîé ëèòåðàòóðå [6, 14]. Äëÿ ïðåîáðàçîâàíèÿ êîìáèíàòîðîâ íåîáõîäèìî äëÿ íà÷àëà îïðåäåëèòü òèï äàííûõ äëÿ èõ ïðåäñòàâëåíèÿ.  ñîîòâåòñòâèè ñ îïðåäåëåíèåì êîìáèíàòîðíîãî òåðìà îïðåäåëåíèå òàêîãî òèïà âûãëÿäèò òàê:
data Combinator = Var String deriving Eq
| App Combinator Combinator | Lam String Combinator
Ýòî îïðåäåëåíèå ïîëíîñòüþ ñîîòâåòñòâóåò ìàòåìàòè÷åñêîìó, êîòîðîå ãëàñèò, ÷òî êîìáèíàòîðíûé òåðì ýòî ëèáî ïåðåìåííàÿ (Var îò àíãëèéñêîãî ñëîâà ), ëèáî àáñòðàêöèÿ (Lam îò àíãëèéñêîãî ñëîâà ), ëèáî ïðèëîæåíèå îäíîãî êîìáèíàòîðíîãî òåðìà ê äðóãîìó (App îò àíãëèéñêîãî ñëîâà ). Äëÿ òîãî ÷òîáû èìåòü âîçìîæíîñòü ïðîñìàòðèâàòü ïîëó÷åííûå ðåçóëüòàòû ïðåîáðàçîâàíèÿ êîìáèíàòîðíûõ òåðìîâ, íåîáõîäèìî îïðåäåëèòü òèï Combinator ýêçåìïëÿðîì êëàññà Show, êîòîðûé ÿâëÿåòñÿ êëàññîì âåëè÷èí, êîòîðûå ìîãóò áûòü îòîáðàæåíû. Êîíå÷íî, èíòåðïðåòàòîð ÿçûêà Haskell ìîæåò ñàìîñòîÿòåëüíî îïðåäåëèòü òàêîé ýêçåìïëÿð, íî îí ñäåëàåò ýòî íå òàê êðàñèâî, êàê ìîæíî ñäåëàòü âðó÷íóþ. Ïîýòîìó ââîäèòñÿ ñëåäóþùåå îïðåäåëåíèå:
variable
lambda application
instance Show Combinator where show ( Var x )
= x
show ( App x y ) = case y of App _ _ −> showLam x ++ " ( " ++ show y ++ ")" _ −> showLam x ++ showLam y
where
showLam l@ ( Lam _ _ ) = " ( " ++ show l ++ ")" showLam x = show x show ( Lam x e )
= "\\" ++ x ++ "." ++ show e
Çäåñü âèäíî, ÷òî ïåðåìåííàÿ îòîáðàæàåòñÿ ïðîñòî ñâîèì èìåíåì, êîòîðîå ïðåäñòàâëÿåòñÿ ñòðîêîé ñèìâîëîâ. Ïðèìåíåíèå êîìáèíàòîðíûõ òåðìîâ äðóã ê äðóãó ïðîñòî çàïèñûâàåòñÿ ïåðå÷èñëåíèåì êîìáèíàòîðíûõ òåðìîâ äðóã çà äðóãîì ñî âçÿòèåì â ñêîáêè, åñëè âòîðîé òåðì ñëîæíûé. À àáñòðàêöèÿ çàïèñûâàåòñÿ ïðè ïîìîùè ñèìâîëà (\) ñ óêàçàíèåì ñèãíàòóðû è õàðàêòåðèñòèêè.
58
Êîìáèíàòîðû? Ýòî ïðîñòî!
Áàçèñ S, K, I îïðåäåëÿåòñÿ ïðè ïîìîùè êîíñòàíòíûõ ôóíêöèé, âîçâðàùàþùèõ êîìáèíàòîðíûå òåðìû â âèäå ïåðåìåííûõ ñ èçâåñòíûìè èìåíàìè:
i = Var " I " k = Var " K " s = Var " S " Äîïîëíèòåëüíî, õîòÿ ýòî è íåîáÿçàòåëüíî, ìîæíî ðåàëèçîâàòü ïðåäèêàò, êîòîðûé ïðîâåðÿåò, ÿâëÿåòñÿ ëè çàäàííàÿ ïåðåìåííàÿ ñâîáîäíîé â èññëåäóåìîì êîìáèíàòîðíîì òåðìå. Ýòîò ïðåäèêàò îïðåäåëÿåòñÿ òàê:
free free free free
:: x x x
String −> Combinator −> Bool ( Var y ) = x == y ( App e1 e2 ) = free x e1 | | free x e2 ( Lam y e ) = free x e
Âñ¼ â ïîëíîì ñîîòâåòñòâèè ñ ìàòåìàòè÷åñêèì îïðåäåëåíèåì. Íàêîíåö, ñàìà ôóíêöèÿ transform, êîòîðàÿ îñóùåñòâëÿåò ïåðåâîä êîìáèíàòîðíîãî òåðìà â áàçèñ S, K, I. ż îïðåäåëåíèå òàêæå âûãëÿäèò â ïîëíîì ñîîòâåòñòâèè ñ ïåðå÷èñëåííûìè â ïðåäûäóùåì ðàçäåëå ïðàâèëàìè òðàíñôîðìàöèè. Çäåñü ìîæíî âèäåòü âñþ ñèëó âûðàçèòåëüíîñòè ÿçûêà Haskell, êîòîðàÿ ïîçâîëÿåò çàïèñûâàòü îïðåäåëåíèÿ ôóíêöèé ïðàêòè÷åñêè â ìàòåìàòè÷åñêîé íîòàöèè.
transform : : Combinator −> Combinator transform ( Var x ) = Var x transform ( App x y ) = App ( transform x ) ( transform y ) transform ( Lam x ( Var y ) ) | x == y = i transform ( Lam x e ) | ( not . free x ) e = App k ( transform e ) transform ( Lam x l@ ( Lam y e ) ) | free x e = transform ( Lam x ( transform l ) ) transform ( Lam x ( App e1 e2 ) ) = App ( App s ( transform ( Lam x e1 ) ) ) ( transform ( Lam x e2 ) ) Âèäíî, ÷òî îïðåäåëåíèå ýòîé ôóíêöèè ïîëíîñòüþ ñîâïàäàåò ñ îïèñàíèåì ïðàâèë òðàíñôîðìàöèè êîìáèíàòîðíûõ òåðìîâ. Îäíàêî äàííàÿ ôóíêöèÿ íå ïîçâîëÿåò ïîëó÷èòü ìèíèìàëüíîå âûðàæåíèå êîìáèíàòîðíîãî òåðìà â áàçèñå S, K, I. Îíà âîçâðàùàåò îäèí èç âîçìîæíûõ âàðèàíòîâ ðàçëîæåíèÿ òåðìà. Íàïðèìåð, êîìáèíàòîð B êîäèðóåòñÿ ïðè ïîìîùè λ-íîòàöèè ñëåäóþùèì îáðàçîì:
b = Lam " x " ( Lam " y " ( Lam " z " ( App ( Var " x " ) ( App ( Var " y " ) ( Var " z " ) ) ) ) ) Åñëè ïåðåäàòü ýòî îïðåäåëåíèå ôóíêöèè transform, òî íà âûõîäå áóäåò òàêàÿ êîíñòðóêöèÿ: S(S(KS)(S(KK)(S(KS)(S(KK)I))))(K(S(S(KS)(S(KK)I))(KI)))
Ïðåäñòàâëåíèå äàííûõ è ôóíêöèé
59
Ïðåäñòàâëåíèå äàííûõ è ôóíêöèé Áûëî áû ñòðàííî, åñëè áû êîìáèíàòîðíàÿ ëîãèêà íå ìîãëà áûòü òåì èíñòðóìåíòîì, ïðè ïîìîùè êîòîðîãî ìîæíî áûëî áû âûðàæàòü ðàçëè÷íûå îáúåêòû. Äåéñòâèòåëüíî, ôîðìàëèçì êîìáèíàòîðíîé ëîãèêè, íåñìîòðÿ íà âåñüìà îãðàíè÷åííûé àëôàâèò, ÿâëÿåòñÿ âïîëíå äîñòàòî÷íûì äëÿ âûðàæåíèÿ òàêèõ áàçîâûõ ïîíÿòèé ìàòåìàòèêè, êàê áóëåâñêèå çíà÷åíèÿ èñòèíû, óïîðÿäî÷åííûå ïàðû íåêîòîðûõ çíà÷åíèé, íàòóðàëüíûå ÷èñëà, ñïèñêè. Ýòî, â ñâîþ î÷åðåäü, ïîçâîëÿåò ïðàêòè÷åñêè ïîëíîñòüþ ñìîäåëèðîâàòü òåîðèþ ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ â ðàìêàõ ïðîñòîé êîìáèíàòîðíîé ëîãèêè. Ñàì ïî ñåáå ñïîñîá êîäèðîâàíèÿ äàííûõ â ðàìêàõ êîìáèíàòîðíîé ëîãèêè íå ÿâëÿåòñÿ äîñòàòî÷íî âûðàçèòåëüíûì, áîëåå òîãî, èíîé ðàç êàæåòñÿ, ÷òî òàêîå êîäèðîâàíèå âû÷óðíî è íàäóìàííî. Ñ òî÷êè çðåíèÿ ýôôåêòèâíîñòè âû÷èñëåíèé òàêæå èìåþòñÿ ïðîáëåìû îïòèìèçàöèÿ â ïðèêëàäíûõ òðàíñëÿòîðàõ ÿçûêîâ ïðîãðàììèðîâàíèÿ ïîçâîëÿåò êîäèðîâàòü è ïðîâîäèòü âû÷èñëåíèÿ íàä çàêîäèðîâàííûìè äàííûìè áîëåå ýôôåêòèâíî. Îäíàêî ýòîò ñïîñîá êîäèðîâàíèÿ äàííûõ ÿâëÿåòñÿ äîâîëüíî èíòåðåñíûì ñ òî÷êè çðåíèÿ ìàòåìàòèêè, òàê êàê ïîçâîëÿåò ïîíÿòü â òîì ÷èñëå è òî, ÷òî äàííûå ìîãóò íåñòè âíóòðè ñåáÿ è ñïîñîáû èõ îáðàáîòêè.
Áóëåâñêèå çíà÷åíèÿ Äëÿ êîäèðîâàíèÿ áóëåâûõ âåëè÷èí íåîáõîäèìî èìåòü ñïîñîá ïðåäñòàâëåíèÿ â êîìáèíàòîðíîé ëîãèêå çíà÷åíèé true, false, à òàêæå ñëóæåáíóþ ñòðóêòóðó if . Îáû÷íî äëÿ ýòèõ öåëåé èñïîëüçóþòñÿ ñëåäóþùèå ïðàâèëà êîäèðîâàíèÿ: 1) true ≡ K; 2) false ≡ KI; 3) if ≡ I. Äåéñòâèòåëüíî, ïðåäëîæåííûé ñïîñîá êîäèðîâàíèÿ ìîæíî ëåãêî ïðîâåðèòü: I
K
if true x y ≡ I K x y = K x y = x I
K
I
if false x y ≡ I K I x y = K I x y = I y = y Êàê ìîæíî âèäåòü, êîäèðîâàíèå ñëóæåáíîãî ñëîâà if âîîáùå íå ÿâëÿåòñÿ íåîáõîäèìûì ìîæíî âïîëíå îáîéòèñü è áåç íåãî. Ñàìè ïî ñåáå çíà÷åíèÿ èñòèííîñòè ÿâëÿþòñÿ óñëîâíûìè âûðàæåíèÿìè, òàê êàê âîçâðàùàþò ïåðâûé èëè âòîðîé îïåðàíä â çàâèñèìîñòè îò ñâîåé ïðèðîäû. Ïîýòîìó êîìáèíàòîð if ÿâëÿåòñÿ òîæäåñòâîì äëÿ òð¼õ îïåðàíäîâ, ïåðâûé èç êîòîðûõ äîëæåí áûòü çíà÷åíèåì èñòèííîñòè. Âïîëíå åñòåñòâåííî, ÷òî íàä ïðåäñòàâëåííûìè çíà÷åíèÿìè èñòèííîñòè äîëæíû èìåòüñÿ ôóíêöèè äëÿ âûïîëíåíèÿ áàçîâûõ îïåðàöèé áóëåâñêîé ëîãèêè. Òàêèå áàçîâûå îïåðàöèè ìîãóò áûòü âûðàæåíû ÷åðåç óñëîâíûå âûðàæåíèÿ. Ñïîñîáû êîäèðîâàíèÿ òð¼õ áàçèñíûõ áóëåâñêèõ îïåðàöèé (îòðèöàíèå, êîíúþíêöèÿ è äèçúþíêöèÿ) âûãëÿäÿò ñëåäóþùèì îáðàçîì: 1) not ≡ C(C if false) true; 2) and ≡ B(CC false) if ; 3) or ≡ C if true. ×èòàòåëþ ïðåäëàãàåòñÿ ñàìîñòîÿòåëüíî ïðîâåðèòü äàííûå òîæäåñòâà íà ïðåäìåò èõ âåðíîñòè. Äëÿ ýòîãî íåîáõîäèìî ðàññìîòðåòü òàáëèöû èñòèííîñòè äëÿ ïåðå÷èñëåííûõ ëîãè÷åñêèõ îïåðàöèé è ñðàâíèòü èõ ñ òðàäèöèîííûìè òàáëèöàìè èñòèííîñòè.
60
Êîìáèíàòîðû? Ýòî ïðîñòî!
Íóìåðàëû ×¼ð÷à Âïîëíå ïîíÿòíî, ÷òî äëÿ êîäèðîâàíèÿ ÷èñåë èëè ïîäîáíûõ èì îáúåêòîâ ìîæíî èñïîëüçîâàòü ëþáîé ñïîñîá âûðàæåíèÿ, ãëàâíîå, ÷òîáû ïîòîì íà òàêîì ñïîñîáå ìîæíî áûëî áû ïîñòðîèòü ïðèåìëåìûå îïåðàöèè, òîæäåñòâåííûå òåì, ÷òî îïðåäåëåíû äëÿ ÷èñåë. Ïîýòîìó, ñîáñòâåííî, ñïîñîáîâ êîäèðîâàíèÿ ÷èñåë ñóùåñòâóåò ìíîæåñòâî. Íî ñàìûì ïåðâûì ñïîñîáîì áûë òîò, ÷òî ïðåäëîæåí À. ×¼ð÷åì è òåïåðü íîñèò íàèìåíîâàíèå ¾íóìåðàëû ×¼ð÷à¿. Íóìåðàëîì ×¼ð÷à ïîðÿäêà n íàçûâàåòñÿ òàêîé îáúåêò n (n íàòóðàëüíîå ÷èñëî èç ðàñøèðåííîãî ìíîæåñòâà íàòóðàëüíûõ ÷èñåë N+ ), êîòîðûé âûðàæàåòñÿ ÷åðåç áàçîâûå êîìáèíàòîðû ñëåäóþùèì îáðàçîì:
n = (SB)n (KI), ãäå ïîä çàïèñüþ (SB)n ïîíèìàåòñÿ n-êðàòíîå ïðèëîæåíèå îáúåêòà (SB) ê ñàìîìó ñåáå: (SB)0 (KI) = KI, (SB)1 (KI) = SB(KI), (SB)2 (KI) = SB(SB(KI)), (SB)3 (KI) = SB(SB(SB(KI))) è ò. ä. Òî åñòü ïî èíäóêöèè ýòè îáúåêòû ìîæíî îïðåäåëèòü êàê: 1) 0 = (SB)0 (KI) = KI; 2) n = (SB)n (KI) = SB(SBn−1 (KI)), n > 0. Ïî ñâîåé ñóòè, ýòè êîìáèíàòîðû ñîçäàþò èòåðàòèâíîå ïðèìåíåíèå çàäàííîé ôóíêöèè ê íåêîòîðîìó àðãóìåíòó, ïðè÷¼ì êîëè÷åñòâî èòåðàöèé ðàâíî îïðåäåëÿåìîìó íóìåðàëîì ÷èñëó:
0f x=x 1f x=f x n f x = f (f (. . . (f x) . . .)) | {z } n ðàç
Äëÿ ýòèõ îáúåêòîâ äîâîëüíî ïðîñòûì ñïîñîáîì ìîæíî îïðåäåëèòü ôóíêöèè äëÿ ñëîæåíèÿ, óìíîæåíèÿ è âîçâåäåíèÿ â ñòåïåíü. Ýòî äåëàåòñÿ ñëåäóþùèì îáðàçîì: 1) add ≡ CI(SB); 2) mlt ≡ B; 3) exp ≡ CI. Äîêàçàòåëüñòâî äàííûõ òîæäåñòâ ëåãêî ïðîâîäèòñÿ ïî èíäóêöèè îïÿòü æå è ïðåäëàãàåòñÿ äëÿ ñàìîñòîÿòåëüíîé ïðîðàáîòêè.
Óïîðÿäî÷åííûå ïàðû Åù¼ îäíèì äîñòàòî÷íî âàæíûì îáúåêòîì, èìåþùèì áîëüøîå ïðàêòè÷åñêîå çíà÷åíèå â ôóíêöèîíàëüíîì ïðîãðàììèðîâàíèè, ÿâëÿåòñÿ óïîðÿäî÷åííàÿ ïàðà, ñîñòîÿùàÿ èç äâóõ çíà÷åíèé. Èç ïàð ñîçäàþòñÿ ñïèñêè è ñïèñî÷íûå ñòðóêòóðû, êîòîðûå, â ñâîþ î÷åðåäü, ÿâëÿþòñÿ îäíèì èç îñíîâíûõ îáúåêòîâ îáðàáîòêè â ôóíêöèîíàëüíûõ ÿçûêàõ6 .
Íàïðèìåð, ïåðâûé ôóíêöèîíàëüíûé ÿçûê LISP íàçâàí òàê èç-çà ñâîåãî íàçíà÷åíèÿ ¾LISt Processing¿ ¾îáðàáîòêà ñïèñêîâ¿. 6
Çàêëþ÷åíèå
61
Äëÿ êîäèðîâàíèÿ ïàðû ïðè ïîìîùè êîìáèíàòîðíûõ òåðìîâ íåîáõîäèìî ñîçäàòü ôóíêöèþ, êîòîðàÿ ÿâëÿåòñÿ êîíñòðóêòîðîì òàêîé ïàðû. Ýòî ìîæíî ñäåëàòü ñëåäóþùèì îáðàçîì:
pair ≡ BC(CI) Äàííûé êîìáèíàòîð ñîñòàâëÿåò ïàðó èç äâóõ çàäàííûõ îáúåêòîâ ëþáîé ïðèðîäû. Äëÿ òîãî ÷òîáû äîñòàòü ýòè îáúåêòû èç ïàðû, íåîáõîäèìû òàê íàçûâàåìûå ¾ ¿, òî åñòü ôóíêöèè äëÿ äîñòóïà ê ýëåìåíòàì ïàðû. Ýòè ñåëåêòîðû ìîæíî îïðåäåëèòü òàê:
ñåëåêòîðû
head ≡ CI true tail ≡ CI false Ýòè êîìáèíàòîðû ¾âûíèìàþò¿ ïåðâîå èëè âòîðîå çíà÷åíèå èç ïåðåäàííîé èì íà âõîä ïàðû. Íàïðèìåð, ìîæíî äîêàçàòü, ÷òî âûðàæåíèå:
head pair xy = x äëÿ ëþáîãî âûðàæåíèÿ x. Òî æå ñàìîå ìîæíî ñêàçàòü è î ñåëåêòîðå tail. ×èòàòåëþ îïÿòü æå ðåêîìåíäóåòñÿ ïðîâåñòè èññëåäîâàíèÿ ýòîãî âûðàæåíèÿ ýòî ïîçâîëèò çàêðåïèòü èçó÷åííûé ìàòåðèàë è áîëåå òîíêî ïîíÿòü ñìûñë è íàçíà÷åíèå êîìáèíàòîðíîé ëîãèêè.
Îáùèå çàìå÷àíèÿ Íàäî îòìåòèòü, ÷òî ïðåäëîæåííûå ñïîñîáû êîäèðîâàíèÿ äàííûõ è ìåòîäîâ äëÿ èõ îáðàáîòêè ïðè ïîìîùè èíñòðóìåíòîâ êîìáèíàòîðíîé ëîãèêè ÿâëÿþòñÿ ñêîðåå íå çàäàííîé äîãìîé, íî øàáëîíàìè, ïî êîòîðûì ìîæíî ïðîèçâîäèòü âû÷èñëåíèÿ íàä çàêîäèðîâàííûìè äàííûìè. Åñëè ðàññìîòðåòü òàêèå ñïîñîáû êîäèðîâàíèÿ áîëåå ïîäðîáíî, òî âèäíî, ÷òî è íóìåðàëû ×¼ð÷à, è óïîðÿäî÷åííûå ïàðû ìîãóò ïðèíèìàòü íà âõîä íå òîëüêî ñàìè çíà÷åíèÿ äëÿ êîäèðîâàíèÿ, íî è ôóíêöèè äëÿ èõ îáðàáîòêè. Òàê, îïðåäåëåíèå ïàðû ÿâëÿåòñÿ äîñòàòî÷íî óíèâåðñàëüíûì îíî íå îãðàíè÷èâàåò ïîíÿòèå óïîðÿäî÷åííîé ïàðû êàêèìè-òî ñïåöèàëüíûìè ðàìêàìè, à îñòàâëÿåò ðàçðàáîò÷èêó âûáèðàòü ñïîñîá óïàêîâêè îáúåêòîâ â ïàðó. Ïîýòîìó ëþáàÿ ïàðà â êà÷åñòâå ôóíêöèè îæèäàåò íà âõîä íåêîòîðóþ ôóíêöèþ äâóõ àðãóìåíòîâ, êîòîðàÿ ïîñëå ïðèìåíåíèÿ âîçâðàùàåò ê èçíà÷àëüíûì îáúåêòàì è îïðåäåëÿåò ñàìó ïàðó. Ýòî çíà÷èò, ÷òî è îïåðàöèè äëÿ ðàñïàêîâêè ïàðû (ñåëåêòîðû) äîëæíû áûòü ðàçëè÷íûìè â êàæäîì êîíêðåòíîì ñëó÷àå. Ïðèâåä¼ííûå âûøå îïðåäåëåíèÿ ÿâëÿþòñÿ øàáëîíàìè. Îäíàêî è ýòè øàáëîíû ñàìè ïî ñåáå òàêæå ðàáîòàþò. Âñå ýòè ðàññóæäåíèÿ êàñàþòñÿ è îñòàëüíûõ ïðèìåðîâ (ðàññìîòðåííûõ â äàííîì ïîäðàçäåëå è âñåõ äðóãèõ). Ýòî çíà÷èò, ÷òî êîìáèíàòîðíàÿ ëîãèêà ïðåäîñòàâëÿåò ó÷¼íûì è ðàçðàáîò÷èêàì óíèâåðñàëüíûé èíñòðóìåíò äëÿ àáñòðàêòíîãî ïðîåêòèðîâàíèÿ ìåòîäîâ äëÿ ðåøåíèÿ øèðîêîãî êëàññà çàäà÷.
Çàêëþ÷åíèå Ðàññìîòðåííîå â ýòîì ðàçäåëå ââåäåíèå â îñíîâû êîìáèíàòîðíîé ëîãèêè íå ïðåòåíäóåò íà öåëîñòíîñòü èçëîæåíèÿ, äà è íåâîçìîæíî â ìàëîé íàó÷íî-ïîïóëÿðíîé êíèãå èçëîæèòü ñëîæíóþ íàóêó î âû÷èñëåíèÿõ, íà êîòîðîé îñíîâàíà ðåàëèçàöèÿ ìíîãèõ ôóíêöèîíàëüíûõ ÿçûêîâ ïðîãðàììèðîâàíèÿ. Ïîýòîìó âñåõ çàèíòåðåñîâàâøèõñÿ ÷èòàòåëåé ìîæíî îòîñëàòü ê èçó÷åíèþ êîìáèíàòîðíîé ëîãèêè è λ-èñ÷èñëåíèÿ ïî ó÷åáíèêàì, ïîëíîöåííî îïèñûâàþùèì ýòè èíòåðåñíåéøèå íàïðàâëåíèÿ ëîãèêè.  êà÷åñòâå íàïðàâëåíèé äëÿ äàëüíåéøåãî èçó÷åíèÿ ìîæíî ïîñîâåòîâàòü ðàññìîòðåíèå ñëåäóþùèõ âîïðîñîâ: 1) Ñèíòåç íîâîãî îáúåêòà ñ çàäàííûìè êîìáèíàòîðíûìè õàðàêòåðèñòèêàìè.
62
Êîìáèíàòîðû? Ýòî ïðîñòî! 2) Èñïîëüçîâàíèå ðåäóêöèè êîìáèíàòîðîâ ïðè ïîìîùè ãðàôîâ, ÷òî ïîçâîëÿåò ïðîâîäèòü ëåíèâûå âû÷èñëåíèÿ, â òîì ÷èñëå è ïîòåíöèàëüíî áåñêîíå÷íûõ ñòðóêòóð äàííûõ. 3) Ïðåîáðàçîâàíèå n-ìåñòíûõ îïåðàòîðíûõ ôóíêöèé â êàððèðîâàííûå, ïîçâîëÿþùèå ïðîèçâîäèòü ÷àñòè÷íûå âû÷èñëåíèÿ. 4) Òèïèçàöèÿ êîìáèíàòîðîâ, êîòîðàÿ ïîçâîëÿåò ðàçáèòü âñ¼ ìíîæåñòâî êîìáèíàòîðîâ íà íåêèå êëàññû ýêâèâàëåíòíîñòè ïî èõ òèïàì (ñîðòàì). 5) Îáîëî÷êà Êàðóáè ñïåöèàëüíàÿ êàòåãîðèÿ â ðàìêàõ êîìáèíàòîðíîé ëîãèêè, ïðè ïîìîùè êîòîðîé êîäèðóþòñÿ âñå îáúåêòû îïåðàòîðíûõ âû÷èñëåíèé, â òîì ÷èñëå è èõ òèïû. 6) Âûðàæåíèå ïðè ïîìîùè êîìáèíàòîðîâ ðàçëè÷íûõ ñèñòåì ïðîãðàììèðîâàíèÿ, â òîì ÷èñëå âûðàæåíèå ÿçûêîâ Lisp, Haskell è ïðî÷èõ. 7) Èçó÷åíèå ñóïåðêîìáèíàòîðîâ îáúåêòîâ äëÿ ëåíèâîãî âû÷èñëåíèÿ çíà÷åíèé íåêîòîðûõ âûðàæåíèé. 8) Îïòèìèçàöèÿ âû÷èñëåíèé ïóò¼ì êîìáèíèðîâàíèÿ ïàðàìåòðîâ øàã ê ïîñòðîåíèþ ñèñòåì ñóïåðêîìïèëÿöèè. 9) Òåõíèêè ïðîâåäåíèÿ ñèíòàêñè÷åñêîãî àíàëèçà â ñâåòå ïðèìåíåíèÿ îíîãî äëÿ èíòåðïðåòàöèè òåêñòîâ íà ôóíêöèîíàëüíûõ ÿçûêàõ ïðîãðàììèðîâàíèÿ (íåïîñðåäñòâåííûå âû÷èñëåíèÿ çíà÷åíèé, êîäèðîâàíèå ïî äå Áðåéíó, êàòåãîðèàëüíàÿ àáñòðàêòíàÿ ìàøèíà è ò. ä.).
Ïîäðîáíî ïðî êîìáèíàòîðíóþ ëîãèêó ìîæíî íà ñïåöèàëèçèðîâàííûõ íàó÷íûõ èíòåðíåò-ðåñóðñàõ.
ïî÷èòàòü
â
èñòî÷íèêàõ
[1,
3,
6]
ëèáî
Ââîä è âûâîä íà ÿçûêå Haskell Ñòàòüÿ áûëà îïóáëèêîâàíà â 12 (36) æóðíàëà ¾Ïîòåíöèàë¿ â äåêàáðå 2007 ãîäà.
 íàñòîÿùåì ýññå ïðèìåíèòåëüíî ê ôóíêöèîíàëüíîìó ÿçûêó Haskell ðàññìàòðèâàåòñÿ òàêîé íåìàëîâàæíûé àñïåêò ëþáîãî ÿçûêà ïðîãðàììèðîâàíèÿ, êàê ñèñòåìà ââîäà/âûâîäà. Ïðèâîäÿòñÿ îñíîâíûå îïðåäåëåíèÿ, ñïîñîáû èñïîëüçîâàíèÿ è ïðèìåðû ïîñòðîåíèÿ ôóíêöèé, ðåàëèçóþùèõ ââîä/âûâîä è âçàèìîäåéñòâèå ñ âíåøíèì ìèðîì (îêðóæåíèåì ïðîãðàììû).
Ââåäåíèå
÷èñòûì
ßçûê Haskell ÿâëÿåòñÿ ôóíêöèîíàëüíûì ÿçûêîì ïðîãðàììèðîâàíèÿ, à ýòî çíà÷èò, ÷òî ëþáàÿ ôóíêöèÿ, êîòîðàÿ îïðåäåëåíà ïðè ðàçðàáîòêå ïðîãðàìì, äîëæíà áûòü , à òàêæå íå äîëæíà èñïîëüçîâàòü â ñâîåé ðàáîòå òàê íàçûâàåìûå . Ïîä äåòåðìèíèðîâàííîñòüþ ôóíêöèé ïîíèìàåòñÿ òàêîå ñâîéñòâî, ÷òî ðåçóëüòàò, âû÷èñëÿåìûé ôóíêöèåé, çàâèñèò òîëüêî îò çíà÷åíèé âõîäíûõ ïàðàìåòðîâ. Ýòî çíà÷èò, ÷òî äëÿ ëþáîãî çàäàííîãî íàáîðà çíà÷åíèé âõîäíûõ ïàðàìåòðîâ ðåçóëüòàò äåòåðìèíèðîâàí (îïðåäåë¼í) ôóíêöèåé. Äâà âûçîâà ôóíêöèè ñ îäíèì è òåì æå íàáîðîì çíà÷åíèé âõîäíûõ ïàðàìåòðîâ âñåãäà âîçâðàòÿò îäèí è òîò æå ðåçóëüòàò. Îòñóòñòâèå ïîáî÷íûõ ýôôåêòîâ îçíà÷àåò, â ñâîþ î÷åðåäü, ÷òî ôóíêöèÿ â ïðîöåññå ñâîåé ðàáîòû îáðàùàåòñÿ è èçìåíÿåò òîëüêî òó îáëàñòü ïàìÿòè, êîòîðàÿ âûäåëåíà äëÿ å¼ ðàáîòû.  ôóíêöèîíàëüíîì ïðîãðàììèðîâàíèè â ýòîé îáëàñòè ïàìÿòè ðàñïîëîæåíû çíà÷åíèÿ âûõîäíûõ ïàðàìåòðîâ, êîòîðûå äîñòóïíû òîëüêî äëÿ ÷òåíèÿ, à òàêæå ðåçóëüòàò âûïîëíåíèÿ ôóíêöèè, êîòîðûé äîñòóïåí äëÿ ÷òåíèÿ è çàïèñè. Êðîìå òîãî, â îáëàñòè ïàìÿòè, âûäåëåííîé äëÿ ðàáîòû ôóíêöèè, ìîãóò áûòü ñîçäàíû òàê íàçûâàåìûå , òî åñòü ëîêàëüíûå ïåðåìåííûå, îáëàñòü âèäèìîñòè (êîíòåêñò) êîòîðûõ îãðàíè÷åíà ôóíêöèåé. Âñ¼ âûøåïåðå÷èñëåííîå íàëàãàåò íà ÷èñòûé ÿçûê ïðîãðàììèðîâàíèÿ îïðåäåë¼ííûå îãðàíè÷åíèÿ. Íàïðèìåð, íåâîçìîæíî ïðîãðàììèðîâàòü â òåðìèíàõ èçìåíåíèÿ íåêîòîðûõ ãëîáàëüíûõ ïåðåìåííûõ, ïîñêîëüêó èõ èñïîëüçîâàíèå ñäåëàåò íåêîòîðûå ôóíêöèè íåäåòåðìèíèðîâàííûìè (ôóíêöèÿ, ê ïðèìåðó, ìîæåò âîçâðàùàòü çíà÷åíèå íåêîòîðîé ãëîáàëüíîé ïåðåìåííîé, êîòîðàÿ èçìåíÿåòñÿ èç äðóãîé ôóíêöèè, à ïîòîìó â çàâèñèìîñòè îò âðåìåíè âûçîâà ïåðâîé ôóíêöèè å¼ ðåçóëüòàò ìîæåò áûòü ðàçëè÷íûì) è èñïîëüçóþùèìè ñòîðîííèå ýôôåêòû (èçìåíåíèå ãëîáàëüíûõ ïåðåìåííûõ è åñòü ñòîðîííèé ýôôåêò). Äðóãàÿ ïðîáëåìà ñèñòåìà ââîäà/âûâîäà ÿçûêà, òî åñòü îáùåíèå ñ âíåøíèì ìèðîì (èëè, êàê ãîâîðÿò, ñ ).  îáùåì âèäå ââîä/âûâîä ìîæíî ïîíèìàòü êàê ÷òåíèå èíôîðìàöèè ñ êàêîãîëèáî âíåøíåãî óñòðîéñòâà (íàïðèìåð, êëàâèàòóðû), à òàêæå çàïèñü äàííûõ îïÿòü-òàêè íà âíåøíåå óñòðîéñòâî (íàïðèìåð, â âèäåîïàìÿòü òåðìèíàëà). Äëÿ ïîíèìàíèÿ ñóùíîñòè ïðîáëåìû îðãàíèçàöèè ñèñòåìû ââîäà/âûâîäà â ÷èñòîì ÿçûêå ïðîãðàììèðîâàíèÿ íåîáõîäèìî äåòàëüíî ðàññìîòðåòü îáà ñëó÷àÿ. , òî åñòü ÷òåíèå äàííûõ ñ âíåøíåãî óñòðîéñòâà êëàâèàòóðû, ìûøè, èç ôàéëà, èç ñåòè è ò. ä. Íàïðèìåð, ïóñòü èìååòñÿ íåêîòîðàÿ ôóíêöèÿ read, êîòîðàÿ ñ÷èòûâàåò ñ êëàâèàòóðû îäèí ñèìâîë è âîçâðàùàåò åãî. Êàêîâ äîëæåí áûòü òèï ýòîé ôóíêöèè? Ñîâåðøåííî ÿñíî, ÷òî ïðèíèìàòü íà âõîä
çàìûêàíèÿ
îêðóæåíèåì ïðîãðàììû Ââîä
äåòåðìèíèðîâàííîé ïîáî÷íûå ýôôåêòû
64
Ââîä è âûâîä íà ÿçûêå Haskell
åé íè÷åãî íå íóæíî. À âîçâðàùàåò òàêàÿ ôóíêöèÿ ñèìâîë, òî åñòü çíà÷åíèå òèïà Char. Òàêèì îáðàçîì, å¼ (îïèñàíèå òèïà) âûãëÿäèò ñëåäóþùèì îáðàçîì:
ñèãíàòóðà
read : : Char Îäíàêî ÿñíî, ÷òî ýòà ôóíêöèÿ íåäåòåðìèíèðîâàíà, ïîñêîëüêó å¼ ðåçóëüòàò áóäåò çàâèñåòü îò òîãî, êàêîé ñèìâîë íà êëàâèàòóðå íàæàë ïîëüçîâàòåëü. Åñëè ïîëüçîâàòåëü íàæì¼ò êíîïêó ¾A¿, ôóíêöèÿ âåðí¼ò ñèìâîë ñ êîäîì 65. Íàæì¼ò äðóãóþ êíîïêó ôóíêöèÿ âîçâðàòèò äðóãîé êîä. Ïîëíàÿ íåäåòåðìèíèðîâàííîñòü â ïîâåäåíèè. , òî åñòü çàïèñü äàííûõ íà íåêîòîðîå âíåøíåå óñòðîéñòâî íà ýêðàí, â ôàéë, â ñåòü è ò. ä. Òàêæå ïóñòü èìååòñÿ íåêîòîðàÿ ôóíêöèÿ put, êîòîðàÿ âûâîäèò çàäàííûé ñèìâîë íà ýêðàí. Êàêîé òèï ó ýòîé ôóíêöèè? ßñíî, ÷òî îíà äîëæíà ïðèíèìàòü íà âõîä îäèí ïàðàìåòð êîä ñèìâîëà, êîòîðûé äîëæåí áûòü âûâåäåí. Òàê ÷òî òèï ïåðâîãî (åäèíñòâåííîãî) ïàðàìåòðà Char. À ÷òî äîëæíà âîçâðàùàòü ýòà ôóíêöèÿ? Êàêîå çíà÷åíèå? Ñîâåðøåííî íå ÿñíî. Ñêîðåå âñåãî, îíà íå äîëæíà âîçâðàùàòü íè÷åãî.  ÿçûêàõ ïðîãðàììèðîâàíèÿ òèïà C äëÿ ýòèõ öåëåé èñïîëüçóåòñÿ òèï void.  ÿçûêå Haskell èñïîëüçóåòñÿ òèï ¾ ¿, òî åñòü ïîñëåäîâàòåëüíîñòü çíà÷åíèé, ñîñòîÿùàÿ èç íóëÿ ýëåìåíòîâ, (). Òàê ÷òî ñèãíàòóðà ôóíêöèè put âûãëÿäèò òàê:
Âûâîä
ïóñòîé êîðòåæ
put : : Char −> ( ) Ýòà ôóíêöèÿ èñïîëüçóåò ñòîðîííèå ýôôåêòû, ïîñêîëüêó ìîäèôèöèðóåò âíåøíþþ ïàìÿòü âèäåîïàìÿòü ýêðàíà, íà êîòîðûé ïðîèçâîäèòñÿ âûâîä. Åñëè áû ôóíêöèÿ çàïèñûâàëà èíôîðìàöèþ â ôàéë, îíà ìîäèôèöèðîâàëà áû ïàìÿòü íà íîñèòåëå èíôîðìàöèè, ãäå çàïèñàí ôàéë. Âèäíî, ÷òî è ââîä, è âûâîä ÿâëÿþòñÿ íåäîïóñòèìûìè ñ òî÷êè çðåíèÿ ÷èñòîãî ÿçûêà ïðîãðàììèðîâàíèÿ. Îäíàêî ÿâëÿåòñÿ ñîâåðøåííåéøèì àáñóðäîì îòñóòñòâèå ñèñòåìû ââîäà/âûâîäà â ÿçûêå ïðîãðàììèðîâàíèÿ îáùåãî íàçíà÷åíèÿ. Äëÿ ÷åãî íóæåí òàêîé ÿçûê? Êàê îðãàíèçîâûâàòü âçàèìîäåéñòâèå ñ ïîëüçîâàòåëåì? Êàê ðàáîòàòü ñ ôàéëàìè? Êàê îðãàíèçîâûâàòü ìíîãîïîòîêîâûå ïðîãðàììû è ðàñïðåäåë¼ííûå âû÷èñëåíèÿ ñ ïåðåäà÷åé èíôîðìàöèè ìåæäó ïîòîêàìè? Êàê âçàèìîäåéñòâîâàòü ñ âíåøíèìè ïðîãðàììàìè ïî ñåòè? Âåäü áåç ïåðå÷èñëåííûõ òåõíîëîãèé â ñîâðåìåííîì ìèðå äåëàòü íå÷åãî. È åñëè â ÿçûêå ïðîãðàììèðîâàíèÿ íå ñóùåñòâóåò ñðåäñòâ äëÿ ðàáîòû ñ íèìè, ýòîìó ÿçûêó ïðîñòî íåò ìåñòà â àðñåíàëå ñîâðåìåííîãî ïðîãðàììèñòà. Åñòåñòâåííî, ÷òî â ÿçûêå Haskell èìåþòñÿ âñå íåîáõîäèìûå ñðåäñòâà äëÿ ðàáîòû ñ ïåðå÷èñëåííûìè òåõíîëîãèÿìè (è äàæå áîëüøå), ïîñêîëüêó ýòîò ÿçûê ÿâëÿåòñÿ ÿçûêîì îáùåãî íàçíà÷åíèÿ. Íî âîçíèêàåò ðåçîííûé âîïðîñ: êàê ìîæåò óæèòüñÿ ÷èñòîòà ÿçûêà ñ çàâåäîìî ¾íå÷èñòûìè¿ ñïîñîáàìè âû÷èñëåíèé? Ýòîò âîïðîñ íà ïðèìåðå ñèñòåìû ââîäà/âûâîäà è áóäåò äåòàëüíî èññëåäîâàí â ýòîì ðàçäåëå äàëåå.
Îñíîâû ôóíêöèîíàëüíîãî ââîäà/âûâîäà Âñå ïðåäûäóùèå ðàçäåëû, ïîñâÿù¼ííûå âîïðîñàì èñïîëüçîâàíèÿ ÿçûêà Haskell, îáõîäèëèñü áåç ââîäà èëè âûâîäà èíôîðìàöèè. Ðàññìàòðèâàëèñü îáùèå âîïðîñû, îïðåäåëÿëèñü òèïû è âçàèìîñâÿçàííûå ôóíêöèè, à ðåçóëüòàòû èõ ðàáîòû èññëåäîâàëèñü ïðè ïîìîùè èíòåðïðåòàòîðà (íàïðèìåð, HUGS 98). Èíòåðïðåòàòîð âñåãäà âûâîäèò íà ýêðàí ðåçóëüòàò, âîçâðàùàåìûé ôóíêöèåé, à ïîòîìó èñïîëüçîâàíèå ââîäà/âûâîäà ïðè âûïîëíåíèè ðàñ÷¼òíûõ çàäà÷ ñìûñëà îñîáîãî íå èìåëî. Îäíàêî ðàçðàáîòêà ñîâðåìåííîãî ïðîãðàììíîãî îáåñïå÷åíèÿ, êàê óæå óêàçàíî âî ââåäåíèè, íå ìîæåò îáîéòèñü áåç âçàèìîäåéñòâèÿ ñ îêðóæåíèåì ïðîãðàììû, â ïåðâóþ î÷åðåäü áåç âçàèìîäåéñòâèÿ ñ ïîëüçîâàòåëåì. Èíòåðàêòèâíûå ïðîãðàììû óæå íàñòîëüêî ïëîòíî âîøëè â íàøó æèçíü, ÷òî ðàáîòà ñ èíòåðïðåòàòîðàìè äëÿ ïîëó÷åíèÿ ðåçóëüòàòîâ âûãëÿäèò ãëóáîêî àðõàè÷íîé. Òàê ÷òî äëÿ óìåíèÿ ñîçäàâàòü àêòèâíî âçàèìîäåéñòâóþùèå ïðîãðàììû íåîáõîäèìî èçó÷èòü îñíîâû ñèñòåìû ââîäà/âûâîäà â ÿçûêå Haskell. Íî êàê áûòü ñ íåäåòåðìèíèðîâàííîñòüþ è íàëè÷èåì ïîáî÷íûõ ýôôåêòîâ? Åñëè ïðèíÿòü èõ êàê åñòü, ìîæíî ðàñïðîùàòüñÿ ñ ÷èñòîòîé ÿçûêà. Íåîáõîäèìî îòìåòèòü, ÷òî íåêîòîðûå ôóíêöèîíàëüíûå ÿçûêè
Îñíîâû ôóíêöèîíàëüíîãî ââîäà/âûâîäà
65
ïîøëè â ñâîåé ýâîëþöèè èìåííî ïî ýòîìó ïóòè èõ ðàçðàáîò÷èêè ïîæåðòâîâàëè ÷èñòîòîé, íî âíåäðèëè â ÿçûê îáû÷íóþ ñèñòåìû ââîäà/âûâîäà. Íî ðàçðàáîò÷èêè ÿçûêà Haskell ïîøëè èíûì ïóò¼ì.  ÿçûêå Haskell ñîçäàí íåêîòîðûé äîñòàòî÷íî óçêèé ¾ìèðîê¿, ãäå ðàçðåøåíû íåäåòåðìèíèðîâàííîñòü è ïîáî÷íûå ýôôåêòû. Ýòîò ¾ìèðîê¿ îãðàíè÷åí â ñëó÷àå ñèñòåìû ââîäà/âûâîäà åäèíñòâåííûì òèïîì äàííûõ, ñ êîòîðûì ìîæíî ðàáîòàòü, IO. Ëþáàÿ ôóíêöèÿ, êîòîðàÿ îñóùåñòâëÿåò ââîä èëè âûâîä, äîëæíà âîçâðàùàòü (à èíîãäà è ïðèíèìàòü íà âõîä) çíà÷åíèÿ òèïà IO. È áîëåå òîãî, íåò âîçìîæíîñòè âûõîäà èç ýòîãî ìàëåíüêîãî ¾ìèðêà¿ êàê òîëüêî íåêîòîðûé âû÷èñëèòåëüíûé ïðîöåññ ¾ïîïàë â ëàïû¿ ê ñèñòåìå ââîäà/âûâîäà, îí îáðå÷¼í îñòàòüñÿ â íåé äî êîíöà. Èòàê, ðàññìîòðåííûå âî ââåäåíèè ãèïîòåòè÷åñêèå ôóíêöèè read è put â ýòîì ñëó÷àå äîëæíû èìåòü ñëåäóþùèå ñèãíàòóðû:
read : : IO Char put : : Char −> IO ( )
êîíòåéíåðíûé òèï
Êàê âèäíî èç ýòèõ îïèñàíèé, òèï IO ïðåäñòàâëÿåò ñîáîé âíóòðè ñåáÿ îí ìîæåò ñîäåðæàòü çíà÷åíèÿ ïðîèçâîëüíîãî òèïà (ïðî êîíòåéíåðíûå òèïû äîïîëíèòåëüíî ìîæíî ïðî÷èòàòü â ýññå ¾Àëãåáðàè÷åñêèå òèïû äàííûõ â ÿçûêå Haskell¿ â íàñòîÿùåì ñáîðíèêå). Äðóãèì êîíòåéíåðíûì òèïîì, ê ïðèìåðó, ÿâëÿåòñÿ ñïèñîê [] . Äà è áîëåå òîãî, ëþáîé , åñëè òîëüêî ýòî íå , ÿâëÿåòñÿ êîíòåéíåðíûì òèïîì. Òàê ÷òî â ýòîì íåò íè÷åãî îñîáåííîãî. Òèï äàííûõ IO êàê áû îáîðà÷èâàåò ñîáîé íåäåòåðìèíèðîâàííûå îïåðàöèè è îïåðàöèè, ñâÿçàííûå ñ ïîáî÷íûìè ýôôåêòàìè. Ïîýòîìó â ðàìêàõ ñèñòåìû ââîäà/âûâîäà òàêèå îïåðàöèè è ìîãóò ïðîèñõîäèòü òîëüêî âíóòðè òèïà IO. Ýòî ñäåëàíî äëÿ òîãî, ÷òîáû îñòàâèòü ñàì ÿçûê Haskell ÷èñòûì. Íî ýòî åù¼ íå âñ¼. Äëÿ âûñòðàèâàíèÿ ïîñëåäîâàòåëüíîñòè äåéñòâèé ââîäà/âûâîäà â ñèíòàêñèñå ÿçûêà Haskell èìååòñÿ ñïåöèàëüíîå êëþ÷åâîå ñëîâî do, êîòîðîå ïîçâîëÿåò ïîñëåäîâàòåëüíî âûïîëíèòü íåñêîëüêî îïåðàöèé ââîäà/âûâîäà îäíó çà äðóãîé. Íàïðèìåð, ïðè ïîìîùè èññëåäîâàííûõ ðàíåå ãèïîòåòè÷åñêèõ ôóíêöèé read è put ìîæíî íàïèñàòü íåñëîæíóþ ïðîãðàììó ñ÷èòàòü ñèìâîë ñ êëàâèàòóðû è âûâåñòè åãî íà ýêðàí. Íà ÿçûêå Haskell ýòî áóäåò âûãëÿäåòü ñëåäóþùèì îáðàçîì:
àëãåáðàè÷åñêèé òèï äàííûõ
ïåðå÷èñëåíèå
do c <− read put c
äâóìåðíûé ñèíòàêñèñ
Êëþ÷åâîå ñëîâî do ïîääåðæèâàåò òàê íàçûâàåìûé , êîãäà ïîñëåäîâàòåëüíîñòü îïåðàöèé ââîäà/âûâîäà ìîæíî íå îòäåëÿòü äðóã îò äðóãà òî÷êîé ñ çàïÿòîé (;), êàê òîãî òðåáóåò ñòðîãèé ñèíòàêñèñ ÿçûêà, à çàïèñûâàòü â ñòîëáèê äðóã ïîä äðóãîì. Ãëàâíîå, ÷òîáû íà÷àëî êàæäîé îïåðàöèè íàõîäèëîñü íà òîì æå çíàêîìåñòå íà íîâîé ñòðîêå, ÷òî è âåñü ñòîëáåö (çàîäíî íåîáõîäèìî îòìåòèòü, ÷òî äâóìåðíûé ñèíòàêñèñ ïîâñåìåñòíî èñïîëüçóåòñÿ â ÿçûêå Haskell è äëÿ çàïèñè äðóãèõ ÿçûêîâûõ êîíñòðóêöèé).  ñèíòàêñèñå êëþ÷åâîãî ñëîâà do èìåþòñÿ äâà ìîìåíòà. Ïåðâûé èñïîëüçîâàíèå ñèìâîëà (<−). Ýòîò ñèìâîë ââîäèò , êîòîðûé ñîïîñòàâëÿåòñÿ ñî çíà÷åíèåì, êîòîðîå âîçâðàùàåòñÿ ôóíêöèåé ïîñëå ñèìâîëà (<−). Åñëè ñîïîñòàâëåíèå ïðîøëî óñïåøíî, òî íèæå ýòîò îáðàçåö ìîæíî èñïîëüçîâàòü ñ ôàêòè÷åñêèì çíà÷åíèåì. Êðîìå òîãî, ñèìâîë (<−) ¾ðàçâîðà÷èâàåò¿ òèï IO, ïîýòîìó òèï çíà÷åíèé â îáðàçöå íå èìååò êîíòåéíåðíîé îáîëî÷êè. Òàê ÷òî âûïîëíåíèå ïåðâîé îïåðàöèè ââîäà/âûâîäà â ïðèìåðå âûøå çàïèøåò â îáðàçåö c êîä ñèìâîëà, êîòîðûé ïîëüçîâàòåëü ââ¼ë ïðè ïîìîùè êëàâèàòóðû. Âòîðîé ìîìåíò îïåðàöèè ââîäà/âûâîäà áåç ñèìâîëà (<−). Ýòè îïåðàöèè ïðîñòî âûïîëíÿþòñÿ, òàê ÷òî â ïðèìåðå âûøå âî âòîðîé ñòðîêå íà ýêðàí áóäåò âûâåäåí ñèìâîë, êîä êîòîðîãî çàïèñàí â îáðàçöå c. Êàê âèäíî, ôóíêöèÿ put ïðèíèìàåò àðãóìåíò òèïà Char, è èìåííî òàêîé òèï èìååò çíà÷åíèå â îáðàçöå c, íåñìîòðÿ íà òî ÷òî ôóíêöèÿ read âîçâðàùàåò çíà÷åíèå òèïà IO Char. Êðîìå óêàçàííûõ äâóõ òèïîâ îïåðàöèé ââîäà/âûâîäà, â êîíñòðóêöèè do ìîãóò ïðèñóòñòâîâàòü îïðåäåëåíèÿ çàìûêàíèé ïîñðåäñòâîì êëþ÷åâîãî ñëîâà let, ïðè ýòîì èñïîëüçîâàíèå êëþ÷åâîãî ñëîâà in íå íóæíî. Ýòî ñèíòàêñè÷åñêîå ïîñëàáëåíèå, êîòîðîå âåä¼ò ê òîìó, ÷òî ñëåäóþùèå äâà ïðèìåðà òîæäåñòâåííû ñ òî÷êè çðåíèÿ òðàíñëÿòîðà ÿçûêà Haskell.
îáðàçåö
66
Ââîä è âûâîä íà ÿçûêå Haskell
l e t p = someFunction a1 a2 a3 in do outputProcess p do l e t p = someFunction a1 a2 a3 outputProcess p Åù¼ îäèí àñïåêò âëîæåíèå âûðàæåíèé do äðóã â äðóãà. Ìîæíî íåîãðàíè÷åííî âêëàäûâàòü ñïèñêè îïåðàöèé ââîäà/âûâîäà äðóã â äðóãà, òîëüêî íåîáõîäèìî ïîìíèòü, ÷òî âûðàâíèâàíèå îïåðàöèé â ñòðîêàõ ñîîòâåòñòâóåò òîìó èëè èíîìó óðîâíþ âûðàæåíèÿ do. Íàðóøåíèå ïðèíöèïîâ äâóìåðíîãî ñèíòàêñèñà ìîæåò ïðèâåñòè íå òîëüêî ê ñèíòàêñè÷åñêèì îøèáêàì, íî è ê ëîãè÷åñêèì, êîòîðûå íå ïðîÿâëÿþòñÿ íà ýòàïå êîìïèëÿöèè, íî ñàìûì áåñïîùàäíûì îáðàçîì íàðóøàþò ðàáîòîñïîñîáíîñòü ïðîãðàììû âî âðåìÿ å¼ èñïîëíåíèÿ. Êðîìå òîãî, òàêèå îøèáêè î÷åíü ñëîæíî îòëàâëèâàòü. Íàêîíåö, íåîáõîäèìî óïîìÿíóòü, ÷òî ëþáîå âûðàæåíèå do èìååò òèï (âïðî÷åì, êàê è ëþáîå âûðàæåíèå â ôóíêöèîíàëüíîé ïàðàäèãìå). Òèï âûðàæåíèÿ do ðàâåí òèïó ïîñëåäíåé îïåðàöèè ââîäà/âûâîäà â ñïèñêå. Ïîýòîìó â ñïèñêå îïåðàöèé ââîäà/âûâîäà íà ïîñëåäíåì ìåñòå îáÿçàòåëüíî äîëæíà ñòîÿòü îïåðàöèÿ, êîòîðàÿ èìååò íåêîòîðûé òèï, à íå âîçâðàùàåò åãî â îáðàçåö (òî åñòü â ïîñëåäíåé ñòðîêå âûðàæåíèÿ do íå äîëæíî èñïîëüçîâàòüñÿ ñèìâîëà (<−), ðàâíî êàê è ëîêàëüíîãî îïðåäåëåíèÿ let). Ïîñêîëüêó âûðàæåíèå do ÿâëÿåòñÿ îáû÷íûì âûðàæåíèåì ñ òî÷êè çðåíèÿ òðàíñëÿòîðà ÿçûêà Haskell, îíî ìîæåò èñïîëüçîâàòüñÿ âî âñåõ òåõ ìåñòàõ, ãäå èìååò ñìûñë èñïîëüçîâàíèå âûðàæåíèÿ ñîîòâåòñòâóþùåãî òèïà. Ïîýòîìó, ê ïðèìåðó, ìîæíî ñîçäàâàòü ñëåäóþùèå îáúåêòû (çíà÷åíèÿ):
ioList = [ do { c1 <− read ; c2 <− read ; put ' > '} , put ' a ' , do { put ' b ' ; put ' c ' } ] ×òî èíòåðåñíî, îïðåäåë¼ííàÿ òàêèì îáðàçîì ôóíêöèÿ íå ïðèâåä¼ò ê âûïîëíåíèþ êàêèõ-ëèáî îïåðàöèé ââîäà/âûâîäà. Ïðè å¼ âûçîâå ïðîèçîéä¼ò ïðîñòîé âîçâðàò ñïèñêà, ñîñòîÿùåãî èç òð¼õ îïåðàöèé ââîäà/âûâîäà, êàæäàÿ èç êîòîðûõ èìååò òèï IO (). Òàê ÷òî òèï ôóíêöèè ioList ðàâåí [ IO ()] . Ýòî çàìå÷àòåëüíîå ñâîéñòâî ñèñòåìû ââîäà/âûâîäà â ÿçûêå Haskell, êîòîðîå äåëàåò ñàìó ñèñòåìó ïîëíîñòüþ ôóíêöèîíàëüíîé.
Ñòàíäàðòíûå ôóíêöèè ââîäà/âûâîäà  ñòàíäàðòíîì ìîäóëå Prelude îïðåäåë¼í áàçîâûé íàáîð ôóíêöèé, ðàáîòàþùèõ ñ ñèñòåìîé ââîäà/âûâîäà â ÿçûêå Haskell. Ýòèõ áàçîâûõ ôóíêöèé âïîëíå äîñòàòî÷íî äëÿ ðåøåíèÿ áîëüøèíñòâà ïðèêëàäíûõ çàäà÷.  ñòàíäàðòíîé ïîñòàâêå ëþáîãî òðàíñëÿòîðà ÿçûêà èìååòñÿ òàêæå äîïîëíèòåëüíûé ìîäóëü IO, â êîòîðîì îïðåäåëåíû ðàñøèðåííûå âîçìîæíîñòè, ïîçâîëÿþùèå ðàáîòàòü ñ êàíàëàìè, èñêëþ÷åíèÿìè (õîòÿ è â ìîäóëå Prelude èìåþòñÿ ñðåäñòâà äëÿ ýòîãî, íî âåñüìà îãðàíè÷åííûå) è ïðåäîñòàâëÿþùèå ìíîæåñòâî âñïîìîãàòåëüíûõ ôóíêöèé äëÿ ðàáîòû ñ ôàéëàìè, êîíñîëüþ è êëàâèàòóðîé. Ìîäóëü IO ÿâëÿåòñÿ äîñòàòî÷íî áîëüøèì, åãî îïèñàíèå âûõîäèò çà ðàìêè ýòîé êíèãè. Ïîýòîìó íèæå îïèñûâàþòñÿ òîëüêî íåêîòîðûå ôóíêöèè èç ñòàíäàðòíîãî ìîäóëÿ Prelude, êîòîðûå ïîçâîëÿò â ñëåäóþùåì ïîäðàçäåëå ñîçäàòü íåñêîëüêî èíòåðåñíûõ ïðèêëàäíûõ ïðîãðàìì. Ñàìûì ïåðâûì îáúåêòîì, êîòîðûé îïðåäåë¼í â ñèñòåìå ââîäà/âûâîäà Haskell, ÿâëÿåòñÿ ñèíîíèì òèïà äëÿ ïðåäñòàâëåíèÿ ïóòåé ê ôàéëàì. Ýòîò ñèíîíèì îïðåäåë¼í èñêëþ÷èòåëüíî äëÿ óäîáî÷èòàåìîñòè ñèãíàòóð ôóíêöèé, ðàáîòàþùèõ ñ ôàéëàìè. Åãî îïðåäåëåíèå âûãëÿäèò ñëåäóþùèì îáðàçîì:
type FilePath = String Âòîðîé âàæíûé òèï, êîòîðûé èñïîëüçóåòñÿ ïðè ðàáîòå ñ ôàéëàìè, ïðåäñòàâëÿåò ñîáîé ïåðå÷èñëåíèå, îïèñûâàþùåå ðåæèìû îòêðûòèÿ ôàéëîâ îòêðûòèå äëÿ ÷òåíèÿ, çàïèñè, äîçàïèñûâàíèÿ; à òàêæå äëÿ ÷òåíèÿ è çàïèñè îäíîâðåìåííî. Ýòî ñòàíäàðòíûå êîíñòàíòû, êîòîðûå ïîääåðæèâàþòñÿ áîëüøèíñòâîì ñîâðåìåííûõ îïåðàöèîííûõ ñèñòåì:
Ñòàíäàðòíûå ôóíêöèè ââîäà/âûâîäà
67
data IOMode ReadMode WriteMode AppendMode ReadWriteMode deriving ( Eq , Ord , Ix , Bounded , Enum , Read , Show )
= | | |
Î÷åíü âàæíûìè ôóíêöèÿìè ÿâëÿþòñÿ ôóíêöèè äëÿ ðàáîòû ñ äåñêðèïòîðàìè ôàéëîâ. Âñå îíè îïðåäåëåíû â âèäå , òî åñòü îáúåêòîâ, çàïðÿòàííûõ ãëóáîêî â íåäðàõ òðàíñëÿòîðîâ è èìåþùèõ òîëüêî îòîáðàæåíèå â ñòàíäàðòíîì ìîäóëå Prelude. Ýòî îòîáðàæåíèå ïðåäñòàâëÿåò ñîáîé ñèãíàòóðó, êîòîðàÿ ðàçðåøàåò èñïîëüçîâàíèå ñîîòâåòñòâóþùåãî èäåíòèôèêàòîðà. Íèæå ïåðå÷èñëÿþòñÿ âñå òàêèå ïðèìèòèâû:
ïðèìèòèâîâ
1) openFile :: FilePath −> IOMode −> IO Handle îòêðûâàåò ôàéë ïî çàäàííîìó èìåíè è ðåæèìó îòêðûòèÿ, âîçâðàùàåò äåñêðèïòîð ôàéëà, êîòîðûé âïîñëåäñòâèè ìîæåò èñïîëüçîâàòüñÿ äëÿ ðàáîòû ñ îòêðûòûì ôàéëîì; 2) hClose :: Handle −> IO () çàêðûâàåò óêàçàííûé ïðè ïîìîùè äåñêðèïòîðà ôàéë; 3) hGetContents :: Handle −> IO String ÷èòàåò âñ¼ ñîäåðæèìîå çàäàííîãî ôàéëà â îäíó ñòðîêó; 4) hGetChar :: Handle −> IO Char ÷èòàåò îäèí ñèìâîë ñ òåêóùåé ïîçèöèè â çàäàííîì ôàéëå; 5) hGetLine :: Handle −> IO String ÷èòàåò îäíó ñòðîêó ñ òåêóùåé ïîçèöèè â çàäàííîì ôàéëå, ïðè ýòîì ñòðîêà çàêàí÷èâàåòñÿ ñèìâîëîì ïåðåâîäà ñòðîêè; 6) hPutChar :: Handle −> Char −> IO () çàïèñûâàåò îäèí çàäàííûé ñèìâîë íà òåêóùóþ ïîçèöèþ â çàäàííîì ôàéëå; 7) hPutStr :: Handle −> String −> IO () çàïèñûâàåò ñòðîêó íà òåêóùóþ ïîçèöèþ â çàäàííîì ôàéëå. Òèï Handle ÿâëÿåòñÿ ñèíîíèìîì òèïà Int (äëÿ òåêóùåé ðåàëèçàöèè èíòåðïðåòàòîðà HUGS 98), íî ìîæåò èìåòü èíóþ ðåàëèçàöèþ â äðóãèõ òðàíñëÿòîðàõ ÿçûêà Haskell, ïîýòîìó ïðè ïðîãðàììèðîâàíèè íåîáõîäèìî èñïîëüçîâàòü òîëüêî ýòîò ñèíîíèì. Êðîìå âñåãî ïðî÷åãî, â âèäå ïðèìèòèâîâ îïðåäåëåíû òðè , êîòîðûå âîçâðàùàþò ñòàíäàðòíûå ïîòîêè stdin (ñòàíäàðòíûé ïîòîê ââîäà ñ êëàâèàòóðû), stdout (ñòàíäàðòíûé ïîòîê âûâîäà â îáû÷íóþ êîíñîëü) è stderr (ñòàíäàðòíûé ïîòîê âûâîäà â êîíñîëü îøèáîê). Âñå ýòè êîíñòàíòíûå ôóíêöèè âîçâðàùàþò çíà÷åíèå òèïà Handle, à ñàìè âîçâðàùàåìûå çíà÷åíèÿ îòëè÷àþòñÿ îò ôàéëîâ òåì, ÷òî èõ íå íàäî íè îòêðûâàòü, íè çàêðûâàòü îíè âñåãäà äîñòóïíû äëÿ ðàáîòû.  ïðèíöèïå, ïåðå÷èñëåííûõ ôóíêöèé äîñòàòî÷íî äëÿ âûïîëíåíèÿ ïðîèçâîëüíûõ îïåðàöèé ââîäà/âûâîäà. Îäíàêî äëÿ óäîáíîé ðàáîòû ñ êëàâèàòóðîé è êîíñîëüþ îïðåäåëåíû äîïîëíèòåëüíûå ôóíêöèè (âñå îíè âûðàæåíû ÷åðåç ïåðå÷èñëåííûå âûøå ñåìü ôóíêöèé):
êîíñòàíòíûå ôóíêöèè
1) putChar :: Char −> IO () âûâîäèò çàäàííûé ñèìâîë â ñòàíäàðòíóþ êîíñîëü âûâîäà stdout; 2) putStr :: String −> IO () âûâîäèò çàäàííóþ ñòðîêó â ñòàíäàðòíóþ êîíñîëü âûâîäà stdout; 3) putStrLn :: String −> IO () âàðèàíò ôóíêöèè putStr, äîáàâëÿþùèé ïîñëå âûâåäåííîé â ñòàíäàðòíóþ êîíñîëü âûâîäà stdout ñòðîêè ñèìâîë ïåðåâîäà ñòðîêè; 4) print :: Show a => a −> IO () âûâîäèò â ñòàíäàðòíóþ êîíñîëü âûâîäà stdout íåêîòîðîå çíà÷åíèå, êîòîðîå ìîæåò áûòü ïðåîáðàçîâàíî â ñòðîêó (òèï ýòîãî çíà÷åíèÿ äîëæåí èìåòü ýêçåìïëÿð êëàññà Show);
68
Ââîä è âûâîä íà ÿçûêå Haskell 5) getChar :: IO Char ÷èòàåò èç ñòàíäàðòíîãî ïîòîêà ââîäà stdin îäèí ñèìâîë; 6) getContents :: IO String ñ÷èòûâàåò âñ¼ ñîäåðæèìîå ñòàíäàðòíîãî ïîòîêà ââîäà stdin â îäíó ñòðîêó; 7) getLine :: IO String ñ÷èòûâàåò èç ñòàíäàðòíîãî çàêàí÷èâàþùóþñÿ ñèìâîëîì ïåðåâîäà ñòðîêè;
ïîòîêà
ââîäà
stdin
îäíó
ñòðîêó,
8) readLn :: Read a => IO a ñ÷èòûâàåò èç ñòàíäàðòíîãî ïîòîêà ââîäà stdin íåêîòîðîå çíà÷åíèå, êîòîðîå ìîæåò áûòü ïîëó÷åíî ïðè ïîìîùè ñèíòàêñè÷åñêîãî ðàçáîðà ñòðîêè (òèï ýòîãî çíà÷åíèÿ äîëæåí èìåòü ýêçåìïëÿð êëàññà Read), ñàìî çíà÷åíèå äîëæíî çàíèìàòü âñþ ñòðîêó, çàêàí÷èâàþùóþñÿ ñèìâîëîì ïåðåâîäà ñòðîêè. Êàê óæå ñêàçàíî, âñå ýòè ôóíêöèè âûðàæåíû ÷åðåç ïðèìèòèâû. Âäóì÷èâûé ÷èòàòåëü ìîæåò ñàìîñòîÿòåëüíî îòêðûòü ñòàíäàðòíûé ìîäóëü Prelude äëÿ òîãî, ÷òîáû èçó÷èòü ñïîñîá òàêîãî âûðàæåíèÿ. Ýòî ïîçâîëèò çàîäíî èçó÷èòü íåïëîõèå ïðèìåðû ðàçðàáîòêè ôóíêöèîíàëüíûõ îïåðàöèé ââîäà/âûâîäà. Ñëåäóþùèé íàáîð ôóíêöèé ïðåäîñòàâëÿåò óäîáíûå èíñòðóìåíòû äëÿ ðàáîòû ñ ôàéëàìè. Âñå îíè òàêæå âûðàæåíû ÷åðåç ïåðå÷èñëåííûå ðàíåå ñåìü ïðèìèòèâíûõ ôóíêöèé: 1) writeFile :: FilePath −> String −> IO () ñîçäà¼ò ôàéë ñ çàäàííûì èìåíåì, ñîäåðæèìûì êîòîðîãî ÿâëÿåòñÿ çàäàííàÿ ñòðîêà, ñàì ôàéë ïîñëå çàïèñè çàêðûâàåòñÿ; 2) appendFile :: FilePath −> String −> IO () äîçàïèñûâàåò â çàäàííûé ïî èìåíè ôàéë çàäàííóþ ñòðîêó, ñàì ôàéë ïîñëå çàïèñè çàêðûâàåòñÿ; 3) readFile :: FilePath −> IO String îòêðûâàåò ôàéë ïî çàäàííîìó èìåíè è ñ÷èòûâàåò âñ¼ åãî ñîäåðæèìîå â îäíó ñòðîêó, êîòîðàÿ âîçâðàùàåòñÿ â êà÷åñòâå ðåçóëüòàòà, ôàéë îñòà¼òñÿ îòêðûòûì; 4) interact :: (String −> String) −> IO () èíòåðåñíàÿ ôóíêöèÿ, êîòîðàÿ ñ÷èòûâàåò âñ¼ ñîäåðæèìîå ñòàíäàðòíîãî ïîòîêà ââîäà stdin â ñòðîêó, ïðèìåíÿåò ê ýòîé ñòðîêå çàäàííóþ ôóíêöèþ, à ðåçóëüòàò ðàáîòû ýòîé ôóíêöèè âûâîäèò â ñòàíäàðòíûé ïîòîê âûâîäà stdout. Íàêîíåö, ïîñëåäíåé ôóíêöèåé äëÿ ðàáîòû ñ ñèñòåìîé ââîäà/âûâîäà, êîòîðàÿ îïèñàíà â ñòàíäàðòíîì ìîäóëå Prelude, ÿâëÿåòñÿ ôóíêöèÿ catch. Ýòà ôóíêöèÿ ïðåäíàçíà÷åíà äëÿ îòëîâà . Ëþáàÿ îïåðàöèÿ ââîäà/âûâîäà â ïðîöåññå ñâîåé ðàáîòû ìîæåò ñãåíåðèðîâàòü èñêëþ÷åíèå íåêîòîðîãî òèïà. Ýòî ìîæåò ïðîèçîéòè ïî ìíîãèì ïðè÷èíàì çàäàííûé ïî èìåíè ôàéë îòñóòñòâóåò, íåò ïðàâ äîñòóïà äëÿ ÷òåíèÿ ôàéëà è ò. ä. Äëÿ òîãî ÷òîáû ïðîãðàììà íå ïðîèçâåëà àâàðèéíîãî îñòàíîâà ñ âûõîäîì â îïåðàöèîííóþ ñèñòåìó, òàêèå èñêëþ÷åíèÿ íåîáõîäèìî ëîâèòü è îáðàáàòûâàòü. Äëÿ ýòîãî êàê ðàç è èñïîëüçóåòñÿ ôóíêöèÿ catch, êîòîðàÿ èìååò ñëåäóþùóþ ñèãíàòóðó:
èñêëþ÷åíèé
catch : : IO a −> ( IOError −> IO a ) −> IO a Ýòà ôóíêöèÿ ïðèíèìàåò íà âõîä äâà ïàðàìåòðà îïåðàöèþ ââîäà/âûâîäà, à òàêæå îáðàáîò÷èê íåêîòîðîãî èñêëþ÷åíèÿ (òèïû èñêëþ÷åíèé îïèñûâàþòñÿ ïåðå÷èñëåíèåì IOError). Åñëè â ïðîöåññå âûïîëíåíèÿ îïåðàöèè ââîäà/âûâîäà èñêëþ÷åíèé íå ïðîèçîøëî, ôóíêöèÿ catch âîçâðàùàåò ðåçóëüòàò îïåðàöèè. Åñëè æå ïðîèçîøëî èñêëþ÷åíèå, òî îíî ïåðåäà¼òñÿ íà âõîä ôóíêöèè-îáðàáîò÷èêó, êîòîðàÿ çàäàíà âòîðûì àðãóìåíòîì ôóíêöèè catch. Ýòà ôóíêöèÿ ìîæåò îáðàáîòàòü èñêëþ÷åíèå, òîãäà ðåçóëüòàò å¼ ðàáîòû áóäåò è ðåçóëüòàòîì âûçîâà ôóíêöèè catch, à ìîæåò è íå îáðàáàòûâàòü.  ïîñëåäíåì ñëó÷àå èñêëþ÷åíèå áóäåò ñãåíåðèðîâàíî ïîâòîðíî è ïåðåäàíî â îáðàáîò÷èê áîëåå âûñîêîãî óðîâíÿ. Ýòèì äîñòèãàåòñÿ èåðàðõè÷íîñòü îáðàáîòêè èñêëþ÷åíèé. Ñàìûì âåðõíèì îáðàáîò÷èêîì èñêëþ÷åíèé ÿâëÿåòñÿ ñèñòåìíàÿ ôóíêöèÿ, êîòîðàÿ îñòàíàâëèâàåò ïðîãðàììó è âûâîäèò ñòàíäàðòíîå ñîîáùåíèå îá îøèáêå. Ýòîò îáðàáîò÷èê âûçûâàåòñÿ âñåãäà, åñëè èñêëþ÷åíèå íå îáðàáîòàíî íè îäíèì èç îáðàáîò÷èêîâ, îïðåäåë¼ííûõ ïðîãðàììèñòîì.
Ïðèìåðû ïðîãðàìì
69
Òàêèì îáðàçîì, â ñòàíäàðòíîì ìîäóëå Prelude îïðåäåëåíû äîñòàòî÷íûå ñðåäñòâà äëÿ ðåøåíèÿ ïðîèçâîëüíûõ ïðèêëàäíûõ çàäà÷, ñâÿçàííûõ ñ èñïîëüçîâàíèåì ââîäà/âûâîäà.  ñëåäóþùåì ðàçäåëå áóäóò ïðèâåäåíû íåêîòîðûå ïðèìåðû èñïîëüçîâàíèÿ ýòèõ ôóíêöèé.
Ïðèìåðû ïðîãðàìì  ÿçûêå Haskell èìååòñÿ îäíî ñîãëàøåíèå, ñõîäíîå ñ ñîãëàøåíèåì îá èìåíè ãëàâíîé ôóíêöèè â òàêèõ ÿçûêàõ ïðîãðàììèðîâàíèÿ, êàê C èëè C++. Åñëè ïðîãðàììà ãîòîâèòñÿ ê êîìïèëÿöèè, òî â íåé äîëæíà áûòü îïðåäåëåíà ôóíêöèÿ main, ïðè ýòîì îíà äîëæíà áûòü îïðåäåëåíà â ìîäóëå Main (èëè ãëàâíîì ìîäóëå áåç íàèìåíîâàíèÿ ïî óìîë÷àíèþ íàèìåíîâàíèå ìîäóëÿ áåð¼òñÿ êàê ðàç Main), à å¼ òèï äîëæåí áûòü:
main : : IO ( ) Åñëè ïîäîáíûå ïðîãðàììû èñïîëüçîâàòü â èíòåðïðåòàòîðàõ (íàïðèìåð, â èíòåðïðåòàòîðå HUGS 98), òî ôóíêöèÿ main áóäåò çàïóùåíà íà èñïîëíåíèå ïðè íàæàòèè íà êíîïêó ¾Çàïóñê¿ íà ïàíåëè èíñòðóìåíòîâ èíòåðïðåòàòîðà. Íàçâàíèå ãëàâíîé ôóíêöèè äîëæíî ó÷èòûâàòüñÿ ïðè ïðîãðàììèðîâàíèè ïðèêëàäíûõ çàäà÷.
Âûâîä ðåçóëüòàòîâ èñïîëíåíèÿ ôóíêöèè íà ýêðàí Äî ýòîãî âî âñåõ ïðèìåðàõ, ïðèâîäèìûõ â ðàçäåëàõ êíèãè, êîòîðûå áûëè ïîñâÿùåíû ÿçûêó Haskell, èñïîëüçîâàëèñü ôóíêöèè, ðåçóëüòàòû êîòîðûõ âûâîäèëèñü àâòîìàòè÷åñêè â èíòåðïðåòàòîðå. Äëÿ ýòîãî áûëî íåîáõîäèìî ïðîñòî íàïèñàòü â ñòðîêå ïðèãëàøåíèÿ èíòåðïðåòàòîðà íàèìåíîâàíèå ôóíêöèè è ñïèñîê å¼ ôàêòè÷åñêèõ ïàðàìåòðîâ, ÷òîáû èíòåðïðåòàòîð ïðîèíòåðïðåòèðîâàë ýòîò âûçîâ ôóíêöèè è âûâåë ðåçóëüòàò íà ýêðàí.  ýòîì ìîìåíòå èìååòñÿ îäíà î÷åíü âàæíàÿ âåùü. Èíòåðïðåòàòîð ìîæåò âûâåñòè íà ýêðàí òîëüêî òàêîå çíà÷åíèå, òèï êîòîðîãî èìååò ýêçåìïëÿð êëàññà Show. Íàïðèìåð, ôóíêöèè ñ òèïîì a −> b íå ìîãóò áûòü âûâåäåíû íà ýêðàí â êà÷åñòâå ðåçóëüòàòà âû÷èñëåíèÿ, ïîñêîëüêó äëÿ ýòîãî òèïà íåò ýêçåìïëÿðà êëàññà Show. Îáû÷íî òàêàÿ îøèáêà ïðîèñõîäèò, åñëè âûçâàòü êàêóþ-ëèáî ôóíêöèþ, ïåðåäàâ åé íà îäíî ôàêòè÷åñêîå çíà÷åíèå ìåíüøå, ÷åì òîãî òðåáóåò ñèãíàòóðà.  ýòîì ñëó÷àå ïðîèçîéä¼ò ÷àñòè÷íîå ïðèìåíåíèå, ðåçóëüòàòîì êîòîðîãî áóäåò ôóíêöèÿ îäíîãî àðãóìåíòà, è èíòåðïðåòàòîð âûâåäåò íà ýêðàí ïðèìåðíî ñëåäóþùåå:
ERROR − Cannot find " show " function for : ∗∗∗ Expression : flip (+) 1 ∗∗∗ Of type : Integer −> Integer Ýòî ïðîèñõîäèò ïîòîìó, ÷òî äëÿ òèïà ëþáîãî çíà÷åíèÿ, êîòîðîå äîëæåí âûâåñòè íà ýêðàí èíòåðïðåòàòîð, îí èùåò ýêçåìïëÿð êëàññà Show, ÷òîáû ïðåîáðàçîâàòü ýòî çíà÷åíèå â ñòðîêó ïðè ïîìîùè ìåòîäà show, ïîñëå ÷åãî ñòðîêà âûâîäèòñÿ íà ýêðàí. Âåñü ýòîò ïðîöåññ äåëàåòñÿ ïðè ïîìîùè ñòàíäàðòíîé ôóíêöèè print. Òî æå ñàìîå íåîáõîäèìî äåëàòü è ïðè âûâîäå ðåçóëüòàòîâ ðàáîòû ôóíêöèè â îòêîìïèëèðîâàííîé ïðîãðàììå. Îäíàêî âåñü ýòîò ïðîöåññ íåîáõîäèìî äåëàòü óæå âðó÷íóþ.  êà÷åñòâå ïðèìåðà ìîæíî ðàññìîòðåòü ïîëó÷åíèå ñïèñêà èç ïÿòè ïåðâûõ ñîâåðøåííûõ ÷èñåë. Áûñòðî íàïèñàâ ôóíêöèè äëÿ ïîëó÷åíèÿ ñïèñêà ñîâåðøåííûõ ÷èñåë:
divisors : : Integer −> [ Integer ] divisors x = [ y | y <− [ 1 . . ( div x 2 ) ] , mod x y == 0 ] perfects : : [ Integer ] perfects = [ x | x <− [ 2 , 4 . . ] , sum ( divisors x ) == x ]
70
Ââîä è âûâîä íà ÿçûêå Haskell
íåîáõîäèìî çàäóìàòüñÿ, à êàê âûâåñòè ïåðâûå ïÿòü ÷èñåë íà ýêðàí? Äëÿ ýòîãî íåîáõîäèìî îïðåäåëèòü ôóíêöèþ main, â êîòîðîé ïðîèçîéä¼ò âû÷èñëåíèå ïåðâûõ ïÿòè ñîâåðøåííûõ ÷èñåë, ïîñëå ÷åãî ðåçóëüòàò áóäåò âûâåäåí íà ýêðàí ïðè ïîìîùè îïåðàöèè ââîäà/âûâîäà. Äîñòàòî÷íî ïðîñòî:
main : : IO ( ) main = do l e t p = take 5 perfects print p  ïðèíöèïå, äëÿ òàêèõ ïðîñòûõ ïðèìåðîâ ìîæíî îáîéòèñü è áåç êîíñòðóêöèè do, ïîñêîëüêó îäíà îïåðàöèÿ ââîäà/âûâîäà ìîæåò áûòü âûçâàíà áåç ýòîãî êëþ÷åâîãî ñëîâà, à ñàìî ñëîâî do íåîáõîäèìî òîëüêî äëÿ ñâÿçûâàíèÿ ïîñëåäîâàòåëüíîñòè îïåðàöèé. Òàê ÷òî ôóíêöèÿ main ìîæåò âûãëÿäåòü òàê:
main : : IO ( ) main = print $ take 5 perfects
Àëüòåðíàòèâà: ýêðàí èëè ôàéë À ÷òî, åñëè äëÿ êàêèõ-òî öåëåé íåîáõîäèìî èìåòü âîçìîæíîñòü âûâåñòè ðåçóëüòàòû íå òîëüêî íà ýêðàí, íî è â íåêîòîðûé ôàéë, ïðè ýòîì ïðåäâàðèòåëüíî èìÿ ôàéëà íåîáõîäèìî çàïðîñèòü ó ïîëüçîâàòåëÿ? Äëÿ ðåøåíèÿ ýòîé çàäà÷è òàêîé ïðîñòîé ôóíêöèåé main, êàêàÿ áûëà â ïðåäûäóùåì ïîäðàçäåëå, óæå íå îáîéòèñü. Ïóñòü òåïåðü íåîáõîäèìî âû÷èñëÿòü ñïèñîê ïðîñòûõ ÷èñåë, à äëÿ íåêîòîðîãî óñëîæíåíèÿ çàäà÷è êîëè÷åñòâî ÷èñåë, êîòîðîå íåîáõîäèìî âû÷èñëèòü, òàêæå áóäåò çàïðàøèâàòüñÿ ó ïîëüçîâàòåëÿ. Ôóíêöèÿ äëÿ âû÷èñëåíèÿ ñïèñêà ïðîñòûõ ÷èñåë íåñëîæíàÿ:
primes : : [ Integer ] primes = sieve [ 2 . . ]
where
sieve ( x : xs ) = x : sieve ( filter ((/= 0 ) . ( ` mod ` x ) ) xs ) À âîò ôóíêöèÿ main áóäåò óæå ïîñëîæíåå:
main : : IO ( ) main = do putStr " Ïðèâåò . Ñêîëüêî ïðîñòûõ ÷èñåë âû÷èñëèòü : " npr <− readLn : : IO Int l e t prs = take npr primes putStr " Êóäà âûâåñòè ðåçóëüòàòû ( f − ôàéë ) : " dst <− getLine i f ( dst /= " f " ) then print prs els e do putStr " Ïîæàëóéñòà , ââåäèòå èìÿ ôàéëà : " fn <− getLine writeFile fn ( show prs ) putStr ( " Ôàéë \"" ++ fn ++ "\" çàïèñàí . " ) Ýòó ôóíêöèþ íåîáõîäèìî ðàññìîòðåòü áîëåå ïîäðîáíî. Íèæå ïîäðîáíî èññëåäóåòñÿ êàæäàÿ îïåðàöèÿ ââîäà/âûâîäà, çàïèñàííàÿ â ñïèñêå âûðàæåíèÿ do ýòîé ôóíêöèè. Ïåðâàÿ îïåðàöèÿ âûâîäèò íà ýêðàí ïðè ïîìîùè ñòàíäàðòíîé ôóíêöèè putStr ïðèâåòñòâèå è âîïðîñ î òîì, ñêîëüêî ïðîñòûõ ÷èñåë íåîáõîäèìî ïîäñ÷èòàòü. Âòîðàÿ ñòðîêà êàê ðàç ïðåäíàçíà÷åíà äëÿ ñ÷èòûâàíèÿ ñ êëàâèàòóðû öåëîãî ÷èñëà, êîòîðîå ââåä¼ò ïîëüçîâàòåëü. Ýòî ÷èñëî áóäåò ïîëîæåíî â îáðàçåö npr. Ïîñêîëüêó êîëè÷åñòâî ïðîñòûõ ÷èñåë, êîòîðîå íåîáõîäèìî ïîäñ÷èòàòü, óæå èçâåñòíî, ýòî ìîæíî ñäåëàòü â òðåòüåé ñòðîêå ñîçäà¼òñÿ çàìûêàíèå prs, êîòîðîå ñîäåðæèò ñïèñîê ïðîñòûõ ÷èñåë, ñîñòîÿùèé èç ââåä¼ííîãî êîëè÷åñòâà ýëåìåíòîâ.
Ïðèìåðû ïðîãðàìì
71
×åòâ¼ðòàÿ îïåðàöèÿ îïÿòü ÿâëÿåòñÿ çàïðîñîì îòíîñèòåëüíî òîãî, êóäà âûâåñòè ðåçóëüòàòû. Ñîîòâåòñòâåííî, ïÿòàÿ îïåðàöèÿ ñ÷èòûâàåò ñèìâîë ñ êëàâèàòóðû.  øåñòîé ñòðîêå èìååòñÿ óñëîâíîå âûðàæåíèå, îôîðìëåííîå êîíñòðóêöèåé if -then-else.  ïðèíöèïå, ëþáîå âûðàæåíèå, êîòîðîå èìååò òèï, îáðàìë¼ííûé êîíòåéíåðîì IO, ìîæåò ïðèñóòñòâîâàòü â ñïèñêå do. Ïîýòîìó â ñïèñêå do ìîãóò ïðèñóòñòâîâàòü âûðàæåíèÿ if èëè case ãëàâíîå, ÷òîáû îíè âîçâðàùàëè ñîîòâåòñòâóþùåå çíà÷åíèå. Òàêèì îáðàçîì, ââåä¼ííûé ñèìâîë ïðîâåðÿåòñÿ íà íåðàâåíñòâî ñèìâîëó "f" (íà ñàìîì äåëå ñðàâíèâàþòñÿ ñòðîêè, ïîñêîëüêó ñ êëàâèàòóðû âñåãäà ââîäÿòñÿ ñòðîêè ñèìâîëîâ, äàæå åñëè ñèìâîë ââåä¼í îäèí). Åñëè ââåä¼ííûé ñèìâîë íå ÿâëÿåòñÿ ñèìâîëîì "f", òî ñòàíäàðòíûì îáðàçîì íà ýêðàí âûâîäèòñÿ ïîäñ÷èòàííûé ñïèñîê ïðîñòûõ ÷èñåë.  ÷àñòè else, îäíàêî, èìååòñÿ íîâûé ñïèñîê îïåðàöèé ââîäà/âûâîäà, îôîðìëåííûé êëþ÷åâûì ñëîâîì do. Ýòî âïîëíå âîçìîæíî ïî ïðè÷èíàì, îïèñàííûì âûøå. Òàê ÷òî çäåñü îïÿòü ïðîèñõîäÿò çàïðîñ ó ïîëüçîâàòåëÿ èìåíè ôàéëà, çàïèñü â ôàéë ðåçóëüòàòà ïðè ïîìîùè ñòàíäàðòíîé ôóíêöèè writeFile, à òàêæå âûâîä óâåäîìëåíèÿ î òîì, ÷òî ôàéë çàïèñàí. Ðåçóëüòàò ðàáîòû ôóíêöèè main ìîæåò âûãëÿäåòü, ê ïðèìåðó, ñëåäóþùèì îáðàçîì:
Ïðèâåò . Ñêîëüêî ïðîñòûõ ÷èñåë âû÷èñëèòü : 1000 Êóäà âûâåñòè ðåçóëüòàòû ( f − ôàéë ) : f Ïîæàëóéñòà , ââåäèòå èìÿ ôàéëà : primes . txt Ôàéë " primes . txt " çàïèñàí . Ê ñîæàëåíèþ, ýòà ôóíêöèÿ main èìååò ðÿä ñóùåñòâåííûõ íåäîñòàòêîâ. Âî-ïåðâûõ, îíà àâàðèéíî çàâåðøàåòñÿ, åñëè ïîëüçîâàòåëü ââåä¼ò íà çàïðîñ êîëè÷åñòâà ïðîñòûõ ÷èñåë êàêóþ-íèáóäü ñòðîêó, êîòîðóþ íåâîçìîæíî ïðåîáðàçîâàòü â öåëîå ÷èñëî. Âî-âòîðûõ, îíà òàêæå àâàðèéíî çàâåðøàåòñÿ, åñëè ôàéë, èìÿ êîòîðîãî ââåäåíî ïîëüçîâàòåëåì, íåâîçìîæíî ñîçäàòü èëè ïåðåçàïèñàòü (íàïðèìåð, íåò ïðàâ äîñòóïà èëè ó ôàéëà èìååòñÿ àòðèáóò ¾òîëüêî ÷òåíèå¿). Íó è, íàêîíåö, â-òðåòüèõ, ôóíêöèÿ âûâîäèò ðåçóëüòàò íà ýêðàí â ëþáîì ñëó÷àå, åñëè ïîëüçîâàòåëü ââ¼ë íå ñèìâîë "f". Õîðîøî áûëî áû, åñëè íà ýêðàí ðåçóëüòàòû âûâîäèëèñü òîëüêî ïî íàæàòèè êàêîãî-íèáóäü îïðåäåë¼ííîãî ñèìâîëà. Áûëî áû íàìíîãî èíòåðåñíåé, åñëè áû íà íåêîððåêòíûé ââîä âî âñåõ òð¼õ ñëó÷àÿõ ïðîãðàììà ñîîáùàëà îá ýòîì è ïîâòîðíî çàïðàøèâàëà èíôîðìàöèþ. Âäóì÷èâîìó ÷èòàòåëþ ïðåäëàãàåòñÿ â öåëÿõ òðåíèðîâêè ñàìîñòîÿòåëüíî ðåàëèçîâàòü òàêóþ ôóíêöèþ main. Ýòî íå òàê ñëîæíî, êàê ìîæåò ïîêàçàòüñÿ íà ïåðâûé âçãëÿä.
Êîïèðîâàíèå ôàéëîâ Ïîñëåäíèé ïðèìåð ñâÿçàí ñ êîïèðîâàíèåì ôàéëîâ. Íåáîëüøàÿ óòèëèòà, êîòîðàÿ çàïðàøèâàåò ó ïîëüçîâàòåëÿ èìÿ ñóùåñòâóþùåãî ôàéëà, à òàêæå èìÿ íîâîãî ôàéëà, â êîòîðûé íåîáõîäèìî ñêîïèðîâàòü ñîäåðæèìîå ñòàðîãî ôàéëà. Åñëè îáà èìåíè êîððåêòíû, óòèëèòà ïðîèçâîäèò êîïèðîâàíèå. Åñëè ÷òîòî íåïðàâèëüíî, ïðîèñõîäèò êàêîå-ëèáî èñêëþ÷åíèå, òî óòèëèòà ïðîñèò ïîëüçîâàòåëÿ çàíîâî ââåñòè âñå äàííûå. Äëÿ íà÷àëà íåîáõîäèìî îïðåäåëèòü ôóíêöèþ, êîòîðàÿ ñêîïèðóåò ñîäåðæèìîå ôàéëà â äðóãîé ôàéë, à òàêæå ñîîáùèò îá ýòîì. Ïðèìåíÿÿ çíàíèÿ, ïîëó÷åííûå â ïîäðàçäåëå, ïîñâÿù¼ííîì ñòàíàäðòíûì ôóíêöèÿì èç ìîäóëÿ Prelude, îïðåäåëèòü òàêóþ ôóíêöèþ íå ñîñòàâëÿåò òðóäà:
copyFile : : String −> String −> IO ( ) copyFile src dst = do body <− readFile src writeFile dst body putStrLn ( " Ôàéë \"" ++ src ++ "\" ñêîïèðîâàí â \"" ++ dst ++ " \ " . " ) Îäíàêî ýòà ôóíêöèÿ âñ¼ òàêæå íå ëèøåíà íåäîñòàòêà îíà ñîâåðøèò àâàðèéíûé îñòàíîâ â ñëó÷àå, åñëè ñ ôàéëàìè ñóùåñòâóåò êàêîé-òî íåïîðÿäîê: íåò ïðàâ äîñòóïà, íåâîçìîæíî ïðî÷èòàòü èëè çàïèñàòü
72
Ââîä è âûâîä íà ÿçûêå Haskell
ôàéë. Îáðàáîò÷èê èñêëþ÷åíèé äîëæåí îõâàòûâàòü ýòó ôóíêöèþ è ¾ñòîðîæèòü¿ å¼ ïîâåäåíèå. Ïîýòîìó âûçîâ ôóíêöèè catch äîëæåí ïðîèñõîäèòü â ôóíêöèè main:
main : : IO ( ) main = do putStr " Ïîæàëóéñòà , ââåäèòå èìÿ ôàéëà äëÿ êîïèðîâàíèÿ : " src <− getLine putStr " Ââåäèòå íîâîå èìÿ ôàéëà : " dst <− getLine catch ( copyFile src dst ) ( \ e −> do putStrLn " Îøèáêà . Ïîæàëóéñòà , ïîâòîðèòå . " main ) Ïåðâûå ÷åòûðå ñòðîêè â âûðàæåíèè do ýòî çàïðîñû èì¼í ôàéëîâ. Ïîñëåäíÿÿ ñòðîêà íàèáîëåå èíòåðåñíà. Çäåñü è ïðîèñõîäèò îáðàáîòêà èñêëþ÷åíèé ïîñðåäñòâîì âûçîâà ñòàíäàðòíîé ôóíêöèè catch. Ïåðâûé îïåðàíä ýòîé ôóíêöèè âûçîâ ôóíêöèè copyFile ñ çàäàííûìè èìåíàìè ôàéëîâ. À âòîðîé îïåðàíä îáðàáîò÷èê îøèáêè.  äàííîì ñëó÷àå îáðàáîò÷èê íàïèñàí äîñòàòî÷íî ïðîñòî. Îí èãíîðèðóåò òèï îøèáêè, ïðîñòî âûâîäèò íà ýêðàí ñîîáùåíèå î òîì, ÷òî ïðîèçîøëà êàêàÿ-òî îøèáêà, è çàïóñêàåò ïðîöåññ ñíà÷àëà. Ðåêóðñèâíûé âûçîâ ôóíêöèè main íå äîëæåí íàñòîðàæèâàòü ýòî îáû÷íîå äåëî. È îïÿòü æå, èìååòñÿ ìíîãî âîçìîæíîñòåé äëÿ óëó÷øåíèÿ ýòîé ôóíêöèè. Ìîæíî ðàñïîçíàâàòü òèï ïðîèçîøåäøåé îøèáêè è âûâîäèòü íà ýêðàí ñîîòâåòñòâóþùåå ñîîáùåíèå. Ìîæíî íå çàñòàâëÿòü ââîäèòü ïîëüçîâàòåëÿ îáà èìåíè ñíîâà, à ïðîñèòü ââîäèòü òîëüêî òî, ñ êîòîðûì ïðîèçîøëà îøèáêà. Ìîæíî ïðèäóìàòü ìíîãî ÷åãî åù¼. Âñå ýòè íîâûå âîçìîæíîñòè îïÿòü îñòàâëÿþòñÿ äëÿ ñàìîñòîÿòåëüíîé ïðîðàáîòêè. Êðîìå òîãî, âäóì÷èâûé ÷èòàòåëü óâèäèò çäåñü îäíó ëîãè÷åñêóþ îøèáêó, êîòîðàÿ íàðî÷èòî îñòàâëåíà â öåëÿõ îáó÷åíèÿ. Ýòà îøèáêà íå ïðèâîäèò ê ãåíåðàöèè èñêëþ÷åíèÿ, íî ìîæåò áûòü ïðè÷èíîé íåïðåäñêàçóåìîãî ïîâåäåíèÿ ïðîãðàììû. Êòî ïåðâûé èç ÷èòàòåëåé ñîîáùèò î íåé è î âîçìîæíîì ñïîñîáå å¼ ïðåîäîëåíèÿ àâòîðó, ïîëó÷èò èíòåðåñíûé ïîäàðîê.
Çàêëþ÷åíèå Äàííûé ðàçäåë êðàòêî îïèñûâàåò ñèñòåìó ââîäà/âûâîäà â ÷èñòîì ôóíêöèîíàëüíîì ÿçûêå Haskell.  íåé íå çàòðàãèâàåòñÿ âàæíåéøèé àñïåêò ýòîé ñèñòåìû å¼ ðåàëèçàöèÿ ïðè ïîìîùè , ïîñêîëüêó ýòà òåîðåòè÷åñêàÿ òåìà äîñòàòî÷íî ñëîæíà è âûõîäèò çà ðàìêè ïðîñòîé íàó÷íî-ïîïóëÿðíîé êíèãè. Âäóì÷èâûé ÷èòàòåëü, æåëàþùèé äâèãàòüñÿ äàëüøå, ìîæåò ñàìîñòîÿòåëüíî èçó÷àòü ìàòåðèàëû, ïîñâÿù¼ííûå ìîíàäàì, ïîñêîëüêó ìîíàäû ÿâëÿþòñÿ îäíîé èç âàæíåéøèõ ÷àñòåé ÿçûêà Haskell.  ñëåäóþùåì ðàçäåëå òåìà ñèñòåìû ââîäà/âûâîäà â ÿçûêå Haskell áóäåò ðàñêðûòà äîïîëíèòåëüíî.
ìîíàäû
Ïðîñòîé èíòåðïðåòàòîð êîìàíä Ñòàòüÿ áûëà îïóáëèêîâàíà â 08 (44) æóðíàëà ¾Ïîòåíöèàë¿ â àâãóñòå 2008 ãîäà.
 ýññå ðàññìàòðèâàåòñÿ îäíà èç èíòåðåñíåéøèõ ïðàêòè÷åñêèõ çàäà÷, çàêëþ÷àþùàÿñÿ â îðãàíèçàöèè öèêëà èíòåðïðåòàöèè êîìàíä, ââîäèìûõ ïîëüçîâàòåëåì ñ êëàâèàòóðû. Äàííàÿ çàäà÷à ïîâñåìåñòíî âîçíèêàåò â èíòåðàêòèâíûõ ïðèëîæåíèÿõ, îò ïðîñòûõ âîïðîñ-îòâåòíûõ âû÷èñëèòåëüíûõ ïðîãðàìì äî îïåðàöèîííûõ ñèñòåì. Íà ïðèìåðå ôóíêöèîíàëüíîãî ÿçûêà ïðîãðàììèðîâàíèÿ Haskell ïîêàçûâàåòñÿ îäèí ñïîñîá ðåàëèçàöèè ïðîñòîãî èíòåðïðåòàòîðà êîìàíä.
Ââåäåíèå Ïðàêòè÷åñêè â ëþáîé ïðèêëàäíîé çàäà÷å èìååòñÿ íåîáõîäèìîñòü îðãàíèçàöèè èíòåðàêòèâíîãî âçàèìîäåéñòâèÿ ñ ïîëüçîâàòåëåì. Äðóãîå äåëî, ÷òî â ðàçëè÷íûõ òèïàõ ïðèëîæåíèé òàêîå âçàèìîäåéñòâèå îñóùåñòâëÿåòñÿ ðàçíûìè ñïîñîáàìè. Íàïðèìåð, â ãðàôè÷åñêèõ ïðèëîæåíèÿõ, óïðàâëÿåìûõ îïåðàöèîííîé ñèñòåìîé òèïà Windows, èíòåðàêòèâíîå âçàèìîäåéñòâèå ñ ïîëüçîâàòåëåì îñóùåñòâëÿåòñÿ ïðè ïîìîùè ãðàôè÷åñêèõ óïðàâëÿþùèõ ýëåìåíòîâ. Îñîáûì ñëó÷àåì ÿâëÿþòñÿ òàê íàçûâàåìûå , â êîòîðûõ âçàèìîäåéñòâèå îñóùåñòâëÿåòñÿ ïðè ïîìîùè ââîäà êîìàíä ñ ïàðàìåòðàìè è ïîëó÷åíèÿ ðåàêöèè ñèñòåìû íà íèõ. Âî âðåìåíà äî ïîÿâëåíèÿ ãðàôè÷åñêèõ îïåðàöèîííûõ ñèñòåì ýòî áûë åñòåñòâåííûé ñïîñîá âçàèìîäåéñòâèÿ. Äà è ñåãîäíÿ ìíîãèå ïðèêëàäíûå ïðîãðàììû âñ¼ òàê æå èñïîëüçóþò êîíñîëüíûé ââîä/âûâîä äëÿ îáùåíèÿ ñ ïîëüçîâàòåëåì. Âûøåñêàçàííîå ïîêàçûâàåò, ÷òî ñîçäàíèå ñèñòåìû ôóíêöèé, êîòîðàÿ ïîçâîëÿåò îðãàíèçîâûâàòü öèêë èíòåðïðåòàöèè è âçàèìîäåéñòâîâàòü ñ ïîëüçîâàòåëåì â èíòåðàêòèâíîì ðåæèìå, ÿâëÿåòñÿ òèïîâîé çàäà÷åé, äëÿ ðåøåíèÿ êîòîðîé ìîæíî ïîäãîòîâèòü òàê íàçûâàåìûé â âèäå íåêîòîðîãî øàáëîíà. Øàáëîí ìîæíî îðãàíèçîâàòü â âèäå íåñêîëüêèõ ìîäóëåé, ÷àñòü èç êîòîðûõ ìîæåò áûòü çàìåíÿåìà â çàâèñèìîñòè îò íàçíà÷åíèÿ èíòåðïðåòàòîðà. Òàêèì îáðàçîì, íèæå â ðàçäåëå ïðåäëàãàåòñÿ îäèí èç âàðèàíòîâ ðåøåíèÿ ýòîé çàäà÷è è ñîçäà¼òñÿ ïðîñòîé èíòåðïðåòàòîð êîìàíä.
êîíñîëüíûå ïðèëîæåíèÿ
ïîâòîðíî èñïîëüçóåìûé êîìïîíåíò
Ïîñòàíîâêà çàäà÷è Ðàçðàáîòêà ëþáîãî ïðîãðàììíîãî îáåñïå÷åíèÿ íà÷èíàåòñÿ ñ ïîñòàíîâêè çàäà÷è, íàïèñàíèÿ . Ïðåäâàðèòåëüíî íàïèñàíèå êðàòêîãî, íî ïðîðàáîòàííîãî òåõíè÷åñêîãî çàäàíèÿ äàæå äëÿ íåáîëüøîé çàäà÷è ÿâëÿåòñÿ õîðîøåé ïðàêòèêîé è ñïîñîáñòâóåò áûñòðîìó îñîçíàíèþ öåëåé è çàäà÷ áóäóùåé ïðîãðàììû, à òàêæå íå ìåíåå áûñòðîé ðåàëèçàöèè. Ïîýòîìó â ýòîì ðàçäåëå áóäåò êðàòêî ñôîðìóëèðîâàíà è ôîðìàëèçîâàíà çàäà÷à, êîòîðóþ íåîáõîäèìî ðåøèòü ïðè ðàçðàáîòêå ïðîñòîãî èíòåðïðåòàòîðà êîìàíä. Èòàê, ïðîñòîé èíòåðïðåòàòîð êîìàíä (äàëåå ÏÈÊ) äîëæåí:
òåõíè÷åñêîãî çàäàíèÿ
1) ïðè çàïóñêå âûâîäèòü íà ýêðàí ïðèâåòñòâåííîå ñîîáùåíèå, êîòîðîå ìîæåò ñîñòîÿòü èç íàçâàíèÿ ïðîãðàììû è å¼ âåðñèè;
74
Ïðîñòîé èíòåðïðåòàòîð êîìàíä 2) ïîñòîÿííî íàõîäèòüñÿ â îæèäàíèè êîìàíäû ïîëüçîâàòåëÿ, êîòîðàÿ ââîäèòñÿ ïðè ïîìîùè êëàâèàòóðû è çàâåðøàåòñÿ íàæàòèåì êëàâèøè ¾Ââîä¿; 3) ðåæèì îæèäàíèÿ ÏÈÊ õàðàêòåðèçóåòñÿ òåì, ÷òî íà ýêðàíå ïðèñóòñòâóåò íàäïèñü ¾Ââåäèòå êîìàíäó:¿, à ñàì ÏÈÊ ãîòîâ ê ââîäó ïîñëåäîâàòåëüíîñòè ñèìâîëîâ; 4) ëþáàÿ êîìàíäà äîëæíà ñîñòîÿòü èç ìíåìîíè÷åñêîãî èìåíè è ïðîèçâîëüíîãî ÷èñëà å¼ àðãóìåíòîâ, îòäåë¼ííûõ îò íàèìåíîâàíèÿ êîìàíäû ïðîáåëîì. Âñå àðãóìåíòû òàêæå îòäåëÿþòñÿ äðóã îò äðóãà ïðîáåëàìè; 5) êîìàíäû ìîãóò èìåòü ñèíîíèìû, êîòîðûå ïîëíîñòüþ çàìåíÿþò ñàìó êîìàíäó. Ñèíîíèì íå îòëè÷èì îò êîìàíäû, íåò íèêàêîé ðàçíèöû èñïîëüçîâàòü êîìàíäó èëè å¼ ñèíîíèì; 6) ïðè ââîäå íåèçâåñòíîãî íàáîðà ñèìâîëîâ, ÏÈÊ äîëæåí ñîîáùàòü ïîëüçîâàòåëþ, ÷òî ââåä¼ííàÿ ïîñëåäîâàòåëüíîñòü íå ÿâëÿåòñÿ äîïóñòèìîé êîìàíäîé; 7) íå äîëæíî èìåòü çíà÷åíèÿ, â êàêîì ðåãèñòðå ñèìâîëîâ ââîäÿòñÿ êîìàíäû. Ïîñëåäîâàòåëüíîñòè ¾StOrE¿ è ¾store¿ äîëæíû áûòü íåðàçëè÷èìû äëÿ ÏÈÊ; 8) ðàñïîçíàâàíèå êîìàíäû äîëæíî ïðîèçâîäèòüñÿ ïðè ïîìîùè ñðàâíåíèÿ ñ íà÷àëîì ïîñëåäîâàòåëüíîñòè ñèìâîëîâ, ñîñòàâëÿþùèõ íàèìåíîâàíèå êîìàíäû. Åñëè ââåä¼ííàÿ ïîëüçîâàòåëåì ïîñëåäîâàòåëüíîñòü ÿâëÿåòñÿ íà÷àëîì êàêîé-ëèáî êîìàíäû, ÏÈÊ âûïîëíÿåò ýòó êîìàíäó. Äðóãèìè ñëîâàìè, ïîñëåäîâàòåëüíîñòü ¾sh¿ âûïîëíèò êîìàíäó ¾show¿; 9) êàæäàÿ êîìàíäà äîëæíà ïîääåðæèâàòü ñïåöèàëüíûé èíôîðìàöèîííûé ðåæèì, ïðè èñïîëüçîâàíèè êîòîðîãî êîìàíäà íå âûïîëíÿåò ñâî¼ îáû÷íîå äåéñòâèå, íî âûâîäèò íà ýêðàí ñïðàâî÷íóþ èíôîðìàöèþ î ñàìîé ñåáå. Ïàðàìåòð, êîòîðûé ïåðåâîäèò êîìàíäó â îïèñàííûé ðåæèì, ¾−?¿;
10) êîìàíäà ¾exit¿ äîëæíà ïîçâîëÿòü âûéòè èç ÏÈÊ, ïðè ýòîì íà ýêðàíå äîëæíî áûòü âûâåäåíî ïðîùàíèå. Âîçìîæíûé ñèíîíèì êîìàíäû ¾quit¿; 11) êîìàíäà ¾help¿ äîëæíà âûâîäèòü íà ýêðàí êðàòêóþ ñïðàâî÷íóþ èíôîðìàöèþ. Âîçìîæíûå ñèíîíèìû êîìàíäû ¾?¿, ¾manual¿; 12) êîìàíäà ¾version¿ äîëæíà âûâîäèòü íà ýêðàí íàèìåíîâàíèå è âåðñèþ ïðîãðàììû; 13) êîìàíäà ¾store¿ äîëæíà çàïèñûâàòü â òàáëèöó ñòðîê çàäàííóþ ïîñëå íå¼ ñòðîêó ñèìâîëîâ. Ïîëüçîâàòåëþ äîëæíî ðàçðåøàòüñÿ çàïèñûâàòü îäèíàêîâûå ñòðîêè â òàáëèöó; 14) êîìàíäà ¾show¿ äîëæíà âûâîäèòü íà ýêðàí òàáëèöó õðàíèìûõ ñòðîê. Êàê âèäíî, ýòè ÷åòûðíàäöàòü íåñëîæíûõ ïðàâèë íåïëîõî îïèñûâàþò ôóíêöèîíàëüíîñòü ïðîñòîãî èíòåðïðåòàòîðà êîìàíä. Íàáîð êîìàíä ñîñòîèò èç ïÿòè íåñëîæíûõ äåéñòâèé, íà ïðèìåðå êîòîðûõ ìîæíî ëåãêî ïîíÿòü ïðèíöèïû ðàáîòû ïîäîáíûõ èíòåðïðåòàòîðîâ. Îñîáûé èíòåðåñ ïðåäñòàâëÿþò äâå ïîñëåäíèå êîìàíäû ¾store¿ è ¾show¿, ïîñêîëüêó îíè ðàáîòàþò ñ íåêîé òàáëèöåé ñèìâîëîâ, òî åñòü, ïî ñóòè, îñóùåñòâëÿþò íåêîòîðûå äåéñòâèÿ, îòëè÷íûå îò ñëóæåáíûõ âûõîäà èç ïðîãðàììû, âûâîäà ñïðàâî÷íîé èíôîðìàöèè è íîìåðà âåðñèè ïðîãðàììû. Òàê ÷òî â äàëüíåéøåì ðàññìîòðåíèè ýòèì äâóì êîìàíäàì íåîáõîäèìî áóäåò óäåëèòü îñîáåííîå âíèìàíèå.
Îñíîâíîé íàáîð ôóíêöèé ×òî òàêîå ïðîñòîé èíòåðïðåòàòîð êîìàíä? Åãî àëãîðèòì ðàáîòû íà âåðõíåì óðîâíå äîñòàòî÷íî ïðîñò: âûâîä çàïðîñà ïîëüçîâàòåëþ íà ââîä êîìàíäû, îáðàáîòêà ââåä¼ííîãî, âûïîëíåíèå êîìàíäû, âûâîä ðåçóëüòàòîâ å¼ ðàáîòû (è âûïîëíåíèå èíîãî ýôôåêòà) è âîçâðàò â íà÷àëî ýòîãî àëãîðèòìà. Ïîëó÷àåòñÿ,
Îñíîâíîé íàáîð ôóíêöèé
75
öèêëå èíòåðïðåòàöèè
÷òî â íåîáõîäèìî ïîëó÷èòü êîìàíäó îò ïîëüçîâàòåëÿ, âûïîëíèòü å¼ è âûâåñòè íà ýêðàí ðåçóëüòàòû å¼ âûïîëíåíèÿ; ïîñëå ÷åãî âñ¼ íà÷èíàåòñÿ ñíà÷àëà. Ïîýòîìó äëÿ ðåàëèçàöèè öèêëà èíòåðïðåòàöèè íåîáõîäèìî ïðîñòî îïèñàòü ýòîò àëãîðèòì íà ÿçûêå ïðîãðàììèðîâàíèÿ. Ê òîìó æå ñàì àëãîðèòì âåñüìà äåêëàðàòèâåí, ïîýòîìó åãî ðåàëèçàöèÿ íà òàêîì ÿçûêå, êàê Haskell, áóäåò ïðîñòîé. Îäíàêî ïåðåä îïðåäåëåíèåì ôóíêöèè, êîòîðàÿ ðåàëèçóåò îïèñàííûé àëãîðèòì, íåîáõîäèìî ñîçäàòü íåêîòîðûå âñïîìîãàòåëüíûå îïðåäåëåíèÿ.
Âñïîìîãàòåëüíûå òèïû äàííûõ Äëÿ íà÷àëà íåîáõîäèìî îïðåäåëèòü òèïû äàííûõ, ñ êîòîðûìè áóäóò ðàáîòàòü ôóíêöèè, îòâå÷àþùèå çà îðãàíèçàöèþ öèêëà èíòåðïðåòàöèè. Ïðåæäå âñåãî ýòî òèï èíòåðïðåòàòîðà, â êîòîðîì õðàíèòñÿ èíôîðìàöèÿ î çàïèñûâàåìûõ ïîëüçîâàòåëåì ñòðîêàõ. Ïîñêîëüêó, êðîìå ñòðîê, íè÷åãî â îêðóæåíèè õðàíèòüñÿ íå áóäåò, åãî òèï ìîæíî îïðåäåëèòü â âèäå ñèíîíèìà:
îêðóæåíèÿ
type Environment = [ String ] Îäíî çíà÷åíèå ýòîãî òèïà áóäåò ñîçäàâàòüñÿ â ñàìîì íà÷àëå çàïóñêà ïðîãðàììû è ïåðåäàâàòüñÿ èç ôóíêöèè â ôóíêöèþ äëÿ îáåñïå÷åíèÿ òîãî, ÷òîáû â ëþáîé ìîìåíò âðåìåíè ïðîèçâîëüíàÿ ôóíêöèÿ çíàëà ñîñòàâ îêðóæåíèÿ (äàæå â ñëó÷àå, åñëè â ñàìîé ôóíêöèè ýòî îêðóæåíèå íå èñïîëüçóåòñÿ). Äàííàÿ òåõíîëîãèÿ ÿâëÿåòñÿ îáû÷íîé â ôóíêöèîíàëüíîì ïðîãðàììèðîâàíèè, ïîñêîëüêó ãëîáàëüíûå ïåðåìåííûå çàïðåùåíû ïàðàäèãìîé (ñòîðîííèå ýôôåêòû íåäîïóñòèìû, à êàæäàÿ ôóíêöèÿ äîëæíà áûòü äåòåðìèíèðîâàííîé). Ñàìî ñîáîé, ÷òî íåêîòîðûå ôóíêöèè ìîãóò èçìåíÿòü îêðóæåíèå, íåêîòîðûå ìîãóò èì âîîáùå íå ïîëüçîâàòüñÿ, íî â êà÷åñòâå ïàðàìåòðà òàêîå îêðóæåíèå áóäåò ïåðåäàâàòüñÿ âåçäå, ãäå îíî áûëî áû íåîáõîäèìî. Íèæå ïðè ðåàëèçàöèè ñóòü ýòîãî áóäåò ÿñíà. Âòîðîé òèï äàííûõ, íåîáõîäèìûé äëÿ ðàáîòû èíòåðïðåòàòîðà, êîä ðåçóëüòàòà âûïîëíåíèÿ êîìàíä. Ýòîò êîä íåîáõîäèì äëÿ òîãî, ÷òîáû â ôóíêöèè öèêëà èíòåðïðåòàöèè îáðàáàòûâàòü ðåçóëüòàò âûïîëíåíèÿ êîìàíäû äîëæíûì îáðàçîì. Îáû÷íî â êà÷åñòâå ìíîæåñòâà çíà÷åíèé òàêîãî êîäà èñïîëüçóþòñÿ äâà ýëåìåíòà êîä âûõîäà èç ïðîãðàììû è êîä óñïåøíîãî âûïîëíåíèÿ îïåðàöèè. Èíîãäà äîáàâëÿåòñÿ êîä íåóñïåøíîãî âûïîëíåíèÿ îïåðàöèè, ÷òîáû â öèêëå èíòåðïðåòàöèè âûâîäèòü ñîîáùåíèå îá ýòîì â ñòàíäàðòíûé ïîòîê âûâîäà ñîîáùåíèé îá îøèáêàõ cerr. Òàêæå ÷àñòî â ýòî ìíîæåñòâî äîáàâëÿþò äâà êîäà êîä íåîáõîäèìîñòè çàïèñè îêðóæåíèÿ â ôàéë è êîä íåîáõîäèìîñòè ÷òåíèÿ îêðóæåíèÿ èç ôàéëà. Ýòî äåëàåòñÿ äëÿ òîãî, ÷òîáû èçáàâèòüñÿ îò íåîáõîäèìîñòè èñïîëüçîâàíèÿ ñèñòåìû ââîäà/âûâîäà âíóòðè ôóíêöèé, âûïîëíÿþùèõ êîìàíäû, à ñàì ââîä/âûâîä ïðîèçâîäèëñÿ áû òîëüêî íà âåðõíåì óðîâíå â ôóíêöèè îðãàíèçàöèè öèêëà èíòåðïðåòàöèè. Èòàê, â ñëó÷àå ïðîñòîãî èíòåðïðåòàòîðà êîìàíä òàêîé òèï ìîæåò âûãëÿäåòü ñëåäóþùèì îáðàçîì:
data ICode IC_Exit IC_Error IC_HelpMessage IC_Success deriving Eq
= | | |
Äîïîëíèòåëüíûé êîíñòðóêòîð IC_HelpMessage äîáàâëåí äëÿ ðàçëè÷åíèÿ òîãî, ÷òî â êà÷åñòâå ðåçóëüòàòà êîìàíäà âåðíóëà ñïðàâî÷íóþ èíôîðìàöèþ. Âîçìîæíî, ÷òî ýòî ìîæåò ïðèãîäèòüñÿ ïðè ðàçâèòèè èíòåðïðåòàòîðà, õîòÿ â ñîçäàâàåìîé âåðñèè ýòîò êîíñòðóêòîð èñïîëüçîâàòüñÿ íå áóäåò. Íàêîíåö, âåñüìà âàæíûì òèïîì ÿâëÿåòñÿ òèï çíà÷åíèÿ, êîòîðûé âîçâðàùàåòñÿ êàæäîé ôóíêöèåé, êîòîðàÿ îáðàáàòûâàåò îäíó êîìàíäó.  öåëÿõ åäèíîîáðàçèÿ ýòî áóäåò îäèí òèï (äà è áûëî áû âåñüìà íåïðîñòî ñäåëàòü îáðàáîòêó ðàçëè÷íûõ òèïîâ, îòäåëüíûõ äëÿ êàæäîé êîìàíäû, õîòÿ è ïî òàêîìó ïóòè ïîéòè, â ïðèíöèïå, âîçìîæíî). Ýòîò òèï äîëæåí îáúåäèíÿòü â ñåáå êîä âûïîëíåíèÿ îïåðàöèè ICode, ñòðîêó ñ ñîîáùåíèåì î ðåçóëüòàòå âûïîëíåíèÿ (åñëè êîìàíäà ÷òî-òî ðàññ÷èòûâàåò, òî ðåçóëüòàò ðàñ÷¼òîâ
76
Ïðîñòîé èíòåðïðåòàòîð êîìàíä
ìîæíî ïðèâåñòè â ñòðîêîâûé âèä), à òàêæå íîâîå çíà÷åíèå îêðóæåíèÿ, êîòîðîå ìîãëî ïîìåíÿòüñÿ â ðåçóëüòàòå äåéñòâèÿ êîìàíäû. Èòîãî:
data IResult = IResult {
code : : ICode , message : : String , environment : : Environment } Âñ¼ ãîòîâî äëÿ ðåàëèçàöèè ôóíêöèè, îðãàíèçóþùåé öèêë èíòåðïðåòàöèè.
Öèêë èíòåðïðåòàöèè Èòàê, êàê óêàçàíî â ñàìîì íà÷àëå ýòîãî ðàçäåëà, öèêë èíòåðïðåòàöèè çàêëþ÷àåòñÿ â âûïîëíåíèè îäíîé êîìàíäû, êîòîðàÿ, âîçìîæíî, ìîäèôèöèðóåò îêðóæåíèå. Ýòî çíà÷èò, ÷òî ôóíêöèÿ, ðåàëèçóþùàÿ öèêë èíòåðïðåòàöèè, äîëæíà ïîëó÷àòü íà âõîä çíà÷åíèå òèïà Environment. Âðîäå áû íè÷åãî äîïîëíèòåëüíîãî åé äëÿ ðàáîòû íå òðåáóåòñÿ. Âîçâðàùàåò æå ýòà ôóíêöèÿ ïóñòîå çíà÷åíèå IO (). Ñîáñòâåííî, ðåàëèçàöèÿ ñàìîé ôóíêöèè äîñòàòî÷íî ïðîñòà:
runICycle : : Environment −> IO ( ) runICycle env = do putStr " Ââåäèòå êîìàíäó : " cmd <− getLine result <− interprete cmd env case ( code result ) of IC_Exit −> putStrLn " Âñåãî äîáðîãî . " _ −> do putStrLn ( message result ++ "\ n " ) runICycle $ environment result Êàê îáû÷íî, ïåðåâîä äåêëàðàòèâíîãî àëãîðèòìà íà íåêîòîðûé ôóíêöèîíàëüíûé ÿçûê ïðîãðàììèðîâàíèÿ ïðîèçâîäèòñÿ ÷óòü ëè íå ñëîâî â ñëîâî.  ñïèñêå îïåðàöèé ââîäà/âûâîäà âûðàæåíèÿ do (ïåðâîãî óðîâíÿ) èìåþòñÿ ðîâíî ÷åòûðå îïåðàöèè, ðîâíî êàê â îïèñàííîì â íà÷àëå àëãîðèòìå. Ïåðâàÿ ñòðîêà ñ ôóíêöèåé putStr âûâîäèò íà ýêðàí ïðèãëàøåíèå ê ââîäó êîìàíäû. Âòîðàÿ ñòðîêà ñ ôóíêöèåé getLine ñ÷èòûâàåò ñ êëàâèàòóðû ñòðîêó ñèìâîëîâ. ×åòâ¼ðòàÿ ñòðîêà ñ îïåðàòîðîì case ïðîâåðÿåò êîä ðåçóëüòàòà âûïîëíåíèÿ êîìàíäû, è åñëè ýòîò êîä ñèãíàëèçèðóåò î íåîáõîäèìîñòè âûõîäà èç öèêëà èíòåðïðåòàöèè è ïðîãðàììû (ïåðâàÿ àëüòåðíàòèâà), òî ïðîèñõîäèò âûâîä íà ýêðàí ïðîùàíèÿ.  ïðîòèâíîì ñëó÷àå, åñëè êîä ðåçóëüòàòà êàêîé-òî èíîé, ïðîèñõîäèò âûâîä íà ýêðàí ñîîáùåíèÿ, êîòîðîå âåðíóëà âûïîëíåííàÿ êîìàíäà, à òàêæå çàïóñê òîé æå ñàìîé ôóíêöèè runICycle ñ íîâûì çíà÷åíèåì îêðóæåíèÿ. Íàèáîëåå èíòåðåñíîé ñòðîêîé â ýòîì ñïèñêå îïåðàöèé ââîäà/âûâîäà ÿâëÿåòñÿ òðåòüÿ ñòðîêà, â êîòîðîé ïîëó÷àåòñÿ ðåçóëüòàò âûïîëíåíèÿ êîìàíäû cmd ïðè òåêóùåì çíà÷åíèè îêðóæåíèÿ env. Ôóíêöèÿ interprete, êîòîðóþ åù¼ ïðåäñòîèò ðåàëèçîâàòü, âîçâðàùàåò â âèäå îáðàçöà result, êîòîðûé èìååò òèï IResult, êàê ðàç ðåçóëüòàò âûïîëíåíèÿ êîìàíäû. Êàê âèäíî èç å¼ ïðèìåíåíèÿ, îíà ïîëó÷àåò íà âõîä äâà ïàðàìåòðà òèïîâ String è Environment, à âîçâðàùàåò ðåçóëüòàò òèïà IO IResult. Òåëî ôóíêöèè îïÿòü æå íå ïðåäñòàâëÿåò íè÷åãî ñëîæíîãî:
interprete : : String −> Environment −> IO IResult interprete cmd env = i f ( cmd == " " ) then return $
Îñíîâíîé íàáîð ôóíêöèé
77
IResult IC_Success " Ïîæàëóéñòà , ââåäèòå êîìàíäó . " env el se l e t ( c : args ) = words cmd command = findCommand c commands in case command of Nothing −> return $ IResult IC_Error " Îøèáêà . Íåëåïàÿ êîìàíäà . " env Just fnc −> return $ fnc ( unwords args ) env Ïðåæäå âñåãî íåîáõîäèìî ïðîâåðèòü, íå ÿâëÿåòñÿ ëè ââåä¼ííàÿ ïîëüçîâàòåëåì êîìàíäà ïóñòîé ñòðîêîé. Åñëè ýòî òàê, òî ïîëüçîâàòåëþ íåîáõîäèìî ñîîáùèòü, ÷òî îí äîëæåí ââåñòè êîìàíäó. Ýòî äåëàåòñÿ ïðè ïîìîùè îïåðàöèè â ÷àñòè then óñëîâèÿ. Ìåòîä return ¾îáîðà÷èâàåò¿ ïåðåäàííîå åìó çíà÷åíèå â òèï-êîíòåéíåð IO. Âî âòîðîé àëüòåðíàòèâå, åñëè ââåä¼ííàÿ êîìàíäà íå ÿâëÿåòñÿ ïóñòîé ñòðîêîé, îíà ðàçáèâàåòñÿ íà ¾ñëîâà¿ (ïî ïðîáåëüíûì ñèìâîëàì) ïðè ïîìîùè ñòàíäàðòíîé ôóíêöèè words. Ýòà ôóíêöèÿ ïîëó÷àåò íà âõîä ñòðîêó, à âîçâðàùàåò ñïèñîê ñòðîê. Òàêèì îáðàçîì ïåðâûì ýëåìåíòîì ýòîãî ñïèñêà ÿâëÿåòñÿ íàèìåíîâàíèå êîìàíäû, à âñå ïîñëåäóþùèå å¼ àðãóìåíòû. command ñîçäà¼òñÿ ïðè ïîìîùè ôóíêöèè findCommand, êîòîðàÿ åù¼ áóäåò ðåàëèçîâàíà. Ýòà ôóíêöèÿ âîçâðàùàåò çíà÷åíèå, ¾îá¼ðíóòîå¿ â òèï Maybe, ýòîò òèï âñåãäà èñïîëüçóåòñÿ â òåõ ñëó÷àÿõ, êîãäà â ïîñëå âûïîëíåíèÿ ôóíêöèè ìîæåò íå îêàçàòüñÿ êàêîãî-ëèáî ðåçóëüòàòà.  äàííîì ñëó÷àå ïîëó÷åíèå çíà÷åíèÿ Nothing ñâèäåòåëüñòâóåò î òîì, ÷òî ôóíêöèÿ äëÿ âûïîëíåíèÿ ââåä¼ííîé êîìàíäû íå áûëà íàéäåíà, òî åñòü êîìàíäà ÿâëÿåòñÿ íåèçâåñòíîé ïðîñòîìó èíòåðïðåòàòîðó. Ñîîòâåòñòâåííî, åñëè ôóíêöèÿ findCommand íàõîäèò òðåáóåìóþ êîìàíäó è âîçâðàùàåò å¼ â êîíñòðóêòîðå Just, òî ýòó êîìàíäó íåîáõîäèìî âûïîëíèòü, ïåðåäàâ åé íà âõîä ñïèñîê àðãóìåíòîâ (â âèäå ñòðîêè) è òåêóùåå çíà÷åíèå îêðóæåíèÿ (âåäü êîìàíäà ìîæåò ðàáîòàòü ñ îêðóæåíèåì). Íî ñðåäè ÷åãî ôóíêöèÿ findCommand èùåò ôóíêöèè, êîòîðûå ðåàëèçóþò äåéñòâèÿ êîìàíä? Êàê âèäíî èç å¼ ïðèìåíåíèÿ, âòîðûì àðãóìåíòîì åé íà âõîä ïåðåäà¼òñÿ íåêîòîðàÿ ôóíêöèÿ commands (íà òî, ÷òî ýòî âíåøíÿÿ ôóíêöèÿ, óêàçûâàåò òî, ÷òî îíà íèãäå íå îïðåäåëåíà â ôóíêöèè interprete â âèäå çàìûêàíèÿ èëè îáðàçöà). Ýòà êîíñòàíòíàÿ ôóíêöèÿ áóäåò íàïèñàíà íèæå îíà ïðîñòî âîçâðàùàåò ñïèñîê ñîîòâåòñòâèé èì¼í êîìàíä (ñòðîê) ôóíêöèÿì. ż ðåàëèçàöèÿ áóäåò ïîêàçàíà â ñëåäóþùåì ðàçäåëå. Íó à ôóíêöèÿ findCommand âûãëÿäèò íå ñëîæíåå äðóãèõ, îïðåäåë¼ííûõ ðàíåå:
Çàìûêàíèå
findCommand : : String −> [ ( String , Command ) ] −> Maybe Command findCommand _ [] = Nothing findCommand cmd ( ( n , c ) : cs ) = i f ( ( map toLower cmd ) ` isPrefixOf ` n ) then Just c el se findCommand cmd cs Ïðè îïðåäåëåíèè ýòîé ôóíêöèè èñïîëüçóþòñÿ äâå ôóíêöèè, âõîäÿùèå â ìîäóëè ñòàíäàðòíîé ïîñòàâêè áèáëèîòåê ÿçûêà Haskell. Ôóíêöèÿ toLower ïåðåâîäèò çàäàííûé ñèìâîë â íèæíèé ðåãèñòð, à ôóíêöèÿ isPrefixOf âîçâðàùàåò çíà÷åíèå True, åñëè ïåðâûé çàäàííûé ñïèñîê ÿâëÿåòñÿ íà÷àëîì âòîðîãî (èëè îíè ñîâïàäàþò). Ïîýòîìó ïðèìåíåíèå óñëîâèÿ (( map toLower cmd) `isPrefixOf` n) êàê ðàç è óäîâëåòâîðÿåò òðåáîâàíèÿ ê ïðîñòîìó èíòåðïðåòàòîðó êîìàíä êîìàíäà äîëæíà ðàñïîçíàâàòüñÿ â ëþáîì ðåãèñòðå, à ñàìî ðàñïîçíàâàíèå äîëæíî âåñòèñü ïî íà÷àëüíûì ñèìâîëàì. Äëÿ òîãî ÷òîáû èñïîëüçîâàòü ýòè ôóíêöèè, íåîáõîäèìî ïðîèçâåñòè ïîäêëþ÷åíèå ìîäóëåé:
import Char ( toLower ) import List ( isPrefixOf ) Òåïåðü âñ¼ ãîòîâî äëÿ ðåàëèçàöèè ôóíêöèè main. Îíà ñîñòîèò èç äâóõ ñòðîê:
main : : IO ( )
78
Ïðîñòîé èíòåðïðåòàòîð êîìàíä
main = do putStrLn greetings runICycle [ ] Ôóíêöèÿ greetings ÿâëÿåòñÿ êîíñòàíòíîé è ñîäåðæèò ñòðîêó ïðèâåòñòâèÿ. Ýòà ñòðîêà âûíåñåíà â êîíñòàíòíóþ ôóíêöèþ â öåëÿõ ïîâòîðíîãî èñïîëüçîâàíèÿ (îíà åù¼ ïðèãîäèòñÿ ïðè ðåàëèçàöèè ôóíêöèé, îáåñïå÷èâàþùèõ âûïîëíåíèå êîìàíä). ż îïðåäåëåíèå òðèâèàëüíî:
greetings : : String greetings = " Ïðîñòîé èíòåðïðåòàòîð êîìàíä . Âåðñèÿ 2 0 0 7 . "
Ôóíêöèè äëÿ èñïîëíåíèÿ êîìàíä Òåïåðü ïðèøëî âðåìÿ ðåàëèçîâàòü âñå ôóíêöèè, êîòîðûå âûïîëíÿþò çàÿâëåííûå â òðåáîâàíèÿõ êîìàíäû. Íî ïåðåä ýòèì íåîáõîäèìî çàïèñàòü ñïèñîê òàêèõ ôóíêöèé è èõ îòîáðàæåíèå íà ðàçëè÷íûå êîìàíäû â ñïåöèàëüíîé êîíñòàíòíîé ôóíêöèè commands, êîòîðàÿ âûçûâàåòñÿ èç ôóíêöèè findCommand. Èç ñèãíàòóðû ýòîé ôóíêöèè òàêæå ÿñíî, ÷òî òèïîì êîíñòàíòíîé ôóíêöèè commands äîëæåí áûòü ñïèñîê ïàð [( String, Command)]. Îñòà¼òñÿ íåÿñíûì, ÷òî òàêîå çà òèï Command. Ýòî ïðîñòî ñèíîíèì ôóíêöèîíàëüíîãî òèïà, ñîçäàííûé äëÿ óäîáñòâà:
type Command = String −> Environment −> IResult Ýòîò òèï äîëæíà èìåòü êàæäàÿ ôóíêöèÿ, êîòîðàÿ èñïîëíÿåò êîìàíäó, ââåä¼ííóþ ïîëüçîâàòåëåì. Êàê âèäíî, êàæäàÿ òàêàÿ ôóíêöèÿ ïðèíèìàåò íà âõîä ñòðîêó àðãóìåíòîâ è îêðóæåíèå, à âîçâðàùàåò îáû÷íûé ðåçóëüòàò âûïîëíåíèÿ êîìàíäû, îïèñûâàåìûé òèïîì IResult. Òàê ÷òî òåïåðü ìîæíî ñîçäàòü ñïèñîê êîìàíä:
commands : : [ ( String , Command ) ] commands = [ ( " ? " , doHelp ) , ( " exit " , doExit ) , ( " help " , doHelp ) , ( " manual " , doHelp ) , ( " quit " , doExit ) , ( " show " , doShow ) , ( " store " , doStore ) , ( " version " , doVersion ) ] Êàê âèäíî, ýòîò ñïèñîê ïîçâîëÿåò îäíîâðåìåííî çàäàâàòü ìíåìîíè÷åñêèå èìåíà äëÿ êîìàíä è èõ ñèíîíèìû.  òàêîì ñïèñêå ìîæíî äåðæàòü ïðîèçâîëüíîå êîëè÷åñòâî ñèíîíèìîâ êîìàíä, ðàâíî êàê è çàäàâàòü íîâûå êîìàíäû. Ïîñêîëüêó ôóíêöèîíàëüíûå ÿçûêè ïðîãðàììèðîâàíèÿ òðàêòóþò ôóíêöèè êàê îáûêíîâåííûå çíà÷åíèÿ, íåò íè÷åãî óäèâèòåëüíîãî â òîì, ÷òî ñàìè ôóíêöèè ìîãóò âûñòóïàòü â êà÷åñòâå ýëåìåíòîâ ñòðóêòóð äàííûõ êîðòåæåé è ñïèñêîâ. Òàê ÷òî òåïåðü îñòà¼òñÿ ðåàëèçîâàòü ïÿòü ôóíêöèé: doExit, doHelp, doShow, doStore è doVersion. Èìååò ñìûñë íà÷àòü ðàññìîòðåíèå ñ ôóíêöèè doHelp. Îíà ðàñïå÷àòûâàåò îáùóþ ñïðàâî÷íóþ èíôîðìàöèþ, à òàêæå èíôîðìàöèþ î çàäàííîé êîìàíäå. Òàê ÷òî âíóòðè íå¼ èìååò ñìûñë âûçûâàòü âñå îñòàëüíûå ôóíêöèè ñî ñïåöèàëüíûì àðãóìåíòîì ¾−?¿, êàê ýòî çàÿâëåíî òðåáîâàíèÿìè ê ïðîñòîìó èíòåðïðåòàòîðó êîìàíä. Èòàê, ôóíêöèÿ doHelp âûãëÿäèò ïðèìåðíî ñëåäóþùèì îáðàçîì:
doHelp : : Command doHelp args env = case args of "" −> IResult
Ôóíêöèè äëÿ èñïîëíåíèÿ êîìàíä
79
IC_HelpMessage ( greetings ++ "\ nÏîæàëóéñòà , ââåäèòå \" help
\" \\ äëÿ ïîëó÷åíèÿ èíôîðìàöèè \\ î êîìàíäå \" cmd \ " . " ) env " −?" −> IResult
IC_HelpMessage " Âûâîäèò ñïðàâî÷íóþ èíôîðìàöèþ \\ î çàäàííîé êîìàíäå . " env _
−> l e t cmd = findCommand args commands
in
case cmd of Nothing
−> IResult
IC_Error ( " Îøèáêà . Íåâîçìîæíî \\ íàéòè ñïðàâî÷íóþ \\ èíôîðìàöèþ î êîìàíäå \"" ++ args ++ " \ " . " ) env Just fnc −> fnc " −?" env Êàê âèäíî, åñëè ýòà êîìàíäà ââåäåíà áåç àðãóìåíòîâ, îíà âûâîäèò îáùóþ èíôîðìàöèþ î ïðîãðàììå, â òîì ÷èñëå è ïåðâîíà÷àëüíîå ïðèâåòñòâèå ñ âåðñèåé ïðîãðàììû. Åñëè ïåðåäàòü ýòîé ôóíêöèè â êà÷åñòâå àðãóìåíòà çàÿâëåííóþ ñòðîêó ¾−?¿, òî ïðîèçîéä¼ò âûâîä ñïðàâî÷íîé èíôîðìàöèè î ñàìîé êîìàíäå help. Åñëè æå ââåñòè êàêîé-ëèáî èíîé àðãóìåíò, òî ïðîèçîéä¼ò ïîèñê êîìàíäû îïÿòü âñ¼ â òîì æå ñïèñêå êîìàíä commands, è â ñëó÷àå åñëè êîìàíäà áóäåò íàéäåíà, äëÿ ïîëó÷åíèÿ ñïðàâêè îíà áóäåò âûçâàíà ñ àðãóìåíòîì ¾−?¿. Âåñüìà èçÿùíî. ×òî áóäåò, åñëè â ñòðîêå ââîäà ïðîñòîãî èíòåðïðåòàòîðà êîìàíä ââåñòè êîìàíäó help help? Íàèáîëåå ïðîñòûìè ÿâëÿþòñÿ êîìàíäû doExit è doVersion. Èõ ðåàëèçàöèÿ òðèâèàëüíà:
doExit : : Command doExit " −?" env = IResult IC_HelpMessage " Âûõîäèò èç ïðîñòîãî \\ èíòåðïðåòàòîðà êîìàíä . " env doExit args env = IResult IC_Exit "" env doVersion : : Command doVersion " −?" env = IResult IC_HelpMessage " Âûâîäèò èíôîðìàöèþ î \\ òåêóùåé âåðñèè ïðîãðàììû . " env doVersion args env = IResult IC_Success greetings env À âîò ôóíêöèè doShow è doStore ÿâëÿþòñÿ íàèáîëåå èíòåðåñíûìè, ïîñêîëüêó ðàáîòàþò ñ îêðóæåíèåì env, êîòîðîå ïåðåäà¼òñÿ ñêâîçü âñå ôóíêöèè ïðîñòîãî èíòåðïðåòàòîðà. Ïåðâàÿ êîìàíäà íå ìîäèôèöèðóåò îêðóæåíèå, íî èñïîëüçóåò åãî äëÿ âûâîäà ñîîáùåíèÿ íà ýêðàí. Îíà íåìíîãèì áîëåå ñëîæíàÿ, ÷åì îñòàëüíûå, ðàññìîòðåííûå äî ýòîãî:
doShow : : Command doShow " −?" env = IResult IC_HelpMessage " Âûâîäèò òåêóùåå ñîäåðæèìîå \\ òàáëèöû ñòðîê . " env doShow args env = IResult IC_Success ( showTable env ) env
where
80
Ïðîñòîé èíòåðïðåòàòîð êîìàíä
showTable [ ] = "" showTable ( s : [ ] ) = s showTable ( s : ss ) = s ++ "\ n " ++ showTable ss Íàêîíåö, ôóíêöèÿ doStore ìîäèôèöèðóåò îêðóæåíèå. Íî è îíà ñàìà ïî ñåáå íå òàê ñëîæíà:
doStore : : Command doStore " −?" env = IResult IC_HelpMessage " Çàïèñûâàåò çàäàííóþ ñòðîêó \\ â òàáëèöó ñòðîê . " env doStore args env = IResult IC_Success ( " Ñòðîêà \"" ++ args ++ "\" óñïåøíî ñîõðàíåíà . " ) ( args : env ) Êàê âèäíî, íîâàÿ ñòðîêà ïðîñòî äîáàâëÿåòñÿ â ãîëîâó èìåþùåãîñÿ ñïèñêà ñòðîê, ïðåäñòàâëåííîãî îêðóæåíèåì. Ýòî íîâîå îêðóæåíèå âîçâðàùàåòñÿ â ñòàíäàðòíîì ðåçóëüòàòå âûïîëíåíèÿ êîìàíäû. Íåò íè÷åãî ïðîùå. Òàêèì îáðàçîì, îïèñàííûì íåñëîæíûì ñïîñîáîì ìîæíî ðåàëèçîâàòü ïðîèçâîëüíûå íàáîðû êîìàíä. Åäèíñòâåííîå, íà ÷òî íåîáõîäèìî îáðàùàòü âíèìàíèå, îïåðàöèè ââîäà/âûâîäà íåäîïóñòèìû â êîìàíäàõ ïðè òàêîé ðåàëèçàöèè, ïîñêîëüêó òèï ôóíêöèé Command íå èìååò âíóòðè ñåáÿ òèïà IO.  ñëó÷àå, åñëè íåîáõîäèìî ñîõðàíÿòü îêðóæåíèå â ôàéë è ñ÷èòûâàòü åãî èç ôàéëà, à òàêæå ñîâåðøàòü èíûå îïåðàöèè ââîäà/âûâîäà, íåîáõîäèìî èëè êàêèì-ëèáî îáðàçîì óêàçûâàòü íà ýòîò ôàêò áîëåå âûñîêèì ôóíêöèÿì (íàïðèìåð, ôóíêöèè runICycle, â êîòîðîé îáðàáàòûâàþòñÿ ðåçóëüòàòû êîìàíä), ëèáî ìåíÿòü òèï Command, âêëþ÷àÿ â íåãî âîçìîæíîñòü ðàáîòû ñ ñèñòåìîé ââîäà/âûâîäà. Ïîñëåäíèé ñïîñîá öåëåñîîáðàçåí, êîãäà áîëüøàÿ ÷àñòü êîìàíä ðàáîòàåò ñ ââîäîì/âûâîäîì.
Çàêëþ÷åíèå  äàííîì ðàçäåëå, êðîìå íåïîñðåäñòâåííîãî èçó÷åíèÿ ñèñòåìû ââîäà/âûâîäà ÿçûêà Haskell è ðåàëèçàöèè ïðîñòîãî èíòåðïðåòàòîðà êîìàíä, òàêæå ðàññìàòðèâàåòñÿ èíòåðåñíåéøèé âîïðîñ ïåðåäà÷è íåêîòîðîãî îêðóæåíèÿ ïî âñåìó íàáîðó ôóíêöèé, èñïîëüçóþùèõñÿ â öèêëå èíòåðïðåòàöèè.  ðàññìîòðåííîì ïðèìåðå ýòà ïåðåäà÷à ïîâñþäó îñóùåñòâëÿëàñü âðó÷íóþ. Êàê ñêàçàíî, ýòî ñäåëàíî íàðî÷íî, ÷òîáû íå çàãðóæàòü ÷èòàòåëÿ áîëåå ñåðü¼çíûìè è ñëîæíûìè òåõíîëîãèÿìè. Äåëî â òîì, ÷òî òàêàÿ ¾ñêâîçíàÿ¿ ïåðåäà÷à ïàðàìåòðà èç îäíîé ôóíêöèè â äðóãóþ ÿâëÿåòñÿ òèïîâîé çàäà÷åé, êîòîðàÿ ÷àñòî âñòðå÷àåòñÿ â ðàçëè÷íûõ ïðîãðàììàõ. Ñàìî ñîáîé, ÷òî äëÿ å¼ ðåøåíèÿ óæå èìååòñÿ ãîòîâàÿ òåõíîëîãèÿ, îñíîâàííàÿ íà , òàê æå êàê è ñàìà ñèñòåìà ââîäà/âûâîäà ÿçûêà Haskell. Äàííàÿ ìîíàäà íàçûâàåòñÿ State ¾Ñîñòîÿíèå¿. ×èòàòåëè, çàèíòåðåñîâàâøèåñÿ âîïðîñîì, ìîãóò ñàìîñòîÿòåëüíî èçó÷èòü ïðèíöèïû ïðèìåíåíèÿ ìîíàäû State. Äîïîëíèòåëüíî îçíàêîìèòüñÿ ñ ïîíèìàíèåì ìîíàä â ôóíêöèîíàëüíîì ïðîãðàììèðîâàíèè è â ÿçûêå Haskell â ÷àñòíîñòè ìîæíî ïðè ïîìîùè ñëåäóþùèõ èñòî÷íèêîâ: [11, 19, 22].
ìîíàäå
Òåîðèÿ ÷èñåë è ÿçûê Haskell Ñòàòüÿ áûëà îïóáëèêîâàíà â 05 (17) æóðíàëà ¾Ïîòåíöèàë¿ â ìàå 2006 ãîäà (ïåðâàÿ ñòàòüÿ èç öèêëà ñòàòåé î ÿçûêå Haskell).
Ýòî ýññå ðàññìàòðèâàåò ôóíêöèîíàëüíûé ÿçûê ïðîãðàììèðîâàíèÿ Haskell íà ïðèìåðå íåêîòîðûõ èíòåðåñíûõ çàäà÷ èç òåîðèè ÷èñåë, è ïðåäëàãàþòñÿ ÷èñëåííûå ñïîñîáû èõ ðåøåíèÿ. Ìåòîäîëîãèÿ ïðåäñòàâëåíèÿ ôóíêöèé íà ÿçûêå Haskell îñíîâàíà íà òîì, ÷òîáû ñäåëàòü îïðåäåëåíèÿ òàêèõ ôóíêöèé íàèáîëåå ïîõîæèìè íà ìàòåìàòè÷åñêèå ôîðìóëû.
Ââåäåíèå Òåîðèÿ ÷èñåë ýòî îäíî èç íàïðàâëåíèé ìàòåìàòèêè, êîòîðîå èíîãäà íàçûâàþò ¾âûñøåé àðèôìåòèêîé¿. Äàííàÿ íàóêà èçó÷àåò íàòóðàëüíûå ÷èñëà è íåêîòîðûå ñõîäíûå ñ íèìè îáúåêòû, ðàññìàòðèâàåò ðàçëè÷íûå ñâîéñòâà (äåëèìîñòü, ðàçëîæèìîñòü, âçàèìîñâÿçè è ò. ä.), àëãîðèòìû ïîèñêà ÷èñåë, à òàêæå îïðåäåëÿåò ðÿä äîñòàòî÷íî èíòåðåñíûõ íàáîðîâ íàòóðàëüíûõ ÷èñåë. Òàê, ê ïðèìåðó, â ðàìêàõ òåîðèè ÷èñåë ðàññìàòðèâàþòñÿ âîïðîñû äåëèìîñòè öåëûõ ÷èñåë äðóã íà äðóãà, àëãîðèòì Åâêëèäà äëÿ ïîèñêà íàèáîëüøåãî îáùåãî äåëèòåëÿ, ïîèñê íàèìåíüøåãî îáùåãî êðàòíîãî, ìàëàÿ è áîëüøàÿ òåîðåìû Ôåðìà.  êà÷åñòâå ñàìûõ èçâåñòíûõ ðÿäîâ íàòóðàëüíûõ ÷èñåë ìîæíî ïðèâåñòè ðÿä Ôèáîíà÷÷è, ïðîñòûå ÷èñëà, ñîâåðøåííûå è äðóæåñòâåííûå ÷èñëà, ñòåïåíè è ñóïåðñòåïåíè íàòóðàëüíûõ ÷èñåë. Ñ äðóãîé ñòîðîíû, â ðàìêàõ ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ ñóùåñòâóþò ðàçëè÷íûå ìåòîäû äëÿ âû÷èñëåíèÿ çíà÷åíèé ñëîæíûõ ôîðìóë. À åñëè ðàññìîòðåòü ìîùü è âûðàçèòåëüíîñòü ñîâðåìåííûõ ôóíêöèîíàëüíûõ ÿçûêîâ ïðîãðàììèðîâàíèÿ, òî ñòàíîâèòñÿ î÷åâèäíûì, ÷òî èçó÷àòü íà ïðàêòèêå ðàçëè÷íûå àñïåêòû òåîðèè ÷èñåë ìîæíî ïðè ïîìîùè ïðîãðàììèðîâàíèÿ ôîðìóë íà êàêîì-íèáóäü ôóíêöèîíàëüíîì ÿçûêå.  ýòîì ðàçäåëå â êà÷åñòâå ôóíêöèîíàëüíîãî ÿçûêà ïðîãðàììèðîâàíèÿ, ïðè ïîìîùè êîòîðîãî ìîæíî ðàññìàòðèâàòü òåîðèþ ÷èñåë, ïðåäëàãàåòñÿ èñïîëüçîâàòü ÿçûê Haskell êàê óæå çàðåêîìåíäîâàâøèé ñåáÿ ÿçûê äëÿ èñïîëüçîâàíèÿ â íàóêå è ïðèêëàäíûõ òåõíîëîãèÿõ. Áîëåå òîãî, ÿçûê Haskell èñïîëüçóåòñÿ â êà÷åñòâå ïåðâîãî ÿçûêà ïðîãðàììèðîâàíèÿ â íåêîòîðûõ óíèâåðñèòåòàõ ìèðà, ïîýòîìó åãî ðàññìîòðåíèå äëÿ ðåøåíèÿ çàäà÷ èç òåîðèè ÷èñåë èìååò åù¼ è ïðàêòè÷åñêóþ öåëü íàó÷èòü ÷èòàòåëÿ îáðàùàòüñÿ ñ ýòèì ÿçûêîì åñòåñòâåííûì è ëîâêèì îáðàçîì. Äëÿ ðàáîòû ñ ôóíêöèÿìè, ïðèâåä¼ííûìè â ýòîì ðàçäåëå, íåîáõîäèìî èñïîëüçîâàòü èíòåðïðåòàòîð ÿçûêà Haskell HUGS 98, áåñïëàòíóþ âåðñèþ êîòîðîãî ìîæíî ïîëó÷èòü â ñåòè Èíòåðíåò ïî àäðåñó http://www.haskell.org/hugs/. Âñå ïðèâîäèìûå íèæå ôóíêöèè ïðîòåñòèðîâàíû â ýòîì èíòåðïðåòàòîðå, ïîýòîìó ïðàâèëüíîñòü èõ îïðåäåëåíèÿ ãàðàíòèðóåòñÿ àâòîðîì. Èñïîëüçîâàíèå äðóãèõ òðàíñëÿòîðîâ ÿçûêà Haskell (íàïðèìåð, êîìïèëÿòîðà GHC) òàêæå âîçìîæíî, îäíàêî äëÿ èõ èñïîëüçîâàíèÿ, âåðîÿòíî, ïðèä¼òñÿ âíîñèòü â îïðåäåëåíèÿ ôóíêöèé íåçíà÷èòåëüíûå èçìåíåíèÿ. Ïðåäïîëàãàåòñÿ, ÷òî ÷èòàòåëü çíàêîì ñ áàçîâûì ñèíòàêñèñîì ÿçûêà Haskell, ïîýòîìó äàëåå îáúÿñíåíèå ñèíòàêñèñà ÿçûêà áóäåò ïðîâîäèòüñÿ ìèíèìàëüíûì îáðàçîì.  ñëó÷àå, åñëè ó ÷èòàòåëÿ âîçíèêíóò
82
Òåîðèÿ ÷èñåë è ÿçûê Haskell
çàòðóäíåíèÿ ñ ïîíèìàíèåì ñèíòàêñèñà ÿçûêà èëè ñìûñëà ïðèâîäèìûõ îïðåäåëåíèé, ìîæíî ïîñîâåòîâàòü îáðàòèòüñÿ ê èçäàííûì êíèãàì [6, 7, 8].
Ïðîñòåéøèå çàäà÷è Ïåðåä òåì êàê íà÷àòü ðàññìîòðåíèå êàêèõ-òî ñëîæíûõ âîïðîñîâ òåîðèè ÷èñåë, íåîáõîäèìî ïðîâåñòè ïîäãîòîâèòåëüíóþ ðàáîòó â âèäå ðàçðàáîòêè íåêîòîðûõ âñïîìîãàòåëüíûõ ôóíêöèé, òðåáóåìûõ äëÿ âû÷èñëåíèÿ áîëåå ñëîæíûõ ôîðìóë. Ê òàêèì ôóíêöèÿì îòíîñÿòñÿ â ïåðâóþ î÷åðåäü ôóíêöèè äëÿ íàõîæäåíèÿ íàèáîëüøåãî îáùåãî äåëèòåëÿ (ÍÎÄ) è íàèìåíüøåãî îáùåãî êðàòíîãî (ÍÎÊ). ÍÎÄ äâóõ öåëûõ ÷èñåë m è n ýòî òàêîé îáùèé äåëèòåëü d (òî åñòü: d | m è d | n), êîòîðûé äåëèòñÿ íà ëþáîé äðóãîé îáùèé äåëèòåëü èñõîäíûõ ÷èñåë. ÍÎÄ îïðåäåë¼í, åñëè õîòÿ áû îäíî èç ÷èñåë m èëè n íå íîëü. Îáîçíà÷åíèå (m, n). Äëÿ âû÷èñëåíèÿ ýòîãî ÷èñëà ìîæíî âîñïîëüçîâàòüñÿ ôóíêöèåé gcd (îò àíãëèéñêîãî íàèìåíîâàíèÿ ):
greatest common divisor
gcd : : Integral a => a −> a −> a gcd 0 0 = error " ÍÎÄ îò 0 è 0 íå îïðåäåë¼í . " gcd m n = gcd ' ( abs m ) ( abs n )
where
gcd ' m 0 = n gcd ' m n = gcd ' n ( rem m n )  ýòîì îïðåäåëåíèè èñïîëüçîâàíà ôóíêöèÿ abs, âû÷èñëÿþùàÿ ìîäóëü çàäàííîãî öåëîãî ÷èñëà, à òàêæå ôóíêöèÿ rem, êîòîðàÿ âîçâðàùàåò îñòàòîê îò öåëî÷èñëåííîãî äåëåíèÿ ïåðâîãî àðãóìåíòà íà âòîðîé. Äàííàÿ ôóíêöèÿ ðåàëèçóåò àëãîðèòì Åâêëèäà, êîòîðûé áûë ðàçðàáîòàí çíàìåíèòûì ôèëîñîôîì äëÿ íàõîæäåíèÿ ÍÎÄ åù¼ âî âðåìåíà Äðåâíåé Ãðåöèè. Íåîáõîäèìî íàïîìíèòü, ÷òî ñòðîêà ñ ñèìâîëàìè ( :: ) ÿâëÿåòñÿ îïðåäåëåíèåì òèïà ôóíêöèè, òåëî êîòîðîé îïðåäåëÿåòñÿ â ñëåäóþùåé ñòðîêå. Òî åñòü òàêàÿ ñòðîêà îïðåäåëÿåò ñèãíàòóðó.  íåé èñïîëüçóþòñÿ äâà ñïåöèàëüíûõ ñèìâîëà: (=>) è (−>). Ïåðâûé çàäà¼ò êîíòåêñò èñïîëüçîâàíèÿ ïåðåìåííûõ òèïà â äàëüíåéøåé çàïèñè (â óêàçàííîì ïðèìåðå ïåðåìåííàÿ a).  ôóíêöèè gcd àðãóìåíòû ìîãóò áûòü ëþáîãî òèïà a, ÿâëÿþùåãîñÿ ýêçåìïëÿðîì êëàññà Integral, òî åñòü êëàññîì ÷èñåë, äëÿ êîòîðûõ îïðåäåëåíû îïåðàöèè öåëî÷èñëåííîãî äåëåíèÿ è âçÿòèÿ îñòàòêà îò äåëåíèÿ. Ñòðåëêà (−>) èñïîëüçóåòñÿ äëÿ îïðåäåëåíèÿ òèïà ôóíêöèé. Òàê, ê ïðèìåðó, çàïèñü òèïà ôóíêöèè Integer −> Bool ãëàñèò, ÷òî ôóíêöèÿ ïðèíèìàåò íà âõîä îäèí ïàðàìåòð òèïà Integer, à âîçâðàùàåò ðåçóëüòàò òèïà Bool.  ñâîþ î÷åðåäü, çàïèñü òèïà Integer −> Char −> Bool ãîâîðèò, ÷òî ó ôóíêöèè åñòü äâà àðãóìåíòà: ïåðâûé òèïà Integer, à âòîðîé òèïà Char. Âîçâðàùàåò ôóíêöèÿ çíà÷åíèå òèïà Bool. Ïîäðîáíî î òèïèçàöèè ôóíêöèé, êëàññàõ òèïîâ è ïàðàìåòðè÷åñêèõ ïåðåìåííûõ òèïîâ íàïèñàíî â óïîìÿíóòûõ óæå êíèãàõ ïî ôóíêöèîíàëüíîìó ïðîãðàììèðîâàíèþ. Äåòàëüíîå ðàññìîòðåíèå ýòèõ àñïåêòîâ ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ âûõîäèò çà ðàìêè ðàññìîòðåíèÿ äàííîãî ðàçäåëà. ÍÎÊ äâóõ öåëûõ ÷èñåë m è n ýòî òàêîå íàèìåíüøåå öåëîå ÷èñëî, êîòîðîå äåëèòñÿ íà m è n áåç îñòàòêà. Îáîçíà÷åíèå [m, n]. Äëÿ âû÷èñëåíèÿ ýòîãî ÷èñëà ìîæíî âîñïîëüçîâàòüñÿ ôóíêöèåé lcm (îò àíãëèéñêîãî íàèìåíîâàíèÿ ):
least common multiple
lcm lcm lcm lcm
: : Integral a => a −> a −> a _ 0 = 0 0 _ = 0 m n = abs ( ( quot m ( gcd m n ) ) ∗ n )
Çäåñü òàêæå âñòðå÷àåòñÿ óæå ðàññìîòðåííàÿ ôóíêöèÿ abs, à òàê æå ôóíêöèÿ quot, âîçâðàùàþùàÿ çíà÷åíèå öåëî÷èñëåííîãî äåëåíèÿ ïåðâîãî àðãóìåíòà íà âòîðîé. Êàê âèäíî, ÍÎÊ âû÷èñëÿåòñÿ äîñòàòî÷íî
Òàêèå íåïðîñòûå ïðîñòûå ÷èñëà
83
ïðîñòî íåîáõîäèìî ðàçäåëèòü ïåðâûé àðãóìåíò íà ÍÎÄ äâóõ ÷èñåë, à ïîòîì ðåçóëüòàò äåëåíèÿ óìíîæèòü íà âòîðîé àðãóìåíò. Íàïèñàííûå ôóíêöèè ìîæíî èñïîëüçîâàòü äëÿ ïîñòðîåíèÿ áåñêîíå÷íîãî ñïèñêà âçàèìíî ïðîñòûõ ÷èñåë. Äâà öåëûõ ÷èñëà íàçûâàþòñÿ âçàèìíî ïðîñòûìè, åñëè èõ ÍÎÄ ðàâåí 1. Äëÿ âû÷èñëåíèÿ òàêîãî ñïèñêà ÷èñåë ìîæíî âîñïîëüçîâàòüñÿ ñëåäóþùåé ôóíêöèåé:
reciprocals : : Integral a => [ ( a , a ) ] reciprocals = [ ( m , n ) | m <− [ 1 . . ] , n <− [ 1 . . m ] , gcd m n == 1 ] Êàê âèäíî, ýòî îïðåäåëåíèå ïîëíîñòüþ ñîîòâåòñòâóåò ìàòåìàòè÷åñêîé ôîðìóëå, ïî êîòîðîé ìîæíî áûëî áû âû÷èñëèòü ìíîæåñòâî ïàð âçàèìíî ïðîñòûõ ÷èñåë:
Nreciprocals = {⟨m, n⟩ | m ∈ N, n ∈ N, (m, n) = 1}
(13)
Äàííàÿ ôóíêöèÿ íå î÷åíü èíòåðåñíà ñ òî÷êè çðåíèÿ å¼ ðåàëèçàöèè. Âñ¼ äîâîëüíî òèïè÷íî îïðåäåëèòåëü ñïèñêà ñ äâóìÿ ãåíåðàòîðàìè (âûðàæåíèÿ ñî çíàêîì (<−)) è îäíèì îõðàíÿþùèì âûðàæåíèåì (óñëîâíîå âûðàæåíèå gcd m n == 1). Çäåñü èíòåðåñíî äðóãîå. Âåäü ïðèâåä¼ííîå îïðåäåëåíèå ôóíêöèè, õîòü è ÿâëÿåòñÿ òàêèì ïðîñòûì, íà ñàìîì äåëå ñîäåðæèò äâà ñêðûòûõ âëîæåííûõ öèêëà è îäíó ïðîâåðêó. Öèêëû ñîîòâåòñòâóþò ãåíåðàòîðàì, ïðè ýòîì ïåðâûé öèêë âûïîëíÿåòñÿ îò åäèíèöû äî áåñêîíå÷íîñòè, à âòîðîé îò åäèíèöû äî çíà÷åíèÿ ïåðåìåííîé ïåðâîãî öèêëà. Ýòî âàæíî, òàê êàê åñëè áû â îïðåäåëåíèè ôóíêöèè ñòîÿëè áû äâà îäèíàêîâûõ ãåíåðàòîðà: m <− [1..] è n <− [1..], òî ðåçóëüòàòû ðàáîòû áûëè áû íå òàê èíòåðåñíû ïåðâûé ýëåìåíò ëþáîé ïàðû â ïîëó÷åííîì áåñêîíå÷íîì ñïèñêå âñåãäà áûë áû ðàâåí åäèíèöå. ×èòàòåëþ ïðåäëàãàåòñÿ ñàìîñòîÿòåëüíî ïîäóìàòü, ïî÷åìó ýòî òàê. Íåîáõîäèìî îòìåòèòü, ÷òî ôóíêöèè gcd è lcm îïðåäåëåíû â ñòàíäàðòíîì ìîäóëå Prelude, ïîýòîìó èõ îïðåäåëåíèå çäåñü ïðèâåäåíî èñêëþ÷èòåëüíî â ïîçíàâàòåëüíûõ öåëÿõ. Ïðè ðàçðàáîòêå ñîáñòâåííûõ ïðîãðàìì ýòè ôóíêöèè ìîæíî èñïîëüçîâàòü íåïîñðåäñòâåííî áåç äîïîëíèòåëüíîãî îïðåäåëåíèÿ. Îäíèì èç ñàìûõ êëþ÷åâûõ ïîíÿòèé òåîðèè ÷èñåë ÿâëÿåòñÿ ïîíÿòèå äåëèòåëÿ. Î÷åíü ìíîãèå öåëî÷èñëåííûå ïîñëåäîâàòåëüíîñòè, â òîì ÷èñëå è òå, êîòîðûå áóäóò ðàññìîòðåíû äàëåå, îïðåäåëÿþòñÿ ÷åðåç äåëèòåëè. Ïîýòîìó áûëî áû èíòåðåñíî èìåòü ôóíêöèþ äëÿ ïîëó÷åíèÿ ñïèñêà äåëèòåëåé çàäàííîãî ÷èñëà. Ïóñòü òàêàÿ ôóíêöèÿ íàçûâàåòñÿ divisors:
divisors : : Integral a => a −> [ a ] divisors n = [ x | x <− [ 1 . . ( n − 1 ) ] , rem n x == 0 ] Íåîáõîäèìî îòìåòèòü, ÷òî äàííàÿ ôóíêöèÿ âîçâðàùàåò ñïèñîê òàê íàçûâàåìûõ ñîáñòâåííûõ äåëèòåëåé ÷èñëà n, òî åñòü òàêèõ, êîòîðûå ñòðîãî ìåíüøå ñàìîãî ÷èñëà n. Òàêèì îáðàçîì, â ðåçóëüòàò ýòîé ôóíêöèè íå âõîäèò ñàìî ÷èñëî n ýòî ñâîéñòâî áóäåò èñïîëüçîâàòüñÿ â íåêîòîðûõ ñëó÷àÿõ â ïîñëåäóþùèõ îïðåäåëåíèÿõ ôóíêöèé.
Òàêèå íåïðîñòûå ïðîñòûå ÷èñëà Î÷åíü øèðîêóþ èçâåñòíîñòü â ðàìêàõ òåîðèè ÷èñåë èìåþò ïðîñòûå ÷èñëà, òî åñòü òàêèå, â ñïèñêå ñîáñòâåííûõ äåëèòåëåé êîòîðûõ íàõîäèòñÿ òîëüêî îäèí äåëèòåëü 1. Òàêèå ÷èñëà íàøëè ñàìîå øèðîêîå ïðèìåíåíèå âî ìíîãèõ ïðèêëàäíûõ îáëàñòÿõ, â òîì ÷èñëå è â ñîâðåìåííûõ ìåòîäàõ è àëãîðèòìàõ øèôðîâàíèÿ èíôîðìàöèè. Êðîìå òîãî, ïðîñòûå ÷èñëà óñïåøíî èñïîëüçóþòñÿ â õåøòàáëèöàõ è äëÿ ãåíåðàöèè ïñåâäîñëó÷àéíûõ ÷èñåë. Ê ñîæàëåíèþ, â ìàòåìàòèêå íå ïðèäóìàíî ïðîñòîé ôîðìóëû äëÿ íàõîæäåíèÿ çàäàííîãî ïî ïîðÿäêó ïðîñòîãî ÷èñëà, ïîýòîìó ïîñòðîåíèå ñïèñêà ïðîñòûõ ÷èñåë äåëàåòñÿ ïåðåáîðîì ñ ïðèìåíåíèåì
84
Òåîðèÿ ÷èñåë è ÿçûê Haskell
âñåâîçìîæíûõ ýâðèñòè÷åñêèõ ïðàâèë ïðîâåðêè íà ïðîñòîòó. Ê ìíîæåñòâó òàêèõ ïðàâèë îòíîñèòñÿ, ê ïðèìåðó, ðåøåòî Ýðàòîñôåíà àëãîðèòì íàõîæäåíèÿ ïðè ïîìîùè ïåðåáîðà âñåõ ïðîñòûõ ÷èñåë äî íåêîòîðîãî çàäàííîãî n. Ïðîùå âñåãî íàõîäèòü ïðîñòûå ÷èñëà ïåðåáîðîì:
primes = [ n | n <− [ 1 . . ] , isPrime n ]
where
isPrime x = ( divisors x == [ 1 ] ) Îäíàêî äàííûé àëãîðèòì âåñüìà íåñîâåðøåíåí. Íåçà÷åì ïåðåáèðàòü âñå ÷èñëà, òåì áîëåå ÷òî èç ÷¼òíûõ ÷èñåë òîëüêî ÷èñëî 2 ÿâëÿåòñÿ ïðîñòûì. Îäíàêî äàëåå ïîëó÷àåòñÿ, ÷òî è âñå ÷èñëà, êðàòíûå òð¼ì, íå ÿâëÿþòñÿ ïðîñòûìè, à òàì è êðàòíûå ïÿòè òîæå è ò. ä. Òàê è ïîÿâèëîñü ðåøåòî Ýðàòîñôåíà õîðîøî áû áûëî åãî âíåäðèòü äëÿ ïîñòðîåíèÿ áåñêîíå÷íîãî ñïèñêà ïðîñòûõ ÷èñåë. ×èòàòåëþ ïðåäëàãàåòñÿ ñàìîñòîÿòåëüíî ïîäóìàòü íàä ýòîé ïðîáëåìîé. Îïèñàííàÿ ôóíêöèÿ primes âïîëíå ïîäõîäèò äëÿ ðåøåíèÿ ìíîãèõ çàäà÷ â ðàìêàõ òåîðèè ÷èñåë. Õîòÿ îíà ðàáîòàåò äîëãî, íî çàòî âïîëíå íàä¼æíî, âû÷èñëÿÿ äåéñòâèòåëüíî áåñêîíå÷íûé ñïèñîê ïðîñòûõ ÷èñåë. ×òîáû ïîëó÷èòü îãðàíè÷åííûé ñïèñîê ïðîñòûõ ÷èñåë, íå ïðåâûøàþùèõ çàäàííîãî n, íåîáõîäèìî âîñïîëüçîâàòüñÿ ñòàíäàðòíîé ôóíêöèåé take, êîòîðàÿ âîçâðàùàåò çàäàííîå êîëè÷åñòâî ýëåìåíòîâ ñ íà÷àëà ñïèñêà (íàïðèìåð, take 1000 primes âåðí¼ò ñïèñîê èç òûñÿ÷è ïåðâûõ ïðîñòûõ ÷èñåë). À äëÿ òîãî ÷òîáû ïîëó÷èòü îïðåäåë¼ííîå ïðîñòîå ÷èñëî, ìîæíî âîñïîëüçîâàòüñÿ ôóíêöèåé ( !! ), âîçâðàùàþùåé çàäàííûé ýëåìåíò ñïèñêà: primes !! 1000 âåðí¼ò òûñÿ÷íîå ïðîñòîå ÷èñëî. Âñåì âûøåïåðå÷èñëåííûì ìîæíî âîñïîëüçîâàòüñÿ äëÿ òîãî, ÷òîáû íàïèñàòü ôóíêöèþ, âîçâðàùàþùóþ ðàçëîæåíèå çàäàííîãî íàòóðàëüíîãî ÷èñëà íà ïðîñòûå äåëèòåëè. Ïî îñíîâíîé òåîðåìå àðèôìåòèêè òàêîå ðàçëîæåíèå ñóùåñòâóåò, è îíî åäèíñòâåííîå (ñ òî÷íîñòüþ äî ïîðÿäêà ñëåäîâàíèÿ ïðîñòûõ äåëèòåëåé). Òàêîå ïðåäñòàâëåíèå íàòóðàëüíîãî ÷èñëà â âèäå ïðîèçâåäåíèÿ ïðîñòûõ íàçûâàåòñÿ ôàêòîðèçàöèåé. Íà íàñòîÿùèé ìîìåíò íåèçâåñòíî êàêèõ-ëèáî àëãîðèòìîâ ôàêòîðèçàöèè ÷èñåë ñ ïîëèíîìèàëüíîé ñëîæíîñòüþ, õîòÿ è íå äîêàçàíî, ÷òî òàêîâûõ àëãîðèòìîâ íåò. Íà ãèïîòåçå î òîì, ÷òî ôàêòîðèçîâàòü ïðîèçâîëüíîå ÷èñëî íå òàê ïðîñòî, îñíîâàí àëãîðèòì øèôðîâàíèÿ ñ îòêðûòûì êëþ÷îì RSA. Òàêèì îáðàçîì, ôóíêöèÿ äëÿ ôàêòîðèçàöèè çàäàííîãî ÷èñëà õîòÿ è áóäåò âåñüìà íåîïòèìèçèðîâàííîé, íî, òåì íå ìåíåå, âïîëíå áóäåò ðàáîòàòü. Îñîáåííî äëÿ íåñëîæíûõ ñîñòàâíûõ ÷èñåë, êîòîðûå ðàâíû ïðîèçâåäåíèþ ïðåèìóùåñòâåííî ìàëåíüêèõ ïðîñòûõ ÷èñåë. ż îïðåäåëåíèå âûãëÿäèò òàê:
expansion : : Integer −> [ Integer ] expansion 1 = [ ] expansion n = x : expansion ( quot n x )
where
primesBN = takeWhile (<= n ) primes x = head [ y | y <− primesBN , mod n y == 0 ] Äàííàÿ ôóíêöèÿ áóäåò ðàáîòàòü ìåäëåííåå äëÿ ÷èñåë, êîòîðûå ðàñêëàäûâàþòñÿ íà áîëüøèå ïðîñòûå ÷èñëà. Òàê, ê ïðèìåðó, ÷èñëî 1 000 000 (ìèëëèîí) ðàñêëàäûâàåòñÿ íà ïðîñòûå ìíîæèòåëè çà äîëè ñåêóíäû ( [2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5]), à âîò ñëåäóþùåå çà íèì ÷èñëî 1 000 001 (ìèëëèîí îäèí) ôàêòîðèçóåòñÿ ïðèìåðíî çà ïîëìèíóòû ([101, 9~901]). ×èòàòåëþ ïðåäëàãàåòñÿ ñàìîñòîÿòåëüíî èçó÷èòü çàâèñèìîñòü âðåìåíè èñïîëíåíèÿ ïðèâåä¼ííîãî àëãîðèòìà ôàêòîðèçàöèè îò âåëè÷èíû àðãóìåíòà. Äîêàçàíî, ÷òî ðÿä ïðîñòûõ ÷èñåë áåñêîíå÷åí. Îäíàêî ñðåäè âñåõ òàêèõ ÷èñåë èìåþòñÿ òàê íàçûâàåìûå ÷èñëà-áëèçíåöû, òî åñòü òàêèå, êîòîðûå îòëè÷àþòñÿ äðóã îò äðóãà íà 2. Íåèçâåñòíî, ñêîëüêî òàêèõ ïàð è áåñêîíå÷íî ëè èõ êîëè÷åñòâî âîîáùå. Ïðîñòåéøåå îïèñàíèå ôóíêöèè, âû÷èñëÿþùåé òàêèå ÷èñëà, âûãëÿäèò ñëåäóþùèì îáðàçîì:
twins : : [ ( Integer , Integer ) ]
Òàêèå íåïðîñòûå ïðîñòûå ÷èñëà
85
twins = [ ( p , p + 2 ) | p <− primes , isPrime ( p + 2 ) ] Êðîìå ÷èñåë-áëèçíåöîâ, ìîæíî ââîäèòü ðÿäû ïàð ïðîñòûõ ÷èñåë, îòëè÷àþùèõñÿ äðóã îò äðóãà íà 4, íà 6 è ò. ä. Òàêèå ðÿäû èìåþò îáîáù¼ííîå íàèìåíîâàíèå ðîäñòâåííûõ ïðîñòûõ ÷èñåë. Äëÿ ïîèñêà ïàð ðîäñòâåííûõ ÷èñåë ìîæíî íàïèñàòü ôóíêöèþ, ïàðàìåòðèçóåìóþ ðàçíèöåé, êîòîðàÿ äîëæíà áûòü ìåæäó ðîäñòâåííûìè ÷èñëàìè. Îïðåäåëåíèå òàêîé ôóíêöèè ìîæåò âûãëÿäåòü òàê:
kins : : Integer −> [ ( Integer , Integer ) ] kins n = [ ( p , p + n ) | p <− primes , isPrime ( p + n ) ]  ýòîì ñëó÷àå îïðåäåëåíèå ôóíêöèè äëÿ ïîèñêà ïðîñòûõ ÷èñåë-áëèçíåöîâ âûãëÿäèò î÷åíü ïðîñòî:
twins : : [ ( Integer , Integer ) ] twins = kins 2 Îäíàêî, íåñìîòðÿ íà âñþ êàæóùóþñÿ ïðîñòîòó ïðîñòûõ ÷èñåë, ìàòåìàòèêè î÷åíü ëþáÿò èõ. È â ñâÿçè ñ ýòèì ïîñòîÿííî èùóò ðàçëè÷íûå ñâîéñòâà, êîòîðûå õàðàêòåðèçóþò ïðîñòûå ÷èñëà. Áîëåå òîãî, äëÿ íåêîòîðûõ öåëåé âûäåëÿþòñÿ îñîáûå ïðîñòûå ÷èñëà, êîòîðûå ïîëó÷àþò ñâîè ñîáñòâåííûå èìåíà, ÷àñòî ïî èìåíè ñâîåãî ïåðâîîòêðûâàòåëÿ. Ó âñåõ òàêèõ ïîäìíîæåñòâ ïðîñòûõ ÷èñåë èìåþòñÿ ñîáñòâåííûå îáëàñòè ïðèìåíåíèÿ.
×èñëà Ìåðñåííà Òàê, ê ïðèìåðó, â XVII âåêå ôðàíöóçñêèé ìàòåìàòèê Ì. Ìåðñåíí îïðåäåëèë ïîñëåäîâàòåëüíîñòü ÷èñåë âèäà:
Mn = 2n − 1
(14)
Ýòà ïîñëåäîâàòåëüíîñòü ïîëó÷èëà íàèìåíîâàíèå ¾÷èñåë Ìåðñåííà¿. Ñàìà ïî ñåáå îíà íå òàê èíòåðåñíà, íî â íåé ñóùåñòâóþò òàê íàçûâàåìûå ïðîñòûå ÷èñëà Ìåðñåííà, êîòîðûå ïîëó÷èëè ñâîþ èçâåñòíîñòü â ñâÿçè ñ ýôôåêòèâíûì êðèòåðèåì ïðîñòîòû Ëþêà Ëåìåðà, áëàãîäàðÿ êîòîðîìó ïðîñòûå ÷èñëà Ìåðñåííà äàâíî óäåðæèâàþò ëèäåðñòâî êàê ñàìûå áîëüøèå èçâåñòíûå ïðîñòûå ÷èñëà. Íà äàííûé ìîìåíò ñàìûì áîëüøèì èçâåñòíûì ïðîñòûì ÷èñëîì ÿâëÿåòñÿ ÷èñëî Ìåðñåííà M30402457 = 230402457 − 1, íàéäåííîå â äåêàáðå 2005 ãîäà. Îíî ñîäåðæèò 9 152 052 äåñÿòè÷íûå öèôðû. Ýôôåêòèâíûé òåñò ïðîñòîòû (òåñò Ëþêà Ëåìåðà) äëÿ ÷èñåë Ìåðñåííà áûë ïðåäëîæåí â 1878 ãîäó è áàçèðóåòñÿ íà òîì íàáëþäåíèè, ÷òî ïðîñòîòà ÷èñëà Ìåðñåííà Mp = 2p − 1 âëå÷¼ò ïðîñòîòó åãî èíäåêñà p, à òàêæå íà ñëåäóþùåì óòâåðæäåíèè: ¾äëÿ ïðîñòîãî p ÷èñëî Mp ÿâëÿåòñÿ ïðîñòûì òîãäà è òîëüêî òîãäà, êîãäà îíî äåëèò ÷èñëî Lp−1 , ãäå ÷èñëà Lk îïðåäåëÿþòñÿ ðåêóððåíòíûì ñîîòíîøåíèåì L1 = 4, Lk+1 = L2k − 2¿. Äëÿ óñòàíîâëåíèÿ ïðîñòîòû Mp ïîñëåäîâàòåëüíîñòü ÷èñåë L1 , L2 , . . . , Lp−1 äîñòàòî÷íî âû÷èñëÿòü ïî ìîäóëþ ÷èñëà Mp (òî åñòü âû÷èñëÿòü íå ñàìè ÷èñëà Lk , äëèíà êîòîðûõ ðàñò¼ò ýêñïîíåíöèàëüíî, à îñòàòêè îò äåëåíèÿ Lk íà Mp , äëèíà êîòîðûõ îãðàíè÷åíà p áèòàìè). Ïîñëåäíåå ÷èñëî â ýòîé ïîñëåäîâàòåëüíîñòè Lp−1 mod Mp íàçûâàåòñÿ âû÷åòîì Ëþêà Ëåìåðà. Òàêèì îáðàçîì, ÷èñëî Ìåðñåííà ÿâëÿåòñÿ ïðîñòûì òîãäà è òîëüêî òîãäà, êîãäà ÷èñëî p ïðîñòîå è âû÷åò Ëþêà Ëåìåðà ðàâåí íóëþ. Äëÿ âû÷èñëåíèÿ ïîñëåäîâàòåëüíîñòè ïðîñòûõ ÷èñåë Ìåðñåííà ìîæíî âîñïîëüçîâàòüñÿ ñëåäóþùèìè íåñëîæíûìè ôóíêöèÿìè (íåîáõîäèìî â î÷åðåäíîé ðàç çàìåòèòü, ÷òî äàííûå îïðåäåëåíèÿ âåñüìà äàëåêè îò îïòèìèçèðîâàííîãî âàðèàíòà îíè ëèøü ïîêàçûâàþò, íàñêîëüêî îïðåäåëåíèÿ ôóíêöèé íà ÿçûêå Haskell ïîõîæè íà ìàòåìàòè÷åñêèå ôîðìóëû):
lucas : : ( Num a , Num b ) => b −> a lucas 1 = 4 lucas n = ( lucas ( n − 1 ) ) ^ 2 − 2
86
Òåîðèÿ ÷èñåë è ÿçûê Haskell
mersenne : : [ Integer ] mersenne = [ m p | p <− primes , rem ( lucas ( p − 1 ) ) ( m p ) == 0 ]
where
m p = 2^ p − 1 Ïðè ïîìîùè ôóíêöèè mersenne âî âðåìÿ íàïèñàíèÿ äàííîãî ïîäðàçäåëà âû÷èñëåíû ïåðâûå ñåìü ïðîñòûõ ÷èñåë Ìåðñåííà: [7, 31, 127, 8 191, 131 071, 524 287, 2 147 483 647].
×èñëà Ôåðìà Ýêñöåíòðè÷íûé ó÷¼íûé Ï. Ôåðìà, ïðèäóìàâøèé ìàëóþ è áîëüøóþ7 òåîðåìû ñâîåãî èìåíè, êîòîðûå äîëãîå âðåìÿ ìó÷èëè ìàòåìàòèêîâ (à áîëüøàÿ è âîâñå äî ïîñëåäíåãî âðåìåíè íå áûëà äîêàçàíà), òàêæå èíòåðåñîâàëñÿ ïðîñòûìè ÷èñëàìè, â ñâÿçè ñ ÷åì ïûòàëñÿ ðàçðàáîòàòü ôîðìóëó, ïðè ïîìîùè êîòîðîé ìîæíî áûëî áû îíûå ÷èñëà âû÷èñëÿòü. Ïîñëå íåêîòîðûõ óñèëèé îí ïîëó÷èë òàêîå ñîîòíîøåíèå: n
Fn = 2 2 + 1
(15)
Ñàì Ï. Ôåðìà ñìîã ïðîâåðèòü ïðîñòîòó ÷èñåë èç äàííîé ïîñëåäîâàòåëüíîñòè òîëüêî äî n = 4. Äàëåå îí ïðîñòî ïðåäïîëîæèë, ÷òî îñòàëüíûå ÷èñëà èç ýòîãî ðÿäà òîæå ïðîñòûå. Îäíàêî â 1732 ãîäó Ë. Ýéëåð íàø¼ë ðàçëîæåíèå ÷èñëà F5 . Íà ñåãîäíÿøíèé äåíü èçâåñòíî, ÷òî âñå ÷èñëà Ôåðìà äëÿ 5 ≤ n ≤ 32 ÿâëÿþòñÿ ñîñòàâíûìè. Áîëüøèå ÷èñëà èç ýòîãî ðÿäà íà ïðîñòîòó ïîêà íå ïðîâåðåíû. Äëÿ ïðîâåðêè ïðîñòîòû ÷èñåë Ôåðìà èñïîëüçóåòñÿ òåñò Ïåïèíà, ÿâëÿþùèéñÿ ïîëèíîìèàëüíûì. Äàííûé òåñò óòâåðæäàåò, ÷òî ÷èñëî Ôåðìà Fn ÿâëÿåòñÿ ïðîñòûì òîãäà è òîëüêî òîãäà, êîãäà Fn −1 3 2 ≡ −1 ( mod Fn ). ×èòàòåëþ ðåêîìåíäóåòñÿ ñàìîñòîÿòåëüíî ðåàëèçîâàòü ôóíêöèþ èëè íàáîð ôóíêöèé äëÿ îñóùåñòâëåíèÿ òåñòà Ïåïèíà äëÿ ïðîñòûõ ÷èñåë Ôåðìà.
×èñëà Ñîôè Æåðìåí Ñîôè Æåðìåí äîêàçàëà áîëüøóþ òåîðåìó Ôåðìà äëÿ ïîêàçàòåëåé n, ÿâëÿþùèõñÿ ïðîñòûìè ÷èñëàìè p, òàêèìè, ÷òî ÷èñëà 2p + 1 òàêæå ïðîñòûå. Òåì ñàìûì ïîäìíîæåñòâî òàêèõ ïðîñòûõ ÷èñåë ïîëó÷èëî íàèìåíîâàíèå ÷èñåë Ñîôè Æåðìåí. Íåèçâåñòíî, ÿâëÿåòñÿ ëè ýòà ïîñëåäîâàòåëüíîñòü áåñêîíå÷íîé, õîòÿ ïðåäïîëàãàåòñÿ, ÷òî ýòî òàê. Äëÿ âû÷èñëåíèÿ ïàð ÷èñåë Ñîôè Æåðìåí ìîæíî âîñïîëüçîâàòüñÿ ñëåäóþùåé ôóíêöèåé:
germain : : [ ( Integer , Integer ) ] germain = [ ( p , 2 ∗ p + 1 ) | p <− primes , isPrime ( 2 ∗ p + 1 ) ]
Äðóãèå ïîñëåäîâàòåëüíîñòè ïðîñòûõ ÷èñåë Ñóùåñòâóåò åù¼ áîëüøîå êîëè÷åñòâî ðàçëè÷íûõ ïîäìíîæåñòâ ïðîñòûõ ÷èñåë, êîòîðûå èñïîëüçóþòñÿ êàê äëÿ ðàçâëå÷åíèÿ, òàê è äëÿ íåêîòîðûõ ïðèêëàäíûõ àñïåêòîâ íàóêè è òåõíèêè. Òàê, ê ïðèìåðó, âûâåäåíû ôîðìóëû äëÿ ïðîñòûõ ÷èñåë èìåíè Âèëüñîíà (íà ñåãîäíÿøíèé äåíü èçâåñòíû òðè òàêèõ ÷èñëà) è èìåíè Âîëüñòåíõîëüìà (èçâåñòíû äâà òàêèõ ÷èñëà).  àíãëîÿçû÷íûõ ìàòåìàòè÷åñêèõ ñïðàâî÷íèêàõ ââîäèòñÿ äî øåñòèäåñÿòè ðàçëè÷íûõ òèïîâ ïðîñòûõ ÷èñåë, ìíîãèå èç êîòîðûõ èñïîëüçóþòñÿ â äîêàçàòåëüñòâàõ òåõ èëè èíûõ òåîðåì.
Äàííàÿ òåîðåìà óòâåðæäàåò, ÷òî äëÿ ëþáîãî öåëîãî n > 2 óðàâíåíèå an + bn = cn íå èìååò ïîëîæèòåëüíûõ öåëûõ ðåøåíèé a, b è c. Ñàì Ï. Ôåðìà äîêàçàë òåîðåìó äëÿ n = 4, çàòåì Ë. Ýéëåð äîêàçàë å¼ äëÿ n = 3, à ïîçæå È. Äèðèõëå ïðèâ¼ë äîêàçàòåëüñòâî äëÿ n = 5. Îêîí÷àòåëüíî äîêàçàëè òåîðåìó òîëüêî â 1994 ãîäó äëÿ ëþáîãî n. 7
Ñîâåðøåíñòâó íåò ïðåäåëà
87
Îñîáûé èíòåðåñ ó ó÷¼íûõ, çàíèìàþùèõñÿ òåîðèåé ÷èñåë, âûçûâàþò òàê íàçûâàåìûå ôàêòîðèàëüíûå ïðîñòûå ÷èñëà. Ôàêòîðèàëüíûì íàçûâàåòñÿ òàêîå ïðîñòîå ÷èñëî, êîòîðîå îòëè÷àåòñÿ íà åäèíèöó â òó èëè èíóþ ñòîðîíó îò ôàêòîðèàëà íåêîòîðîãî íàòóðàëüíîãî ÷èñëà: n! ± 1. Ýòè ÷èñëà èíòåðåñíû òåì, ÷òî ñèãíàëèçèðóþò ñâîèì ïðèñóòñòâèåì î íà÷àëå èëè êîíöå äëèííîé ïîñëåäîâàòåëüíîñòè ñîñòàâíûõ ÷èñåë. Äëÿ ïîëó÷åíèÿ áåñêîíå÷íîãî ñïèñêà òàêèõ ïðîñòûõ ÷èñåë ìîæíî âîñïîëüçîâàòüñÿ ñëåäóþùèìè ôóíêöèÿìè:
fact : : ( Num a , Enum a ) => a −> a fact n = product [ 1 . . n ] fp : : [ Integer ] fp = [ p | n <− test , p <− n , isPrime p ]
where
test = [ [ x − 1, x +1] | x <− map fact [ 1 . . ] ] Ôóíêöèÿ product èç ñòàíäàðòíîãî ìîäóëÿ Prelude âîçâðàùàåò ïðîèçâåäåíèå ýëåìåíòîâ ïåðåäàííîãî åé â êà÷åñòâå àðãóìåíòà ñïèñêà. Ñ äðóãîé ñòîðîíû, ïðîñòûå ÷èñëà ìîæíî èñïîëüçîâàòü è äëÿ ðàçâëå÷åíèÿ. Íàïðèìåð, â ðÿäó ïðîñòûõ ÷èñåë ìîæíî èñêàòü òàêèå, êîòîðûå ÷èòàþòñÿ îäèíàêîâî â îáå ñòîðîíû (â äåñÿòè÷íîé ñèñòåìå ñ÷èñëåíèÿ) ÷èñëà-ïàëèíäðîìû. Òàêèå ïàëèíäðîìû ìîæíî òàêæå èñêàòü è ñðåäè ïðîñòûõ ÷èñåë â ðàçëè÷íûõ ñèñòåìàõ ñ÷èñëåíèÿ. ×èòàòåëþ ïðåäëàãàåòñÿ ñàìîñòîÿòåëüíî ðàçðàáîòàòü ôóíêöèþ äëÿ ïðîâåðêè òîãî, ÷òî çàäàííîå ÷èñëî ÿâëÿåòñÿ ïàëèíäðîìîì, è ðåàëèçîâàòü áåñêîíå÷íûé ñïèñîê ïðîñòûõ ÷èñåë-ïàëèíäðîìîâ.
Ñîâåðøåíñòâó íåò ïðåäåëà Äðóãèì øèðîêèì êëàññîì ÷èñåë, ëþáèìûõ â òåîðèè ÷èñåë, ÿâëÿþòñÿ òàê íàçûâàåìûå ñîâåðøåííûå ÷èñëà, êîòîðûå ðàâíû ñóììå âñåõ ñâîèõ ñîáñòâåííûõ äåëèòåëåé. Ñîâåðøåííûõ ÷èñåë î÷åíü ìàëî.  íàòóðàëüíîì ðÿäó äî îäíîãî ìèëëèîíà âñòðå÷àþòñÿ òîëüêî ÷åòûðå òàêèõ ÷èñëà, à äî òðèëëèîíà âñåãî øåñòü. Ïðîùå âñåãî èñêàòü òàêèå ÷èñëà ïðè ïîìîùè ñëåäóþùåé ôóíêöèè:
perfects : : [ Integer ] perfects = [ n | n <− [ 1 . . ] , sum ( divisors n ) == n ] Ôóíêöèÿ sum èç ñòàíäàðòíîãî ìîäóëÿ Prelude âîçâðàùàåò ñóììó ýëåìåíòîâ ïåðåäàííîãî åé â êà÷åñòâå àðãóìåíòà ñïèñêà. Îäíàêî äàííîå îïðåäåëåíèå âåñüìà íåñîâåðøåííî. Åñëè îáðàòèòüñÿ ê òåîðèè ÷èñåë, òî â íåé ìîæíî íàéòè äîêàçàòåëüñòâî òîãî, ÷òî ÷¼òíûå ñîâåðøåííûå ÷èñëà è ÷èñëà Ìåðñåííà, ðàññìîòðåííûå â ïðåäûäóùåì ïîäðàçäåëå, ñâÿçàíû äðóã ñ äðóãîì ïðîñòûì ñîîòíîøåíèåì:
Pp = 2p−1 ∗ (2p − 1),
(16)
ãäå ÷èñëî 2p − 1 ÿâëÿåòñÿ ïðîñòûì (÷èñëîì Ìåðñåííà). Òàêèì îáðàçîì, êàæäîìó ÷¼òíîìó ñîâåðøåííîìó ÷èñëó ñîîòâåòñòâóåò ÷èñëî Ìåðñåííà, è íàîáîðîò. Ýòî ñîîòíîøåíèå íàø¼ë åù¼ äðåâíåãðå÷åñêèé ìàòåìàòèê Åâêëèä, à ñòðîãî äîêàçàë Ë. Ýéëåð. Îäíàêî íå äîêàçàíî, ñóùåñòâóþò ëè íå÷¼òíûå ñîâåðøåííûå ÷èñëà, ïîòîìó äàííîå ñîîòíîøåíèå íåîáõîäèìî èñïîëüçîâàòü ñ îñòîðîæíîñòüþ. Èçâåñòíî ëèøü, ÷òî åñëè íå÷¼òíîå ñîâåðøåííîå ÷èñëî ñóùåñòâóåò, òî îíî äîëæíî ïðåâûøàòü 10300 . Èñïîëüçóÿ óêàçàííîå ñîîòíîøåíèå, ìîæíî ðåàëèçîâàòü ôóíêöèþ, âû÷èñëÿþùóþ ñîâåðøåííûå ÷èñëà íå ìåäëåííûì ïåðåáîðîì, à äîñòàòî÷íî áûñòðî:
88
Òåîðèÿ ÷èñåë è ÿçûê Haskell
perfects : : [ Integer ] perfects = [ p n | n <− primes , isPrime ( m n ) ]
where
p n = 2^( n − 1 ) ∗ ( m n ) m n = 2^ n − 1 Äîïîëíèòåëüíî ïðîâåðèòü ïîëó÷àåìûå ÷èñëà ìîæíî ïðè ïîìîùè ïðåäèêàòà isPerfect:
isPerfect : : Integral a => a −> Bool isPerfect n = sum ( divisors n ) == n Îäíàêî ìàòåìàòèêè íå îñòàíîâèëèñü íà òàêîé ôîðìóëèðîâêå.  îáèõîä áûëî ââåäåíî ïîíÿòèå äðóæåñòâåííûõ ÷èñåë, êîòîðûå ñâÿçàíû äðóã ñ äðóãîì òàêèì ñîîòíîøåíèåì, ïðè êîòîðîì ïåðâîå ÷èñëî â ïàðå ðàâíî ñóììå ñîáñòâåííûõ äåëèòåëåé âòîðîãî ÷èñëà, à âòîðîå ñóììå ñîáñòâåííûõ äåëèòåëåé ïåðâîãî ñîîòâåòñòâåííî. Òàêèì îáðàçîì, ñîâåðøåííûå ÷èñëà ÿâëÿþòñÿ äðóæåñòâåííûìè ïî îòíîøåíèþ ñàìè ê ñåáå. Ñïèñîê ïàð äðóæåñòâåííûõ ÷èñåë ìîæíî ïîëó÷èòü ïðè ïîìîùè ñëåäóþùåé ôóíêöèè:
friends : : [ ( Integer , Integer ) ] friends = [ ( m , n ) | m <− [ 1 . . ] , n <− [ 1 . . ( m − 1 ) ] , sum ( divisors m ) == n , sum ( divisors n ) == m ] Êàê óæå óïîìèíàëîñü, ñîâåðøåííûå ÷èñëà î÷åíü ðåäêè. Äëÿ òîãî ÷òîáû ïîëå äëÿ èññëåäîâàíèé â ýòîì íàïðàâëåíèè áûëî íåìíîãî øèðå, ìàòåìàòèêè ââåëè íåêîòîðûå äîïîëíèòåëüíûå îïðåäåëåíèÿ öåëî÷èñëåííûõ ïîñëåäîâàòåëüíîñòåé: íåäîñòàòî÷íîå ÷èñëî è èçáûòî÷íîå ÷èñëî. Ê íåäîñòàòî÷íûì îòíîñÿòñÿ òàêèå íàòóðàëüíûå ÷èñëà, ñóììà ñîáñòâåííûõ äåëèòåëåé êîòîðûõ ìåíüøå ñàìîãî ÷èñëà. Ñîîòâåòñòâåííî, ê èçáûòî÷íûì îòíîñÿòñÿ ÷èñëà, ñóììà ñîáñòâåííûõ äåëèòåëåé êîòîðûõ áîëüøå ñàìîãî ÷èñëà. Òàêèì îáðàçîì, âåñü êëàññ íàòóðàëüíûõ ÷èñåë ìîæåò áûòü ðàçä¼ëåí íà òðè íåïåðåñåêàþùèõñÿ ïîäìíîæåñòâà íåäîñòàòî÷íûõ, ñîâåðøåííûõ è èçáûòî÷íûõ ÷èñåë. À êàæäîå íàòóðàëüíîå ÷èñëî, â ñâîþ î÷åðåäü, íàõîäèòñÿ â îäíîì èç ýòèõ òð¼õ ïîäìíîæåñòâ. Íî è ýòîãî àäåïòàì ìàòåìàòèêè ïîêàçàëîñü ìàëî. Áûëè ââåäåíû ñëåãêà íåäîñòàòî÷íûå è ñëåãêà èçáûòî÷íûå ÷èñëà. Òàêèå ÷èñëà îòëè÷àþòñÿ îò ñîâåðøåííûõ â òó èëè èíóþ ñòîðîíó ðîâíî íà åäèíèöó. Îäíàêî ïðè îïðåäåëåíèè ïîäîáíûõ ìíîæåñòâ ìàòåìàòèêîâ æäàëî íåêîòîðîå ðàçî÷àðîâàíèå. Åñëè èñïîëüçîâàòü ñëåäóþùèå ôóíêöèè äëÿ ïîèñêà òàêèõ ÷èñåë:
imperfects : : [ Integer ] imperfects = [ n | n <− [ 1 . . ] , sum ( divisors n ) == n − 1 ] excesses : : [ Integer ] excesses = [ n | n <− [ 1 . . ] , sum ( divisors n ) == n + 1 ] òî áóäåò ÿñíî, ÷òî ïåðâàÿ ôóíêöèÿ âîçâðàùàåò ñïèñîê ñòåïåíåé ÷èñëà 2, à âòîðàÿ ôóíêöèÿ íå âûäà¼ò âîîáùå íèêàêîãî ðåçóëüòàòà. Òàê è ïîëó÷èëîñü â ìàòåìàòèêå äî ñèõ ïîð íåèçâåñòíî, ñóùåñòâóþò ëè èíûå ñëåãêà íåäîñòàòî÷íûå ÷èñëà, êðîìå ñòåïåíåé äâîéêè, à òàêæå ñóùåñòâóþò ëè â ïðèíöèïå ñëåãêà èçáûòî÷íûå ÷èñëà. ×èòàòåëþ ðåêîìåíäóåòñÿ ñàìîñòîÿòåëüíî ðàçðàáîòàòü ôóíêöèè äëÿ ãåíåðàöèè áåñêîíå÷íûõ ñïèñêîâ íåäîñòàòî÷íûõ è èçáûòî÷íûõ ÷èñåë, à òàêæå ðàçðàáîòàòü ôóíêöèþ âûñøåãî ïîðÿäêà, ïðè ïîìîùè êîòîðîé ìîæíî ïîëó÷èòü âñå ïÿòü ïåðå÷èñëåííûõ êëàññîâ íàòóðàëüíûõ ÷èñåë ñîâåðøåííûå, èçáûòî÷íûå è ñëåãêà èçáûòî÷íûå, íåäîñòàòî÷íûå è ñëåãêà íåäîñòàòî÷íûå ÷èñëà.
Çàêëþ÷åíèå
89
Çàêëþ÷åíèå Òåîðèÿ ÷èñåë çàíèìàòåëüíàÿ íàóêà. Íà íåé îñíîâàíû ìíîãèå èíòåðåñíûå àñïåêòû ïðèêëàäíûõ òåõíîëîãèé â ñàìûõ ðàçëè÷íûõ îáëàñòÿõ íàóêè è òåõíèêè. Çíàíèå îñíîâ òåîðèè ÷èñåë ïîìîãàåò ðàçðàáàòûâàòü áîëåå îïòèìèçèðîâàííûå àëãîðèòìû â âû÷èñëèòåëüíûõ çàäà÷àõ, à òàêæå óñïåøíî ïðèìåíÿòü ÷èñëåííûå ìåòîäû ïðè ðåøåíèè ðàçëè÷íûõ çàäà÷ ïðè ïîìîùè âû÷èñëèòåëüíîé òåõíèêè. Áîëåå òîãî, òåîðèÿ ÷èñåë ïîçâîëÿåò áûòü áîëåå âíèìàòåëüíûì ê ðàçëè÷íûì ÷èñëîâûì ïîñëåäîâàòåëüíîñòÿì, ðàçâèâàåò óìåíèå íàõîäèòü ñêðûòûå âçàèìîñâÿçè â êàçàëîñü áû õàîòè÷åñêèõ ìíîæåñòâàõ ÷èñåë. Âñ¼ ýòî, â ñâîþ î÷åðåäü, ñàìûì áëàãîòâîðíûì îáðàçîì ñêàçûâàåòñÿ íà ðàçâèòèè èíòåëëåêòóàëüíûõ ñïîñîáíîñòåé ÷åëîâåêà.  ñåòè Èíòåðíåò ïî àäðåñó http://www.research.att.com/njas/sequences/ íàõîäèòñÿ ýíöèêëîïåäèÿ öåëî÷èñëåííûõ ïîñëåäîâàòåëüíîñòåé (ê ñîæàëåíèþ, íà àíãëèéñêîì ÿçûêå), â êîòîðîé ïðåäñòàâëåíà èíôîðìàöèÿ áîëåå ÷åì î ñòà òûñÿ÷àõ ðàçëè÷íûõ êîíå÷íûõ è áåñêîíå÷íûõ ïîñëåäîâàòåëüíîñòåé, ñîñòîÿùèõ èç öåëûõ ÷èñåë. Äàííóþ ýíöèêëîïåäèþ â òîì ÷èñëå ìîæíî èñïîëüçîâàòü è äëÿ ñàìîñòîÿòåëüíîãî ñîçäàíèÿ íîâûõ çàäà÷ â ðàìêàõ òåîðèè ÷èñåë äëÿ ïîñëåäóþùåãî ðåøåíèÿ ìåòîäàìè ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ.
Ìàãè÷åñêèå êâàäðàòû è ðåøåíèå ïåðåáîðíûõ çàäà÷ Ñòàòüÿ áûëà îïóáëèêîâàíà â 06 (30) æóðíàëà ¾Ïîòåíöèàë¿ â èþíå 2007 ãîäà.
 äàííîì ýññå ðàññìàòðèâàþòñÿ òèïîâûå ñïîñîáû ðåøåíèÿ çàäà÷ íà ïåðåáîð, êîòîðûå ÷àñòî ïîïàäàþòñÿ â ðàìêàõ ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ è ïðîãðàììèðîâàíèÿ âîîáùå.  êà÷åñòâå ïðèìåðà äëÿ ðàññìîòðåíèÿ ïðåäëàãàåìûõ ìåòîäèê äà¼òñÿ çàäà÷à ïîëó÷åíèÿ ñïèñêà ìàãè÷åñêèõ êâàäðàòîâ äëÿ çàäàííîãî ðàçìåðà êâàäðàòà. Ðàññìîòðåíèå, êàê îáû÷íî, ïðîèçâîäèòñÿ íà ôóíêöèîíàëüíîì ÿçûêå ïðîãðàììèðîâàíèÿ Haskell.
Ââåäåíèå Áîëüøàÿ ñîâåòñêàÿ ýíöèêëîïåäèÿ äà¼ò ñóõîå è ìàòåìàòè÷åñêè ÷¼òêîå îïðåäåëåíèå ìàãè÷åñêîãî êâàäðàòà:
Ìàãè÷åñêèé êâàäðàò êâàäðàò, ðàçäåë¼ííûé íà ðàâíîå ÷èñëî n ñòîëáöîâ è ñòðîê, ñî âïèñàííûìè â ïîëó÷åííûå êëåòêè ïåðâûìè n2 íàòóðàëüíûìè ÷èñëàìè, êîòîðûå äàþò â ñóììå ïî êàæäîìó ñòîëáöó, êàæäîé ñòðîêå è äâóì áîëüøèì äèàãîíàëÿì îäíî è òî æå ÷èñëî (ðàâíîå, êàê ëåãêî äîêàçàòü, n(n2+1) ). Äîêàçàíî, ÷òî ìàãè÷åñêèé êâàäðàò ìîæíî ïîñòðîèòü äëÿ ëþáîãî n, íà÷èíàÿ ñ n = 3. Ñóùåñòâóþò ìàãè÷åñêèå êâàäðàòû, óäîâëåòâîðÿþùèå ðÿäó äîïîëíèòåëüíûõ óñëîâèé, íàïðèìåð ìàãè÷åñêèé êâàäðàò ñ 64 êëåòêàìè, êîòîðûé ìîæíî ðàçáèòü íà 4 ìåíüøèõ, ñîäåðæàùèõ ïî 16 êëåòîê êâàäðàòà, ïðè÷¼ì â êàæäîì èç íèõ ñóììà ÷èñåë ëþáîé ñòðîêè, ñòîëáöà èëè áîëüøîé äèàãîíàëè îäíà è òà æå (130).  Èíäèè è íåêîòîðûõ äðóãèõ ñòðàíàõ ìàãè÷åñêèå êâàäðàòû óïîòðåáëÿëè â êà÷åñòâå òàëèñìàíîâ. Ñîñòàâëåíèå ìàãè÷åñêèõ êâàäðàòîâ êëàññè÷åñêèé îáðàçåö ìàòåìàòè÷åñêèõ ðàçâëå÷åíèé è ãîëîâîëîìîê. 2
Íî ñòðîãàÿ íàóêà, êàê îáû÷íî, ñóõà. Íà ñàìîì æå äåëå ìàãè÷åñêèå êâàäðàòû ñ äðåâíåéøèõ âðåì¼í èñïîëüçóþòñÿ äëÿ ðàçëè÷íûõ öåëåé, ñâÿçàííûõ ñ âîëøåáñòâîì è êîëäîâñòâîì, èíà÷å îòêóäà ó íèõ òàêîå íàçâàíèå? È äåéñòâèòåëüíî, ìàãè÷åñêèå êâàäðàòû ýòî ñèìâîëû ÷èñëîâîé ãàðìîíèè, êîòîðûå âûðàæàþò êîñìè÷åñêèé ïðèíöèï ìèðîïîðÿäêà. Êàæäûé ìàãè÷åñêèé êâàäðàò èëëþñòðèðóåò çàêîíû îíòîëîãè÷åñêîé ñèììåòðèè, òåì ñàìûì ÷åðåç íåãî ïîñòèãàåòñÿ ïðèñóòñòâèå ðàöèîíàëüíîãî íà÷àëà â ìèðîçäàíèè.  ìàãè÷åñêîé ïðàêòèêå èñïîëüçîâàëèñü êâàäðàòû, ïðåäíàçíà÷åííûå äëÿ îáðåòåíèÿ ñâåðõúåñòåñòâåííûõ ñïîñîáíîñòåé ïîë¼òîâ â îáëèêå ïòèö, ïîíèìàíèÿ ÿçûêà æèâîòíûõ, îáðåòåíèÿ íåâèäèìîãî äëÿ ãëàç ñîñòîÿíèÿ, íàõîæäåíèÿ êëàäîâ, ðàñêðûòèÿ ñåêðåòîâ ïðîøëîãî, ïðîíèêíîâåíèÿ â áóäóùåå è ò. ï. Èìåëèñü êâàäðàòû-çàêëèíàíèÿ, íàïðàâëåííûå ïðîòèâ âðàãîâ. Äàæå ïåðåïèñûâàíèå èõ â òåòðàäü ïðåäñòàâëÿëîñü âåñüìà îïàñíûì, è ìàã â òàêèõ ñëó÷àÿõ âîñïðîèçâîäèë èõ ñ óìûøëåííîé îøèáêîé.
Ïðîñòåéøèé âàðèàíò ïåðåáîðà
91
Ðàçíûå ìàãè÷åñêèå êâàäðàòû ïðèïèñûâàëèñü ðàçíûì ñèëàì. Òàê, ê ïðèìåðó, ÷èñëîâîé êâàäðàò ñ òð¼õêëåòî÷íûìè ñòîðîíàìè ñîîòâåòñòâóåò ïëàíåòå Ñàòóðí. Îí äåìîíñòðèðóåò ñèììåòðèþ ìåæäó ÷¼òíûìè è íå÷¼òíûìè ÷èñëàìè. Êâàäðàò ñ ÷åòûð¼õêëåòî÷íûìè ñòîðîíàìè îòíîñèòñÿ ê Þïèòåðó. Êâàäðàò ñ ïÿòèêëåòî÷íûìè ñòîðîíàìè ÿâëÿåòñÿ àðõåòèïîì Ìàðñà, ñ÷èòàëîñü, ÷òî çàêëèíàíèÿ íàä íèì ðàçâèâàþò âîèíñòâåííîñòü. Êâàäðàò ñ øåñòèêëåòî÷íûìè ñòîðîíàìè ñèìâîëèçèðóåò Ñîëíöå. Êâàäðàò ñ ñåìèêëåòî÷íûìè ñòîðîíàìè ñîîòíîñèòñÿ ñ Âåíåðîé, òàê æå êàê òð¼õêëåòî÷íûé, äåìîíñòðèðîâàë ñèììåòðèþ ÷¼òíûõ è íå÷¼òíûõ öèôð. Êàê âèäíî, ìàãè÷åñêèå êâàäðàòû â äðåâíèå âðåìåíà èìåëè ÷ðåçâû÷àéíî ñåðü¼çíîå ïðèêëàäíîå çíà÷åíèå. À ïîñåìó ìîæíî ïðåäïîëîæèòü, ÷òî çíàíèå î ìàãè÷åñêèõ êâàäðàòàõ âåñüìà âàæíî, ïîýòîìó èõ èçó÷åíèå ìîæåò ñïîñîáñòâîâàòü ðàçâèòèþ ìàãè÷åñêîé ñèëû. Íó à ëþäÿì, íàñòðîåííûì íà àáñîëþòíîå ðàöèîíàëüíîå ìûøëåíèå, ïîíðàâèòñÿ ðåøàòü çàäà÷ó íà ïîèñê âñåõ ìàãè÷åñêèõ êâàäðàòîâ çàäàííîãî ðàçìåðà â àâòîìàòèçèðîâàííîì (èëè äàæå àâòîìàòè÷åñêîì) ðåæèìå, òàê êàê ñî âðåì¼í äðåâíèõ ôèëîñîôîâ è ìèñòèêîâ ìû ïîëó÷èëè â ñâî¼ ðàñïîðÿæåíèå òàêèå ïðåêðàñíûå èíñòðóìåíòû äëÿ ýòèõ öåëåé, êàê ýëåêòðîííûå âû÷èñëèòåëüíûå ìàøèíû è ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå. Ïðèíèìàÿ âî âíèìàíèå îáà óêàçàííûõ àñïåêòà, äàëåå â ýòîì ðàçäåëå ðàññìàòðèâàþòñÿ ïåðåáîðíûå çàäà÷è ñëîæíîãî õàðàêòåðà ñ áîëüøèì îáú¼ìîì ïåðåáîðà íà ïðèìåðå ïîèñêà ìàãè÷åñêèõ êâàäðàòîâ. Ðàññìîòðåíèå âåä¼òñÿ ïðè ïîìîùè ôóíêöèîíàëüíîãî ÿçûêà ïðîãðàììèðîâàíèÿ Haskell, ïîýòîìó äëÿ ïîíèìàíèÿ ÷èòàòåëü äîëæåí áûòü çíàêîì ñ ñèíòàêñèñîì ýòîãî ÿçûêà â îáú¼ìå îïóáëèêîâàííûõ â êíèã [6] è [14].
Ïðîñòåéøèé âàðèàíò ïåðåáîðà Äëÿ òîãî ÷òîáû íà÷àòü äâèãàòüñÿ â êàêîì-òî íàïðàâëåíèè ïðè ðåøåíèè ïîñòàâëåííîé çàäà÷è, íåîáõîäèìî ðàññìîòðåòü êàêèå-íèáóäü ïðîñòåéøèå ÷àñòíûå ñëó÷àè, ÷òîáû ïîíÿòü, ÷òî äîëæíî ïðîèñõîäèòü ïðè ïîèñêå ìàãè÷åñêèõ êâàäðàòîâ. Äëÿ ýòèõ öåëåé ïîäîéä¼ò ìàãè÷åñêèé êâàäðàò ðàçìåðà 3 × 3, òàê êàê òàêîé êâàäðàò îäèí (ñ òî÷íîñòüþ äî ïîâîðîòîâ è îòðàæåíèé), à ïîòîìó îñóùåñòâèòü åãî ïîèñê áóäåò ëåãêî. Êðîìå òîãî, êîëè÷åñòâî âàðèàíòîâ äëÿ ïåðåáîðà íå òàê âåëèêî. ×òî åñòü ìàãè÷åñêèé êâàäðàò ðàçìåðà 3 × 3 ñ ìàòåìàòè÷åñêîé òî÷êè çðåíèÿ? Ýòî ìàòðèöà óêàçàííîãî ðàçìåðà, â êîòîðîé ðàçìåùåíû ÷èñëà îò 1 äî 9 òàêèì îáðàçîì, ÷òî ñóììû ÷èñåë â ãîðèçîíòàëüíûõ ðÿäàõ, âåðòèêàëüíûõ ñòîëáöàõ è äâóõ äèàãîíàëÿõ ðàâíû ìåæäó ñîáîé. Ýòî íàòàëêèâàåò íà ìûñëü î òîì, êàê äîëæíà âûãëÿäåòü ôóíêöèÿ äëÿ ïåðåáîðà â ïåðâîì ïðèáëèæåíèè: ( / / ) : : Eq a => [ a ] −> a −> [ a ] [ ] // y = [] ( x : xs ) // y = i f ( x == y )
then xs el se x : ( xs // y )
( / / / ) : : Eq a => [ a ] −> [ a ] −> [ a ] s /// [ ] = s s /// ( x : xs ) = ( s // x ) /// xs
ms_3 : : [ [ Integer ] ] ms_3 = [ [ x1 , x2 , x3 , y1 , y2 , y3 , z1 , z2 , z3 ] x1 <− [ 1 . . 9 ] , x2 <− [ 1 . . 9 ] /// x3 <− [ 1 . . 9 ] /// y1 <− [ 1 . . 9 ] ///
| [ x1 ] , [ x1 , x2 ] , [ x1 , x2 , x3 ] ,
92
Ìàãè÷åñêèå êâàäðàòû è ðåøåíèå ïåðåáîðíûõ çàäà÷
y2 <− [ 1 . . 9 ] /// [ x1 , x2 , x3 , y1 ] , y3 <− [ 1 . . 9 ] /// [ x1 , x2 , x3 , y1 , y2 ] , z1 <− [ 1 . . 9 ] /// [ x1 , x2 , x3 , y1 , y2 , y3 ] , z2 <− [ 1 . . 9 ] /// [ x1 , x2 , x3 , y1 , y2 , y3 , z1 ] , z3 <− [ 1 . . 9 ] /// [ x1 , x2 , x3 , y1 , y2 , y3 , z1 , z2 ] , x1 + x2 + x3 == y1 + y2 + y3 , x1 + x2 + x3 == z1 + z2 + z3 , x1 + x2 + x3 == x1 + y1 + z1 , x1 + x2 + x3 == x2 + y2 + z2 , x1 + x2 + x3 == x3 + y3 + z3 , x1 + x2 + x3 == x1 + y2 + z3 , x1 + x2 + x3 == x3 + y2 + z1 ] Âñïîìîãàòåëüíûå îïåðàöèè (//) è (///) èñïîëüçóþòñÿ äëÿ ïîëó÷åíèÿ ñïèñêà ñ èñêëþ÷¼ííûì èç íåãî ýëåìåíòîì è ïîäñïèñêîì ñîîòâåòñòâåííî. Êàê âèäíî, ýòà ôóíêöèÿ äîñòàòî÷íî ãðîìîçäêà. Îäíàêî îíà ïîëíîñòüþ âîñïðîèçâîäèò ìàòåìàòè÷åñêîå îïðåäåëåíèå, äàííîå ìàãè÷åñêîìó êâàäðàòó ðàçìåðà 3 × 3. Îíà èñïîëüçóåò ïðåäñòàâëåíèå ìàòðèöû â âèäå ñïèñêà èç äåâÿòè ýëåìåíòîâ (÷òî íå òàê ïðèíöèïèàëüíî), à ñàìè ýëåìåíòû âûáèðàþòñÿ èç íàáîðà ÷èñåë îò 1 äî 9, ïðè ýòîì íà êàæäîì ñëåäóþùåì øàãå èç ýòîãî íàáîðà óäàëÿþòñÿ ïðåäûäóùèå âûáðàííûå ýëåìåíòû. Ïîñëå ÷åãî ïðîèçâîäèòñÿ ïðîâåðêà. Çàïóñê ýòîé ôóíêöèè íà èñïîëíåíèå â èíòåðïðåòàòîðå HUGS 98 äàñò íåóòåøèòåëüíûå ðåçóëüòàòû. Âåñü ïîèñê çàéì¼ò îêîëî ìèíóòû âðåìåíè, íî ïðè ýòîì áóäåò ïðîèçâåäåíî 150 ìèëëèîíîâ , áóäåò çàäåéñòâîâàíî 267 ìèëëèîíîâ ÿ÷ååê ïàìÿòè, à ñáîðùèê ìóñîðà çàïóñòèòñÿ 295 ðàç. È ýòî âñ¼ òîëüêî ðàäè òîãî, ÷òîáû ïîëó÷èòü îäèí-åäèíñòâåííûé ìàãè÷åñêèé êâàäðàò (â ðåçóëüòàòå, êîíå÷íî, áóäåò âûâåäåíî 8 èçîìîðôíûõ äðóã äðóãó êâàäðàòîâ) ñëåäóþùåãî âèäà:
ðåäóêöèé
2 9 4
7 5 3
6 1 8
Ýòî ñîâåðøåííî íåïðèåìëåìûé ðåçóëüòàò, òàê êàê ýòî íå ïîçâîëèò âû÷èñëèòü íè îäíîãî ìàãè÷åñêîãî êâàäðàòà ðàçìåðîì 4 × 4 è âûøå çà äîñòóïíîå âðåìÿ. Ïîýòîìó íåîáõîäèìà êàêàÿ-òî îïòèìèçàöèÿ. Ïåðâîå, ÷òî ïðèõîäèò â ãîëîâó ïîñëå èçó÷åíèÿ ôóíêöèè ãåíåðàöèè, ýòî èñïîëüçîâàíèå ìàãè÷åñêîé ñóììû äëÿ ñðàâíåíèÿ â . Âåäü ôîðìóëà å¼ âû÷èñëåíèÿ èçâåñòíà. Íó à âòîðîå èñïîëüçîâàíèå èíîãî ïîðÿäêà ïåðåáîðà è ïîèñêà, êîòîðûé ïîçâîëèò îòñå÷ü çàâåäîìî òóïèêîâûå âåòâè äåðåâà ïåðåáîðà. Íàïðèìåð, íîâàÿ, áîëåå îïòèìèçèðîâàííàÿ ôóíêöèÿ ìîæåò âûãëÿäåòü ñëåäóþùèì îáðàçîì:
âûðàæåíèÿõ îõðàíû
magicSum : : Fractional a => a −> a magicSum n = n ∗ ( n ^2 + 1 ) / 2 ms_3 ' : : [ [ Double ] ] ms_3 ' = [ [ x1 , x2 , x3 , y1 , y2 , y3 , z1 , z2 , z3 ] |
Ïðîñòåéøèé âàðèàíò ïåðåáîðà
x1 x2 x3 x1 y1 z1
<− [ 1 . . 9 ] , <− [ 1 . . 9 ] /// [ x1 ] <− [ 1 . . 9 ] /// [ x1 , + x2 + x3 == ms , <− [ 1 . . 9 ] /// [ x1 , <− [ 1 . . 9 ] /// [ x1 , y1 ] x1 + y1 + z1 == ms , y2 <− [ 1 . . 9 ] /// [ x1 , y1 , x3 + y2 + z1 == ms , y3 <− [ 1 . . 9 ] /// [ x1 , y1 , y1 + y2 + y3 == ms , z2 <− [ 1 . . 9 ] /// [ x1 , y1 , y3 ] x2 + y2 + z2 == ms , z3 <− [ 1 . . 9 ] /// [ x1 , y1 , y3 , z1 + z2 + z3 == ms , x3 + y3 + z3 == ms , x1 + y2 + z3 == ms ] where ms = magicSum 3
93
,
x2 ] , x2 , x3 ] , x2 , x3 , ,
x2 , x3 , z1 ] , x2 , x3 , z1 , y2 ] , x2 , x3 , z1 , y2 , ,
x2 , x3 , z1 , y2 , z2 ] ,
Âûïîëíåíèå ôóíêöèè ms_3' ïðîèñõîäèò óæå ïðàêòè÷åñêè ìãíîâåííî. Ïðè ýòîì òðåáóåòñÿ 208 òûñÿ÷ ðåäóêöèé è 365 òûñÿ÷ ÿ÷ååê ïàìÿòè. Ýòî âûèãðûø â ýôôåêòèâíîñòè ïî÷òè â 723 ðàçà ïî ñðàâíåíèþ ñ ïðåäûäóùèì îïðåäåëåíèåì. Ìîæíî åù¼ ïîèãðàòüñÿ ñ äàëüíåéøåé îïòèìèçàöèåé àëãîðèòìà ïåðåáîðà, íàïðèìåð óäàëÿÿ èç íàáîðà [1..9] íå ïîäñïèñêè, à îäèíî÷íûå ýëåìåíòû, ïîëó÷åííûå íà ïðåäûäóùåì øàãå ïåðåáîðà, îïðåäåëÿÿ ëîêàëüíûå ïåðåìåííûå äëÿ ýòèõ öåëåé, íî ñìûñëà â ýòîì îñîáåííîãî íåò, òàê êàê â ïîäîáíûõ îïðåäåëåíèÿõ ôóíêöèé èìåþòñÿ äâå ïðîáëåìû: îäíà íå î÷åíü ñåðü¼çíàÿ, à äðóãàÿ âåñüìà ñåðü¼çíàÿ. Ïåðâàÿ çàêëþ÷àåòñÿ â òîì, ÷òî ïðè èñïîëüçîâàíèè ôóíêöèè magicSumm, êîòîðàÿ âû÷èñëÿåò ñóììó ìàãè÷åñêîãî êâàäðàòà, ïðîèñõîäèò âûõîä çà ïðåäåëû ìíîæåñòâà íàòóðàëüíûõ ÷èñåë. Ýòî íåõîðîøî, èáî èñïîëüçîâàíèå îïåðàöèé íàä ÷èñëàìè ñ ïëàâàþùåé òî÷êîé, êîãäà òàêèå ÷èñëà äàæå íå èñïîëüçóþòñÿ, íåîáîñíîâàííî. Ýòà ïðîáëåìà ðåøàåòñÿ ïðîñòî çàìåíîé îïðåäåëåíèÿ ôóíêöèè (ñàìîñòîÿòåëüíî ìîæíî äîêàçàòü, ÷òî ýòî îïðåäåëåíèå òîæäåñòâåííî ïî ðåçóëüòàòó ïðåäûäóùåìó, òî åñòü èìååò ìåñòî îïðåäåëåíèé ôóíêöèé):
ýêñòåíñèîíàëüíîå òîæäåñòâî
magicSum : : Integral a => a −> a magicSum n = sum [ 1 . . ( n ^ 2 ) ] ` div ` n Èñïîëüçîâàíèå òàêîãî îïðåäåëåíèÿ åù¼ áîëüøå ñíèæàåò çàòðàòû âû÷èñëèòåëüíûõ ðåñóðñîâ. Âìåñòî âû÷èñëåíèÿ ñóììû ýëåìåíòîâ ñïèñêà ìîæíî òàêæå ïîëüçîâàòüñÿ îïåðàòîðîì öåëî÷èñëåííîãî äåëåíèÿ div â ïðåäûäóùåì îïðåäåëåíèè. Ýôôåêòèâíîñòü ïðèìåðíî îäèíàêîâàÿ. Îäíàêî íîâîå îïðåäåëåíèå ôóíêöèè magicSum íå óñòðàíÿåò äðóãóþ ïðîáëåìó, áîëåå ñåðü¼çíóþ. Ïðîáëåìà ñèÿ ñâÿçàíà ñ âåñüìà ÷àñòíûì âèäîì ôóíêöèé ms_3 è ms_3' îíè ïðåäíàçíà÷åíû òîëüêî äëÿ âû÷èñëåíèÿ ìàãè÷åñêèõ êâàäðàòîâ 3 × 3. À ÷òî, åñëè ïîòðåáóåòñÿ âû÷èñëèòü ìàãè÷åñêèå êâàäðàòû ïðîèçâîëüíîãî ðàçìåðà n × n? Ýòè ôóíêöèè, åñòåñòâåííî, íå ïîäîéäóò. Ñàìî ñîáîé ðàçóìååòñÿ, ÷òî
94
Ìàãè÷åñêèå êâàäðàòû è ðåøåíèå ïåðåáîðíûõ çàäà÷
íåîáõîäèìî ñîçäàòü óíèâåðñàëüíîå îïðåäåëåíèå ôóíêöèè äëÿ ëþáîãî çàäàííîãî n. Íî ïîäîéòè ê ýòîé çàäà÷å íå òàê ïðîñòî. . .
Ïåðåáîð ñ èñïîëüçîâàíèåì ïåðåñòàíîâîê Ïðè ðàññìîòðåíèè çàäà÷è äëÿ ïðîèçâîëüíîãî ðàçìåðà ìàãè÷åñêîãî êâàäðàòà n × n âîçíèêàåò ïðîáëåìà ïðåäñòàâëåíèÿ òàêîãî êâàäðàòà â ïàìÿòè. Ìîæíî îòìåòèòü, ÷òî ïðåäëîæåííûé â ïðåäûäóùåì ðàçäåëå ñïîñîá ïðåäñòàâëåíèÿ â âèäå ñïèñêà èìååò ñâîþ ïðèâëåêàòåëüíîñòü êàê íàèáîëåå ïðîñòîé ñïîñîá. Èì ìîæíî âîñïîëüçîâàòüñÿ è â îáùåì ñëó÷àå. Îäíàêî âñ¼ åù¼ ñòîèò âîïðîñ î ñïîñîáàõ ïîëó÷åíèÿ ðàçëè÷íûõ êîìáèíàöèé, êîòîðûå áóäóò ðàññìàòðèâàòüñÿ â êà÷åñòâå ìàãè÷åñêèõ êâàäðàòîâ.  ýòîì äåëå ïîìîæåò òàêàÿ îòðàñëü ìàòåìàòèêè, êàê êîìáèíàòîðèêà, òàê êàê îíà èìååò äîñòàòî÷íûå ìåõàíèçìû äëÿ îïèñàíèÿ ðàçëè÷íûõ ñïîñîáîâ ïåðåáîðà. Ê íåé è íåîáõîäèìî îáðàòèòüñÿ. Äëÿ ðåøåíèÿ çàäà÷è î ïîñòðîåíèè ñïèñêà ìàãè÷åñêèõ êâàäðàòîâ ðàçìåðíîñòè n × n íåîáõîäèìî ïîëó÷àòü âñåâîçìîæíûå êîìáèíàöèè ÷èñåë îò 1 äî n2 , âûñòðîåííûå â ñïèñîê, ïîñëå ÷åãî êàæäóþ êîìáèíàöèþ ïðîâåðÿòü íà ¾ìàãè÷íîñòü¿. Ýòî ïðîñòåéøåå ïîíèìàíèå îáîáù¼ííîãî ïåðåáîðíîãî àëãîðèòìà. À äëÿ ïîëó÷åíèÿ ñïèñêà âñåõ âîçìîæíûõ êîìáèíàöèé çàäàííûõ ÷èñåë êàê ðàç è ìîæíî âîñïîëüçîâàòüñÿ îäíèì èç ïîíÿòèé êîìáèíàòîðèêè. Ýòî ïîíÿòèå (íåîáõîäèìî îòìåòèòü, ÷òî ñåãîäíÿ ôóíêöèè äëÿ ïîëó÷åíèÿ ïåðåñòàíîâîê è äðóãèõ êîìáèíàòîðíûõ ðàçìåùåíèé èìåþòñÿ â ñòàíäàðòíîì ìîäóëå Data.List). Ïåðåñòàíîâêàìè èç n ýëåìåíòîâ íàçûâàþòñÿ êîìáèíàöèè òàêèõ ýëåìåíòîâ, êàæäîå èç êîòîðûõ ñîäåðæèò âñå n ýëåìåíòîâ, îòëè÷àþùèõñÿ ïîýòîìó äðóã îò äðóãà òîëüêî ïîðÿäêîì ðàñïîëîæåíèÿ ýëåìåíòîâ. Íàïðèìåð, èç 3 ýëåìåíòîâ (a, b, c) ìîæíî îáðàçîâàòü ñëåäóþùèå ïåðåñòàíîâêè: abc, bac, cab, acb, bca, cba. ×èñëî âñåõ âîçìîæíûõ ïåðåñòàíîâîê, êîòîðûå ìîæíî îáðàçîâàòü èç n ýëåìåíòîâ, îáîçíà÷àåòñÿ ñèìâîëîì Pn è âû÷èñëÿåòñÿ ïî ôîðìóëå:
ïåðåñòàíîâêà
(17)
Pn = n!
Òàêèì îáðàçîì, íåîáõîäèìî ñîçäàòü ôóíêöèè äëÿ ãåíåðàöèè âñåõ âîçìîæíûõ ïåðåñòàíîâîê äëÿ ýëåìåíòîâ ñïèñêà îò 1 äî n2 è ïîñëåäóþùåé ïðîâåðêè ñãåíåðèðîâàííûõ êîìáèíàöèé. Ïåðâóþ ôóíêöèþ íàïèñàòü äîñòàòî÷íî ïðîñòî:
permutations : : Eq a => [ a ] −> [ [ a ] ] permutations [ ] = [ [ ] ] permutations l = [ x : ps | x <− l , ps <− ( permutations ( l // x ) ) ]
êëîç
Ñïèñîê âñåõ ïåðåñòàíîâîê äëÿ çàäàííîãî ñïèñêà ýëåìåíòîâ âû÷èñëÿåòñÿ Ïåðâûé â ýòîì îïðåäåëåíèè ÿâëÿåòñÿ âûõîäîì èç ðåêóðñèè, îïðåäåëÿÿ ðåçóëüòàò ôóíêöèè íà ïóñòîì ñïèñêå. Âòîðîé êëîç îïðåäåëåíèÿ ñàìûé ãëàâíûé. Èìåííî îí îïðåäåëÿåò ñïîñîá âû÷èñëåíèÿ ñïèñêà ïåðåñòàíîâîê ýëåìåíòîâ îò 1 äî n2 . Ñìûñë ìîæíî ïîíÿòü, ïðî÷èòàâ îïðåäåëåíèå ýòîãî êëîçà ïðèìåðíî òàê:
Ïåðåñòàíîâêè ýëåìåíòîâ ñïèñêà l âû÷èñëÿþòñÿ êàê ñïèñîê ñïèñêîâ, ãäå ãîëîâà êàæäîãî ñïèñêà âûáèðàåòñÿ èç ñïèñêà l, à õâîñò èç ñïèñêà ïåðåñòàíîâîê, ïîëó÷åííûõ äëÿ èñõîäíîãî ñïèñêà l áåç âûáðàííîãî íà ïðåäûäóùåì øàãå ýëåìåíòà x. Èìåÿ â ñâî¼ì àðñåíàëå ýòó ôóíêöèþ, ìîæíî ïîëó÷èòü ñïèñîê âñåõ âîçìîæíûõ ïåðåñòàíîâîê ÷èñåë îò 1 äî n2 . Îñòà¼òñÿ ïðîâåðèòü òàêèå êîìáèíàöèè íà ¾ìàãè÷íîñòü¿. À äëÿ ýòîãî íåîáõîäèìà ôóíêöèÿ (èëè íàáîð ôóíêöèé), êîòîðàÿ âîçâðàòèò áóëåâñêîå çíà÷åíèå â çàâèñèìîñòè îò òîãî, ÿâëÿåòñÿ ëè ïåðåäàííàÿ åé íà âõîä êîìáèíàöèÿ ìàãè÷åñêèì êâàäðàòîì. Ïðè ïðåäñòàâëåíèè ìàãè÷åñêèõ êâàäðàòîâ â âèäå ñïèñêà òàêàÿ ôóíêöèÿ ìîæåò âûãëÿäåòü ñëåäóþùèì îáðàçîì:
Ïåðåáîð ñ èñïîëüçîâàíèåì ïåðåñòàíîâîê
isMagic : : Int −> [ Int ] −> Bool isMagic n ms = i f ( n ^2 /= length then False els e ( testH s n ( testV s n ( testD s n where s = magicSum n
95
ms ) ms ) && ms ) && ms )
Ýòà ôóíêöèÿ äëÿ çàäàííîãî ðàçìåðà n è çàäàííîé êîìáèíàöèè ms âîçâðàùàåò çíà÷åíèå True, åñëè êîìáèíàöèÿ ms ÿâëÿåòñÿ ìàãè÷åñêèì êâàäðàòîì n × n, è çíà÷åíèå False â ïðîòèâíîì ñëó÷àå. Â å¼ îïðåäåëåíèè èñïîëüçóþòñÿ âñïîìîãàòåëüíûå ôóíêöèè testH, testV è testD, êîòîðûå ïðèìåíÿþòñÿ äëÿ ïðîâåðêè ñóììû ÷èñåë ãîðèçîíòàëåé, âåðòèêàëåé è äèàãîíàëåé ìàãè÷åñêîãî êâàäðàòà ms íà ðàâåíñòâî ìàãè÷åñêîé ñóììå. Ýòè ôóíêöèè îïðåäåëèòü íå òàê ñëîæíî, ïðèíèìàÿ âî âíèìàíèå ñïîñîá ïðåäñòàâëåíèÿ ìàãè÷åñêîãî êâàäðàòà.
testH : : Int −> Int −> [ Int ] −> Bool testH _ _ [ ] = True testH s n ms = ( sum ( take n ms ) == s ) && ( testH s n ( drop n ms ) ) testV : : Int −> Int −> [ Int ] −> Bool testV s n ms = testV ' s n n ms
where
testV ' _ 0 _ _ = True testV ' s a n ms = ( sum [ ms ! ! ( ( a − 1 ) + ( j ∗ n ) ) | j <− [ 0 . . ( n − 1 ) ] ] == s ) && ( testV ' s ( a − 1 ) n ms ) testD : : Int −> Int −> [ Int ] −> Bool testD s n ms = ( sum [ ms ! ! ( i ∗ ( n + 1 ) ) | i <− [ 0 . . ( n − 1 ) ] ] == s ) && ( sum [ ms ! ! ( ( i + 1 ) ∗ ( n − 1 ) ) | i <− [ 0 . . ( n − 1 ) ] ] == s ) Ôóíêöèÿ testH óñòðîåíà ïðîñòî. Îíà ïîñëåäîâàòåëüíî ñâåðÿåò ñóììó êàæäûõ n ýëåìåíòîâ ïåðåäàííîãî åé äëÿ ïðîâåðêè ñïèñêà ñ ìàãè÷åñêèì ÷èñëîì, êîòîðîå òàêæå ïåðåäà¼òñÿ â êà÷åñòâå âõîäíîãî ïàðàìåòðà (ýòî ñäåëàíî â êà÷åñòâå îïòèìèçàöèè). Ýòî äåëàåòñÿ âûáîðêîé ïåðâûõ n ýëåìåíòîâ (ñòàíäàðòíàÿ ôóíêöèÿ take), ïðîâåðêîé èõ ñóììû è ïåðåäà÷åé îñòàâøèõñÿ ýëåìåíòîâ ñïèñêà (ñòàíäàðòíàÿ ôóíêöèÿ drop) â ýòó æå ñàìóþ ôóíêöèþ testH. Ôóíêöèÿ testV íåìíîãî ñëîæíåå. Ãëàâíûé ñìûñë å¼ ðàáîòû çàêëþ÷àåòñÿ â ïîëó÷åíèè ñïèñêà ýëåìåíòîâ èñõîäíîãî ñïèñêà, ðàñïîëîæåííûõ â îäíîì ñòîëáöå. Äëÿ ýòîãî èñïîëüçóåòñÿ âñïîìîãàòåëüíàÿ ôóíêöèÿ testV', ó êîòîðîé âî âòîðîì êëîçå ïåðâûì îïåðàíäîì êîíúþíêöèè (&&) êàê ðàç è íàõîäèòñÿ ôîðìóëà äëÿ âû÷èñëåíèÿ ïîçèöèé ýëåìåíòîâ â ñïèñêå, êîòîðûå â êâàäðàòå íàõîäÿòñÿ â îäíîì ñòîëáöå (äëÿ íóìåðàöèè ñòîëáöà èñïîëüçóåòñÿ ïàðàìåòð a). ×èòàòåëþ ðåêîìåíäóåòñÿ ñàìîñòîÿòåëüíî ïðîâåðèòü ýòó ôîðìóëó. Íàêîíåö, ôóíêöèÿ testD ïðîñòî ïðîâåðÿåò äâå äèàãîíàëè êâàäðàòà. Îïÿòü æå, âäóì÷èâûé ÷èòàòåëü íàéä¼ò ïðîâåðêó ôîðìóë ïîëó÷åíèÿ ýëåìåíòîâ èç äèàãîíàëåé êâàäðàòà, êîòîðûé ïðåäñòàâëÿåòñÿ ñïèñêîì, èíòåðåñíîé çàäà÷åé. Îñòà¼òñÿ ðåàëèçîâàòü ãëàâíóþ ôóíêöèþ äëÿ ïîëó÷åíèÿ ñïèñêà ìàãè÷åñêèõ êâàäðàòîâ ðàçìåðà n × n. Ïîñëå ïðîâåä¼ííûõ ïîäãîòîâèòåëüíûõ ðàáîò ýòî íå ïðåäñòàâëÿåòñÿ ñëîæíûì äåëîì. ż îïðåäåëåíèå âûãëÿäèò ïðîñòî:
getMagicSquares : : Int −> [ [ Int ] ]
96
Ìàãè÷åñêèå êâàäðàòû è ðåøåíèå ïåðåáîðíûõ çàäà÷
getMagicSquares n = [ ms | ms <− permutations [ 1 . . ( n ^ 2 ) ] , isMagic n ms ] Êàê âèäíî, çäåñü óñòðîåí ïåðåáîð âñåõ âîçìîæíûõ ïåðåñòàíîâîê ñ ïîñëåäóþùåé ïðîâåðêîé èõ íà ¾ìàãè÷íîñòü¿.  î÷åðåäíîé ðàç ìîæíî óäèâèòüñÿ âûðàçèòåëüíîñòè ÿçûêà Haskell. Åäèíñòâåííîå, ÷òî íåîáõîäèìî îáúÿñíèòü, ýòî èñïîëüçîâàíèå îãðàíè÷åíèÿ íà òèï ôóíêöèè: Int −> [[Int]]. Èñïîëüçîâàíèå òèïà Int (îãðàíè÷åííûå öåëûå ÷èñëà) âìåñòî Integer (öåëûå ÷èñëà íåîãðàíè÷åííîãî ðàçìåðà) ïîçâîëÿåò âåñüìà ñåðü¼çíî ñíèçèòü ðåñóðñíûå çàòðàòû íà ïðîâåäåíèå âû÷èñëåíèé. Çàìåðû ïðîèçâîäèòåëüíîñòè ðàáîòû ýòîé ôóíêöèè èìååò ñìûñë äåëàòü äëÿ n = 3, òàê êàê äëÿ áîëüøèõ n ôóíêöèÿ ðàáîòàåò ñëèøêîì ìåäëåííî. ż çàïóñê ñ ïàðàìåòðîì 3 äà¼ò òàêèå ðåçóëüòàòû: 140 ìèëëèîíîâ ðåäóêöèé, 205 ìèëëèîíîâ ÿ÷ååê ïàìÿòè è 230 çàïóñêîâ ïðîöåññà ñáîðêè ìóñîðà. Êàê âèäíî, ýòè çíà÷åíèÿ íå ñèëüíî îòëè÷àþòñÿ îò çíà÷åíèé ôóíêöèè ms_3, ïîýòîìó ìîæíî ïðåäïîëîæèòü, ÷òî äëÿ n > 3 ôóíêöèÿ áóäåò ðàáîòàòü î÷åíü ìåäëåííî. Ïîýòîìó èìååò ñìûñë çàäóìàòüñÿ îá îïòèìèçàöèè, èáî, íåñìîòðÿ íà òî ÷òî ôóíêöèÿ getMagicSquares ñòàëà óíèâåðñàëüíîé ñ òî÷êè çðåíèÿ ðàçìåðà ìàãè÷åñêèõ êâàäðàòîâ, å¼ ïðîèçâîäèòåëüíîñòü âñ¼ æå îñòàâëÿåò æåëàòü ëó÷øåãî.
Ïåðåáîð ñ èñïîëüçîâàíèåì ðàçìåùåíèé Ïðè ðàññìîòðåíèè ïðåäûäóùåãî àëãîðèòìà ìîæíî áûëî óâèäåòü îäíó äîâîëüíî èíòåðåñíóþ åãî îñîáåííîñòü, êîòîðàÿ è ñâîäèò íà íåò âñå âîçìîæíîñòè ïîñòðîåíèÿ çà ðåàëüíîå âðåìÿ ìàãè÷åñêèõ êâàäðàòîâ ðàçìåðà 4 × 4. Îñîáåííîñòü ñèÿ çàêëþ÷àåòñÿ â òîì, ÷òî âî âðåìÿ îñóùåñòâëåíèÿ ïåðåáîðà ñîâåðøàåòñÿ ïîëíàÿ âûáîðêà êîìáèíàöèè, êîòîðàÿ òîëüêî ïîñëå ýòîãî ïðîâåðÿåòñÿ íà ¾ìàãè÷íîñòü¿, õîòÿ ýòó ïðîâåðêó ìîæíî ñäåëàòü äî ïîëó÷åíèÿ ïîëíîãî íàáîðà ÷èñåë (ñð. êàê ýòî ñäåëàíî â ôóíêöèè ms_3'). Íàïðèìåð, â ñëó÷àå ðàçìåðà 4 × 4 íåò íèêàêîé íàäîáíîñòè ðàññìàòðèâàòü âñþ êîìáèíàöèþ, åñëè ñóììà ïåðâûõ ÷åòûð¼õ ÷èñåë íå ðàâíà 34. Ïîýòîìó äëÿ ìàãè÷åñêîãî êâàäðàòà ðàçìåðà n × n íåîáõîäèìî îãðàíè÷èâàòü ïåðåáîð ïðè ïîìîùè ïðîâåðêè ñóììû êàæäûõ n ÷èñåë â ïîëó÷àåìîé êîìáèíàöèè. Ýòî ïîìîæåò ñäåëàòü ïîíÿòèå , êîòîðîå òàêæå îïðåäåëÿåòñÿ â êîìáèíàòîðèêå. Ðàçìåùåíèÿìè èç n ýëåìåíòîâ ïî k íàçûâàþòñÿ êîìáèíàöèè, êîòîðûå ìîæíî îáðàçîâàòü èç çàäàííûõ n ýëåìåíòîâ, ñîáèðàÿ â êàæäóþ êîìáèíàöèþ ïî k ýëåìåíòîâ, ïðè ýòîì ñàìè êîìáèíàöèè ìîãóò îòëè÷àòüñÿ äðóã îò äðóãà êàê ñàìèìè ýëåìåíòàìè, òàê è ïîðÿäêîì èõ âçàèìíîãî ðàñïîëîæåíèÿ. Íàïðèìåð, èç 3 ýëåìåíòîâ (a, b, c) ïî 2 ìîæíî îáðàçîâàòü ñëåäóþùèå ðàçìåùåíèÿ: ab, ac, ba, bc, ca, cb. ×èñëî âñåõ âîçìîæíûõ ðàçìåùåíèé, êîòîðûå ìîæíî îáðàçîâàòü èç n ýëåìåíòîâ ïî k , îáîçíà÷àåòñÿ ñèìâîëîì Akn è âû÷èñëÿåòñÿ ïî ôîðìóëå:
ðàçìåùåíèÿ
Akn =
n! (n − k)!
(18)
Èòàê, â ñëó÷àå ìàãè÷åñêîãî êâàäðàòà ðàçìåðà n × n íåîáõîäèìî ãåíåðèðîâàòü n ðàçìåùåíèé èç n2 ïî n è êàæäîå èç íèõ ïðîâåðÿòü íà ñîîòâåòñòâèå ìàãè÷åñêîé ñóììå. Äëÿ ýòîãî íóæíà ôóíêöèÿ ãåíåðàöèè âñåõ ðàçìåùåíèé ýëåìåíòîâ èç çàäàííîãî ñïèñêà. Îïðåäåëèòü å¼ íåñëîæíî:
arrangements : : ( Num a , Eq b ) => a −> [ b ] −> [ [ b ] ] arrangements 0 _ = [ [ ] ] arrangements k l = [ x : as | x <− l , as <− ( arrangements ( k − 1 ) ( l // x ) ) ] Ñìûñë å¼ âïîëíå ïîíÿòåí ïåðâûé àðãóìåíò îïðåäåëÿåò êîëè÷åñòâî ýëåìåíòîâ â ðàçìåùåíèè, à âòîðîé ñïèñîê ýëåìåíòîâ.  ðåçóëüòàòå áóäåò âûäàí ñïèñîê ñïèñêîâ, êàæäûì ýëåìåíòîâ êîòîðîãî ÿâëÿåòñÿ ñïèñîê, ÿâëÿþùèéñÿ îäíèì èç ðàçìåùåíèé ïî k ýëåìåíòîâ èç ñïèñêà l. Îäíàêî, êàê âèäíî, ýòà ôóíêöèÿ íå ãåíåðèðóåò ìàãè÷åñêèå êâàäðàòû çàäàííîãî ðàçìåðà, òàê êàê îíà äîëæíà ëèøü èñïîëüçîâàòüñÿ äëÿ ãåíåðàöèè òàêèõ êâàäðàòîâ. Ïîýòîìó íåîáõîäèìà äîïîëíèòåëüíàÿ ôóíêöèÿ, êîòîðàÿ âîçâðàùàëà áû ñïèñîê ñïèñêîâ, êàæäûì ýëåìåíòîì êîòîðîãî áûëî áû ïðåäñòàâëåíèå îäíîãî âàðèàíòà
Ïåðåáîð ñ èñïîëüçîâàíèåì ðàçìåùåíèé
97
¾êàíäèäàòà¿ â ìàãè÷åñêèå êâàäðàòû, êàê ýòî äåëàåò ôóíêöèÿ permutations. Ðåàëèçîâàòü òàêóþ ôóíêöèþ ìîæíî ïî àíàëîãèè:
constructSquares : : Integral a => a −> [ a ] −> [ [ a ] ] constructSquares _ [ ] = [ [ ] ] constructSquares n l = [ a ++ as | a <− ( arrangements n l ) , sum a == s , as <− ( constructSquares n ( l /// a ) ) ] where s = magicSum n Êàê âèäíî, îïðåäåëåíèå ýòîé ôóíêöèè ïðàêòè÷åñêè ïîëíîñòüþ ïîâòîðÿåò îïðåäåëåíèå ôóíêöèè permutations (êîíå÷íî, â ðàìêàõ èñïîëüçóåìûõ ïîíÿòèé), çà èñêëþ÷åíèåì íîâîãî óñëîâèÿ îõðàíû, êîòîðîå îòñåêàåò ïåðåáîð â ñëó÷àÿõ, åñëè î÷åðåäíîé íàáîð èç n ÷èñåë íå ïðîõîäèò ïåðâîíà÷àëüíûé òåñò íà ¾ìàãè÷íîñòü¿.  ýòîì âûðàæåíèè îõðàíû èñïîëüçîâàíî ëîêàëüíîå îïðåäåëåíèå s äëÿ òîãî, ÷òîáû âû÷èñëèòü ìàãè÷åñêóþ ñóììó äëÿ çàäàííîãî n òîëüêî îäèí ðàç, à íå äëÿ êàæäîãî a â îòäåëüíîñòè (îäèí èç ñïîñîáîâ îïòèìèçàöèè âû÷èñëåíèé ÷èòàòåëü ñàìîñòîÿòåëüíî ìîæåò ñðàâíèòü ïîêàçàòåëè ýôôåêòèâíîñòè â ñëó÷àÿõ èñïîëüçîâàíèÿ è â ñëó÷àå å¼ îòñóòñòâèÿ). Îñòà¼òñÿ ñîçäàòü íîâîå îïðåäåëåíèå ôóíêöèè äëÿ ïîëó÷åíèÿ ñïèñêà ìàãè÷åñêèõ êâàäðàòîâ çàäàííîãî ðàçìåðà. Ýòî óæå íå ïðåäñòàâëÿåò è âîâñå íèêàêîé ñëîæíîñòè:
ëîêàëüíîé ïåðåìåííîé
getMagicSquares ' : : Int −> [ [ Int ] ] getMagicSquares ' n = [ ms | ms <− constructSquares n [ 1 . . ( n ^ 2 ) ] , isMagic n ms ] Îäíàêî êàê îöåíèòü âîçìîæíîñòè íîâîãî îïðåäåëåíèÿ? Ñìîæåò ëè îíî ïîìî÷ü ïîëó÷èòü ñïèñîê âñåõ ìàãè÷åñêèõ êâàäðàòîâ ñ ðàçìåðîì õîòÿ áû 4 × 4? Äëÿ ïîëó÷åíèÿ îòâåòà íà ýòîò âîïðîñ íåîáõîäèìî ïðîâåñòè íåáîëüøîå èññëåäîâàíèå, êîòîðîå ïîìîæåò îöåíèòü âðåìÿ âûïîëíåíèÿ ôóíêöèè ïåðåä å¼ íåïîñðåäñòâåííûì çàïóñêîì. Äëÿ ýòîãî íåîáõîäèìî ñîáðàòü ôàêòè÷åñêèå äàííûå, êîòîðûå îáîçðèìû çà ìàëîå âðåìÿ. Ýòî çàìåðû âû÷èñëèòåëüíûõ ïàðàìåòðîâ äëÿ ôóíêöèé getMagicSquares è getMagicSquares' íà àðãóìåíòàõ 1, 2, è 3. Âñå ýòè çàìåðû áûëè ïðåäâàðèòåëüíî ñäåëàíû è ñâåäåíû â îäíó òàáëèöó:
n 1 2 3 4
getMagicSquares 801 1 352 13 742 19 850 8 2.42 · 10 3.44 · 108 4.36 · 1015 7.02 · 1015
getMagicSquares' 975 1 488 8 983 13 152 6 4.78 · 10 6.69 · 106 1.47 · 1011 1.96 · 1011
 ïåðâîé ñòðîêå äëÿ êàæäîé ôóíêöèè ïîêàçàíî êîëè÷åñòâî ïðîâåä¼ííûõ âî âðåìÿ âû÷èñëåíèé ðåäóêöèé, âòîðàÿ êîëè÷åñòâî èñïîëüçîâàííûõ ÿ÷ååê ïàìÿòè ñîîòâåòñòâåííî. ×åòâ¼ðòàÿ ñòðîêà òàáëèöû ïîêàçûâàåò âû÷èñëåííûå (ïðîãíîçèðóåìûå) çíà÷åíèÿ. Êàê áûëè ïîëó÷åíû ýòè çíà÷åíèÿ? Ïðè ïîìîùè íåñëîæíûõ âû÷èñëåíèé. Ïåðâîíà÷àëüíî áûëî çàìå÷åíî, ÷òî (ñòåïåíü ÷èñëà 10) ïåðå÷èñëåííûõ çíà÷åíèé èçìåíÿåòñÿ â íåêîòîðîé ïîñëåäîâàòåëüíîñòè. Ýòî ìîæíî âèäåòü â ïðåäñòàâëåííîé òàáëèöå äëÿ ïåðâîé ôóíêöèè ïîðÿäîê èçìåíÿåòñÿ êàê: 2, 4, 8 (î÷åíü ïîõîæå íà ñòåïåíè ÷èñëà 2); äëÿ âòîðîé ôóíêöèè ïîñëåäîâàòåëüíîñòü òàêàÿ: 2, 4, 6 (âðîäå ïðîñòî ÷¼òíûå ÷èñëà, íî ýòî ìîæåò áûòü è íåâåðíûì ïðåäïîëîæåíèåì). Ñîîòâåòñòâåííî, èç ïðåäïîëîæåíèÿ î òîì, ÷òî îòíîøåíèå ïîðÿäêîâ çíà÷åíèé íå èçìåíÿåòñÿ ïðè óâåëè÷åíèè n, ñäåëàíî âû÷èñëåíèå ýòèõ ïàðàìåòðîâ äëÿ n = 4. Íàïðèìåð, çíà÷åíèå ïàðàìåòðà â ïåðâîé ÿ÷åéêå ÷åòâ¼ðòîé ñòðîêè âû÷èñëåíî ïî ñëåäóþùåé ôîðìóëå:
ïîðÿäîê
R4 = R3 ·
3 2 (R R2 ) 2 (R R1 )
=
R33 · R1 R23
(19)
98
Ìàãè÷åñêèå êâàäðàòû è ðåøåíèå ïåðåáîðíûõ çàäà÷
Àíàëîãè÷íî âû÷èñëÿþòñÿ è çíà÷åíèÿ äðóãèõ ÿ÷ååê ÷åòâ¼ðòîé ñòðîêè (ïðè âû÷èñëåíèè ïî òàáëèöå çíà÷åíèÿ ìîãóò íåìíîãî îòëè÷àòüñÿ îò òåõ, ÷òî ïðåäñòàâëåíû, òàê êàê ïðè âû÷èñëåíèè âî âðåìÿ ýêñïåðèìåíòà èñïîëüçîâàëèñü áîëåå òî÷íûå çíà÷åíèÿ, ÷åì òå, êîòîðûå âíåñåíû â òàáëèöó). Äëÿ ïðîâåðêè ïîëó÷åííûõ ðåçóëüòàòîâ ìîæíî ïîñòðîèòü ãðàôèê (ñì. ðèñ. 4), ïðè ïîìîùè êîòîðîãî ìîæíî îöåíèòü ïðàâèëüíîñòü ñïðîãíîçèðîâàííûõ ðåçóëüòàòîâ. Êîíå÷íî, èç-çà ãèãàíòñêèõ çíà÷åíèé íåîáõîäèìî èñïîëüçîâàòü ïî îñè Y , êîòîðàÿ õàðàêòåðèçóåòñÿ òåì, ÷òî ðàâíûå ðàññòîÿíèÿ ïî íåé ñîîòâåòñòâóþò ðàâíûì îòíîøåíèÿì âåëè÷èí. Èñïîëüçîâàíèå òàêîé øêàëû ñëåäóåò åù¼ è èç òîãî, ÷òî èìåííî ïîðÿäîê âåëè÷èí ïðèìåíÿåòñÿ ïðè ïðîãíîçèðîâàíèè.
ëîãàðèôìè÷åñêóþ øêàëó
Ðèñ. 4. Ãðàôèê èçìåíåíèÿ êîëè÷åñòâà ðåäóêöèé äëÿ ôóíêöèé getMagicSquares è getMagicSquares' Êàê âèäíî íà ãðàôèêå, êðèâûå äîñòàòî÷íî ïëàâíûå, à ïîòîìó íîâûå òî÷êè (ñïðîãíîçèðîâàííûå) âïîëíå âïèñûâàþòñÿ â èçó÷àåìóþ êàíâó. Ñëåäîâàòåëüíî, íà îñíîâàíèè ýòèõ çíà÷åíèé ìîæíî ñïðîãíîçèðîâàòü âðåìÿ, êîòîðîå áóäåò çàòðà÷åíî íà ïåðåáîð è ïîèñê âñåõ ìàãè÷åñêèõ êâàäðàòîâ ðàçìåðà 4 × 4. Âðåìÿ ìîæíî âû÷èñëèòü ïî ñëåäóþùåé ôîðìóëå (ó÷èòûâàÿ, ÷òî âðåìÿ âû÷èñëåíèé çàâèñèò ëèíåéíî îò êîëè÷åñòâà ðåäóêöèé):
T 4 = T3 ·
R4 R3
(20)
Äëÿ âû÷èñëåíèÿ âñåõ ìàãè÷åñêèõ êâàäðàòîâ ðàçìåðà 3 × 3 ïðè ïîìîùè ïåðâîé ôóíêöèè áûëî çàòðà÷åíî 28.98 ñåêóíäû, ïðè ïîìîùè âòîðîé 1.13 ñåêóíäû (ýòè âðåìåíà çàìåðåíû óæå ïîñëå êîìïèëÿöèè ôóíêöèé â êîìïèëÿòîðå GHC â öåëÿõ óñêîðåíèÿ ïðîöåññà, ïîýòîìó îíè îòëè÷àþòñÿ îò âðåìåííûõ çíà÷åíèé, óïîìÿíóòûõ ðàíåå). Ñîîòâåòñòâåííî, äëÿ ôóíêöèè getMagicSquares âðåìÿ âûïîëíåíèÿ äëÿ n = 4 áóäåò ðàâíî 522 ìèëëèîíà ñåêóíä (16 ñ ïîëîâèíîé ëåò), à äëÿ ôóíêöèè getMagicSquares' 34.7 òûñÿ÷è ñåêóíä (9 ñ ïîëîâèíîé ÷àñîâ). Ïîñëå ïîëó÷åíèÿ òàêîãî îïòèìèñòè÷åñêîãî ðåçóëüòàòà áûëî ðåøåíî ïðîâåðèòü òåîðåòè÷åñêèå âûêëàäêè íà ïðàêòèêå. Äëÿ ýòîãî íà íî÷ü áûëà çàïóùåíà ôóíêöèÿ getMagicSquares' ñ ïàðàìåòðîì 4. È ðåçóëüòàò
Äàëüíåéøàÿ óíèâåðñàëèçàöèÿ àëãîðèòìà
99
áûë ïîëó÷åí: ÷åðåç 10 ÷àñîâ áûëî ïîëó÷åíî 7040 ìàãè÷åñêèõ êâàäðàòîâ ðàçìåðà 4 × 4, ïåðâûé è ïîñëåäíèé èç êîòîðûõ ïðåäñòàâëåíû íèæå: 1 12 13 8
2 14 7 11
15 3 10 6
16 5 4 9
16 5 4 9
15 3 10 6
2 14 7 11
1 12 13 8
Êàê âèäíî, ýòè äâà êâàäðàòà ÿâëÿþòñÿ çåðêàëüíûì îòðàæåíèåì äðóã äðóãà. Äåéñòâèòåëüíî, àëãîðèòì ïîëó÷àåò âñå ìàãè÷åñêèå êâàäðàòû, â òîì ÷èñëå îòðàæ¼ííûå è ïîâ¼ðíóòûå. Êîëè÷åñòâî íåèçîìîðôíûõ äðóã äðóãó ìàãè÷åñêèõ êâàäðàòîâ, òàêèì îáðàçîì, íåîáõîäèìî ïîëó÷àòü, äåëÿ îáùåå èõ êîëè÷åñòâî íà 8. Äëÿ ðàçìåðà 4 × 4 ýòî êîëè÷åñòâî áóäåò ðàâíÿòüñÿ 880. È äåéñòâèòåëüíî, â 1930 ãîäó íåìåöêèé ìàòåìàòèê Ô. Ôèòòèíã òåîðåòè÷åñêè ðàññ÷èòàë êîëè÷åñòâî ìàãè÷åñêèõ êâàäðàòîâ ðàçìåðîì 4 × 4, êîòîðîå ïî åãî ðàñ÷¼òàì ðàâíî êàê ðàç 880. À åù¼ ðàíåå, â XVII âåêå ôðàíöóçñêèé ìàòåìàòèê Â. Ôðåíèêëü ïîñòðîèë (âðó÷íóþ) âñå âîçìîæíûå ìàãè÷åñêèå êâàäðàòû ðàçìåðà 4 × 4.
Äàëüíåéøàÿ óíèâåðñàëèçàöèÿ àëãîðèòìà Ïîëó÷åííûå ôóíêöèåé getMagicSquares' ðåçóëüòàòû âïå÷àòëÿþò. Îäíàêî ó íå¼ âñ¼ åù¼ îñòàþòñÿ íåäîðàáîòêè, êîòîðûå æåëàòåëüíî óñòðàíèòü. Íåäîðàáîòêè ýòè êàñàþòñÿ óæå áîëüøå èíòåðôåéñíîãî ïëàíà, íåæåëè îïòèìèçàöèè ïåðåáîðíîãî ïðîöåññà. Íàïðèìåð, âûâîä ìàãè÷åñêèõ êâàäðàòîâ íà ýêðàí îñòàâëÿåò æåëàòü ëó÷øåãî îíè ïðåäñòàâëÿþòñÿ â âèäå ñïèñêà, à ïîòîìó òàê è âûâîäÿòñÿ. Èíòåðïðåòèðîâàòü ðåçóëüòàòû î÷åíü ñëîæíî, ÷èòàòü ïîëó÷åííûå çàïèñè íåóäîáíî. Ñ äðóãîé ñòîðîíû, ïðåäñòàâëåííûé àëãîðèòì ðàáîòàåò òîëüêî ñ ÷èñëîâûìè ìàãè÷åñêèìè êâàäðàòàìè, õîòÿ â öåëÿõ ðàçâëå÷åíèÿ ìîæíî ïðèäóìàòü è íå÷èñëîâûå êâàäðàòû, à òàêæå ïðî÷èå ìàãè÷åñêèå ôèãóðû. Èç íå÷èñëîâûõ ìàãè÷åñêèõ êâàäðàòîâ, ê ïðèìåðó, ìîæíî ïðèâåñòè òàêîé, êîòîðûé äî ñèõ ïîð èñïîëüçóåòñÿ ðàçíûìè ëþäüìè â ¾ìàãè÷åñêèõ¿ öåëÿõ: S A T O R
A R E P O
T E N E T
O P E R A
R O T A S
êëàññ
Âîò è õîòåëîñü áû ñäåëàòü íåêîòîðûé èíòåðôåéñíûé , êîòîðûé îïèñûâàë áû ìåòîäû äëÿ ãåíåðàöèè ðàçëè÷íûõ êîìáèíàöèé è äàëüíåéøåé ïðîâåðêè èõ íà ¾ìàãè÷íîñòü¿. Ýòî ïîçâîëèò îïðåäåëÿòü äîïîëíèòåëüíûå òèïû äàííûõ è ðåàëèçîâûâàòü äëÿ íèõ ìåòîäû ãåíåðàöèè ìàãè÷åñêèõ ôèãóð. Îïèñàòü ñàì èíòåðôåéñíûé êëàññ äîñòàòî÷íî ïðîñòî (íåîáõîäèìîñòü ââåäåíèÿ èçîìîðôíîãî ñïèñêó òèïà MagicList äëÿ ïðåäñòàâëåíèÿ ñïèñêà ìàãè÷åñêèõ ôèãóð áóäåò îáúÿñíåíà ïîçæå):
newtype MagicList f = ML [ f ] c l a s s Magic f where getMagicFigures : : Int −> MagicList f isMagic : : f −> Bool
100
Ìàãè÷åñêèå êâàäðàòû è ðåøåíèå ïåðåáîðíûõ çàäà÷
Êàê âèäíî, ýòîò êëàññ îïèñûâàåò äâà ìåòîäà: äëÿ ãåíåðàöèè ñïèñêà ìàãè÷åñêèõ ôèãóð (getMagicFigures) è äëÿ ïðîâåðêè íåêîé êîìáèíàöèè íà ¾ìàãè÷íîñòü¿ (isMagic). Òåïåðü îñòà¼òñÿ îïðåäåëèòü íîâûå (ÀÒÄ), ïðè ïîìîùè êîòîðûõ ïðåäñòàâëÿòü â ïàìÿòè ñàìè ìàãè÷åñêèå ôèãóðû. Ñïèñîê â ýòîì äåëå òàêæå ìîæåò ïîìî÷ü, íî ìîæíî ñäåëàòü è áîëåå èíòåðåñíûå ñïîñîáû ïðåäñòàâëåíèÿ, êîòîðûå ïîìîãóò â òîì ÷èñëå îïòèìèçèðîâàòü âû÷èñëèòåëüíûå ïðîöåññû. Ñîáñòâåííî, èçó÷åííûå óæå ÷èñëîâûå ìàãè÷åñêèå êâàäðàòû ìîæíî ïðåäñòàâëÿòü ñïèñêîì, íî äîáàâèòü ê íåìó äîïîëíèòåëüíîå ïîëå â âèäå ðàçìåðà êâàäðàòà, ÷òîáû íå çàíèìàòüñÿ ïîñòîÿííîé ïåðåäà÷åé ýòîãî ïàðàìåòðà èç ôóíêöèè â ôóíêöèþ. Ýòî äåëàåòñÿ ïðè ïîìîùè òàêîãî îïðåäåëåíèÿ:
àëãåáðàè÷åñêèå òèïû äàííûõ
data Square a = Square { dimension : : Int , values :: [a] } Òóò âèäíî, ÷òî äàííûé ÀÒÄ ìîæíî èñïîëüçîâàòü äëÿ ïðåäñòàâëåíèÿ ëþáûõ êâàäðàòîâ. ×òîáû åãî èñïîëüçîâàòü, íåîáõîäèìî îïèñàòü ýêçåìïëÿð êëàññà Magic äëÿ ýòîãî ÀÒÄ. Òàê êàê ïîêà èññëåäóþòñÿ òîëüêî ÷èñëîâûå ìàãè÷åñêèå êâàäðàòû, äà è íåâîçìîæíî ñäåëàòü îáùåå ïðàâèëî äëÿ ïðîâåðêè ¾ìàãè÷íîñòè¿ ÷èñëîâûõ è íå÷èñëîâûõ êâàäðàòîâ, ýêçåìïëÿð êëàññà áóäåò íåñêîëüêî ñóæåííûì:
instance Magic ( Square Int ) where getMagicFigures d = ML [ sq | sq <− constructSquares d [ 1 . . ( d ^ 2 ) ] , isMagic sq ] isMagic ( Square d v ) = i f ( d ^2 /= length v ) then False el se ( testH ms d v ) && ( testV ms d v ) && ( testD ms d v ) where ms = magicSum d Êàê âèäíî, çäåñü èñïîëüçîâàíû ñòàðûå âñïîìîãàòåëüíûå ôóíêöèè äëÿ ãåíåðàöèè êîìáèíàöèé, à òàêæå äëÿ ïðîâåðêè ¾ìàãè÷íîñòè¿ ïî ãîðèçîíòàëÿì, âåðòèêàëÿì è äèàãîíàëÿì.  ýòîì íåò íè÷åãî çàçîðíîãî. Íî áîëüøå âñåãî âûçûâàåò èíòåðåñ îïðåäåëåíèå äëÿ ýòîãî ÀÒÄ ýêçåìïëÿðà ñòàíäàðòíîãî êëàññà Show, ìåòîäû êîòîðîãî èñïîëüçóþòñÿ äëÿ âûâîäà çíà÷åíèé òèïîâ íà ýêðàí (è â ôàéëû). Õîòåëîñü áû, ÷òîáû íà ýêðàíå êâàäðàòû âûãëÿäåëè èìåííî êâàäðàòàìè, à íå íåâçðà÷íûìè ñïèñêàìè ÷èñåë. Äà è ñïèñîê êâàäðàòîâ òîæå íàäî áû ïðèóêðàñèòü, à èìåííî âûâîäèòü êâàäðàòû îäèí çà äðóãèì ñ îòäåëåíèåì äðóã îò äðóãà ïóñòîé ñòðîêîé. Äëÿ ýòîãî è íåîáõîäèì èçîìîðôíûé òèï MagicList åãî òàêæå íåîáõîäèìî ñäåëàòü ýêçåìïëÿðîì êëàññà Show (â ñëó÷àå, åñëè áû íå áûëî îïðåäåëåíèÿ òàêîãî òèïà, íåâîçìîæíî áûëî áû ïåðåîïðåäåëèòü ñïîñîá âûâîäà ñïèñêà ìàãè÷åñêèõ ôèãóð íà ýêðàí). Òàêèå ýêçåìïëÿðû îïðåäåëÿþòñÿ ñëåäóþùèì îáðàçîì:
instance Show a =>
Show ( Square a ) where show ( Square d v ) = i f ( null v ) then "+" ++ ( showLine d ) el se "+" ++ ( showLine d ) ++ "\ n | " ++ showRow ( take d v ) ++
Äàëüíåéøàÿ óíèâåðñàëèçàöèÿ àëãîðèòìà
101
"\ n " ++ show ( Square d ( drop d v ) ) = "" showRow ( x : xs ) = ( showCell x ) ++ ( showRow xs )
where showRow [ ]
showCell x = " " ++ ( replicate ( nLength d2 − nLength x ) ' ' ) ++ ( show x ) ++ " | " showLine 0 = "" showLine i = "−" ++ ( replicate ( nLength d2 ) ' − ') ++ "−+" ++ ( showLine ( i − 1 ) ) nLength x = length $ show x d2 = d ^2
instance Show a =>
Show ( MagicList ( Square a ) ) where show ( ML [ ] ) = "" show ( ML ( x : xs ) ) = show x ++ "\ n \ n " ++ show ( ML xs )
Íå ñòîèò ïóãàòüñÿ ñòîëü íåïðîñòûõ íà ïåðâûé âçãëÿä îïðåäåëåíèé. Âñå ýòè ôóíêöèè íàïðàâëåíû ëèøü íà òî, ÷òîáû âûâîäèòü ÷èñëîâûå ìàãè÷åñêèå êâàäðàòû â ÷èòàáåëüíîì âèäå. Íàïðèìåð, îäèí èç ìàãè÷åñêèõ êâàäðàòîâ ðàçìåðà 5 × 5, ïîëó÷åííûé â ïðîöåññå ðàáîòû íàä ðàçäåëîì, áûë âûâåäåí ýòèìè ôóíêöèÿìè â òàêîì âèäå: +−−−−+−−−−+−−−−+−−−−+−−−−+ | 3 | 16 | 9 | 22 | 15 | +−−−−+−−−−+−−−−+−−−−+−−−−+ | 20 | 8 | 21 | 14 | 2 | +−−−−+−−−−+−−−−+−−−−+−−−−+ | 7 | 25 | 13 | 1 | 19 | +−−−−+−−−−+−−−−+−−−−+−−−−+ | 24 | 12 | 5 | 18 | 6 | +−−−−+−−−−+−−−−+−−−−+−−−−+ | 11 | 4 | 17 | 10 | 23 | +−−−−+−−−−+−−−−+−−−−+−−−−+ Îñòà¼òñÿ îòìåòèòü, ÷òî âûçûâàòü íîâóþ ôóíêöèþ getMagicFigures òàê ïðîñòî óæå íå ïîëó÷èòñÿ, òàê êàê òðàíñëÿòîð ÿçûêà Haskell íå ñìîæåò àâòîìàòè÷åñêè îïðåäåëèòü òèï âîçâðàùàåìîãî ðåçóëüòàòà, ÷òîáû âûáðàòü òðåáóåìûé ýêçåìïëÿð êëàññà Magic. Ïîýòîìó òèï íåîáõîäèìî â äàííîì ñëó÷àå óêàçûâàòü ÿâíî:
main : : Int −> IO ( )
102
Ìàãè÷åñêèå êâàäðàòû è ðåøåíèå ïåðåáîðíûõ çàäà÷
main d = print ( getMagicFigures d : : MagicList ( Square Int ) ) Ýòî íåáîëüøàÿ ïëàòà çà áîëüøóþ óíèâåðñàëüíîñòü â ïðåäñòàâëåíèè.
Çàêëþ÷åíèå Äàëüíåéøàÿ ðàáîòà íàä óñîâåðøåíñòâîâàíèåì ïåðåáîðíîãî àëãîðèòìà ìîæåò ïðèíåñòè îùóòèìûå ðåçóëüòàòû. Âåäü â ýòîì íåáîëüøîì ðàçäåëå íàìå÷åí òîëüêî ïóòü, ïî êîòîðîìó ìîæíî äâèãàòüñÿ. Çäåñü ïîêàçàíû íåêîòîðûå èç ïðèíöèïîâ îïòèìèçàöèè ïðîãðàìì íà ôóíêöèîíàëüíûõ ÿçûêàõ ïðîãðàììèðîâàíèÿ. Íî â ñëó÷àå íåîáõîäèìîñòè äàëåå íàäî äâèãàòüñÿ ñàìîñòîÿòåëüíî. Íàïðèìåð, ìîæíî åù¼ áîëüøå ïîðàáîòàòü íàä ïðåäñòàâëåíèåì ìàãè÷åñêèõ êâàäðàòîâ, ÷òîáû ñäåëàòü ôóíêöèè test∗ áîëåå ïðîñòûìè. Ýòîãî ìîæíî äîáèòüñÿ ïðè ïîìîùè ÿâíîãî õðàíåíèÿ ïîçèöèè ÷èñëà â ñàìîì ìàãè÷åñêîì êâàäðàòå. Ýòî óâåëè÷èò êîëè÷åñòâî çàíèìàåìîé ïàìÿòè, íî äîñòàòî÷íî ñèëüíî óñêîðèò ïðîöåññû ïðîâåðêè íà ¾ìàãè÷íîñòü¿ ãîðèçîíòàëåé, âåðòèêàëåé è äèàãîíàëåé, òàê êàê îòïàä¼ò íåîáõîäèìîñòü ïåðåáèðàòü ñïèñêè ïðè ïîìîùè îïåðàòîðà ( !! ). Òàêæå íåîáõîäèìî ïîðàáîòàòü íàä ñàìèì àëãîðèòìîì ïåðåáîðà, òàê êàê îí åù¼ âåñüìà äàë¼ê îò ñîâåðøåíñòâà (íàïðèìåð, îöåíêà âðåìåíè, íåîáõîäèìîãî äëÿ âû÷èñëåíèÿ âñåõ ìàãè÷åñêèõ êâàäðàòîâ ðàçìåðà 5 × 5, ïîêàçàëà, ÷òî âû÷èñëåíèå èõ ïðè ïîìîùè ôóíêöèè getMagicSquares çàéì¼ò ïî÷òè 17 òûñÿ÷åëåòèé, à ïðè ïîìîùè ôóíêöèè getMagicSquares' 24 äíÿ).  ýòîì äåëå ïîìîæåò òàêæå âíåäðåíèå â îïðåäåëåíèÿ ôóíêöèé âîçìîæíîñòè îñóùåñòâëÿòü ïîèñê ìàãè÷åñêèõ êâàäðàòîâ, íà÷èíàÿ ñ îïðåäåë¼ííîé êîìáèíàöèè. Ýòî ïîçâîëèò ðàñïðåäåëèòü óñèëèÿ ïî ïîèñêó ìàãè÷åñêèõ ôèãóð êàê âî âðåìåíè, òàê è â ïðîñòðàíñòâå (çàäåéñòâîâàâ, ê ïðèìåðó, íåñêîëüêî êîìïüþòåðîâ, êîòîðûå áóäóò ðàáîòàòü â íî÷íîå âðåìÿ). Òàê ÷òî âîçìîæíîñòåé äëÿ ñàìîñòîÿòåëüíîãî òâîð÷åñòâà â ýòîì íàïðàâëåíèè òüìà. Äåðçàéòå!
Çàäà÷à î ðàíöå Ñòàòüÿ áûëà îïóáëèêîâàíà â 09 (57) æóðíàëà ¾Ïîòåíöèàë¿ â ñåíòÿáðå 2009 ãîäà.
 ýññå ïðåäëàãàåòñÿ ðàññìîòðåíèå îäíîé èç êëàññè÷åñêèõ îïòèìèçàöèîííûõ çàäà÷ çàäà÷à î ðàíöå. Äàþòñÿ ìàòåìàòè÷åñêàÿ ôîðìóëèðîâêà çàäà÷è è å¼ ðåøåíèÿ, ïðåäëàãàåòñÿ ðåàëèçàöèÿ ýòîãî ðåøåíèÿ íà ôóíêöèîíàëüíîì ÿçûêå ïðîãðàììèðîâàíèÿ Haskell, à òàêæå ðàññìàòðèâàåòñÿ ïðèìåð èñïîëüçîâàíèÿ ðàçðàáîòàííîé îáîáù¼ííîé ôóíêöèè äëÿ ïîèñêà ðåøåíèÿ êîíêðåòíîé ïðîáëåìû.
Ââåäåíèå Íàó÷íî-òåõíè÷åñêèé ïðîãðåññ è ðàçâèòèå ìåòîäîâ ïðèêëàäíîé ìàòåìàòèêè äàëè íà÷àëî íîâîé äèñöèïëèíå, êîòîðàÿ çàíèìàåòñÿ ðàçðàáîòêîé è ïðèìåíåíèåì ìåòîäîâ íàõîæäåíèÿ îïòèìàëüíûõ ðåøåíèé íà îñíîâå ìàòåìàòè÷åñêîãî è ñòàòèñòè÷åñêîãî ìîäåëèðîâàíèÿ è ðàçëè÷íûõ ýâðèñòè÷åñêèõ òåõíèê â ðàçëè÷íûõ îáëàñòÿõ ÷åëîâå÷åñêîé äåÿòåëüíîñòè. Äàííàÿ äèñöèïëèíà ïîëó÷èëà íàçâàíèå ¾èññëåäîâàíèå îïåðàöèé¿ (â ðîññèéñêèõ âûñøèõ ó÷åáíûõ çàâåäåíèÿõ ìîæåò ïðåïîäàâàòüñÿ ïîä íàçâàíèåì ¾ìåòîäû îïòèìèçàöèè¿ èëè ñõîæèìè). Îñîáûé òîë÷îê ê ðàçâèòèþ ìåòîäîâ îïòèìèçàöèè äàëà Âòîðàÿ ìèðîâàÿ âîéíà. Âî âðåìÿ íå¼ èññëåäîâàíèå îïåðàöèé ñòàëî øèðîêî ïðèìåíÿòüñÿ äëÿ ïëàíèðîâàíèÿ áîåâûõ äåéñòâèé. Íàïðèìåð, äëÿ Âîåííî-âîçäóøíûõ ñèë ñîþçíèêîâ ó÷¼íûìè áûëè âûðàáîòàíû ðåêîìåíäàöèè, êîòîðûå ïîçâîëèëè óâåëè÷èòü ýôôåêòèâíîñòü áîìáîìåòàíèÿ â ÷åòûðå ðàçà. Ïîñëå âîéíû ãðóïïû ñïåöèàëèñòîâ ïî èññëåäîâàíèþ îïåðàöèé ïðîäîëæèëè ñâîþ ðàáîòó â âîîðóæ¼ííûõ ñèëàõ ÑØÀ è Âåëèêîáðèòàíèè. Ïóáëèêàöèÿ ðÿäà ðåçóëüòàòîâ â îòêðûòîé ïå÷àòè âûçâàëà âñïëåñê îáùåñòâåííîãî èíòåðåñà ê ýòîìó íàó÷íîìó íàïðàâëåíèþ. Âîçíèêëà òåíäåíöèÿ ê ïðèìåíåíèþ ìåòîäîâ èññëåäîâàíèÿ îïåðàöèé â êîììåð÷åñêîé äåÿòåëüíîñòè, â öåëÿõ ðåîðãàíèçàöèè ïðîèçâîäñòâà, ïåðåâîäà ïðîìûøëåííîñòè íà ìèðíûå ðåëüñû.  ÑÑÑÐ èññëåäîâàíèå îïåðàöèé òàêæå ïîëó÷èëî øèðîêîå ðàñïðîñòðàíåíèå (âïëîòü äî òîãî, ÷òî ñîâåòñêèé ìàòåìàòèê è ýêîíîìèñò Ë. Â. Êàíòîðîâè÷ ïîëó÷èë â 1975 ãîäó Íîáåëåâñêóþ ïðåìèþ ïî ýêîíîìèêå çà âêëàä â òåîðèþ îïòèìàëüíîãî ðàñïðåäåëåíèÿ ðåñóðñîâ). Õàðàêòåðíûìè îñîáåííîñòÿìè èññëåäîâàíèÿ îïåðàöèé ÿâëÿþòñÿ ñèñòåìíûé ïîäõîä ê ïîñòàâëåííîé ïðîáëåìå è àíàëèç. Ñèñòåìíûé ïîäõîä ÿâëÿåòñÿ ãëàâíûì ìåòîäîëîãè÷åñêèì ïðèíöèïîì èññëåäîâàíèÿ îïåðàöèé. Ëþáàÿ çàäà÷à, êîòîðàÿ ðåøàåòñÿ, äîëæíà ðàññìàòðèâàòüñÿ ñ òî÷êè çðåíèÿ âëèÿíèÿ ôóíêöèîíèðîâàíèÿ ñèñòåìû â öåëîì. Äëÿ èññëåäîâàíèÿ îïåðàöèé õàðàêòåðíî òî, ÷òî ïðè ðåøåíèè êàæäîé ïðîáëåìû ìîãóò âîçíèêàòü íîâûå çàäà÷è. Âàæíîé îñîáåííîñòüþ èññëåäîâàíèÿ îïåðàöèé åñòü ñòðåìëåíèå íàéòè îïòèìàëüíîå ðåøåíèå ïîñòàâëåííîé çàäà÷è (ïðèíöèï ¾îïòèìàëüíîñòè¿). Îäíàêî íà ïðàêòèêå òàêîå ðåøåíèå ÷àñòî áûâàåò íåâîçìîæíî íàéòè ïî ñëåäóþùèì ïðè÷èíàì: 1) îòñóòñòâèå ìåòîäîâ, äàþùèõ âîçìîæíîñòü íàéòè ãëîáàëüíîå îïòèìàëüíîå ðåøåíèå çàäà÷è; 2) îãðàíè÷åííîñòü ñóùåñòâóþùèõ ðåñóðñîâ (ê ïðèìåðó, îãðàíè÷åííîñòü ìàøèííîãî âðåìåíè ÝÂÌ), ÷òî äåëàåò íåâîçìîæíûì ðåàëèçàöèþ òî÷íûõ ìåòîäîâ îïòèìèçàöèè.
104
Çàäà÷à î ðàíöå
 òàêèõ ñëó÷àÿõ îáû÷íî îãðàíè÷èâàþòñÿ ïîèñêîì íå îïòèìàëüíûõ, à äîñòàòî÷íî õîðîøèõ ñ òî÷êè çðåíèÿ ïðàêòèêè ðåøåíèé. Ïðèõîäèòñÿ èñêàòü êîìïðîìèññ ìåæäó ýôôåêòèâíîñòüþ ðåøåíèé è çàòðàòàìè íà èõ ïîèñê. Èññëåäîâàíèå îïåðàöèé äà¼ò èíñòðóìåíò äëÿ ïîèñêà òàêèõ êîìïðîìèññîâ. Èññëåäîâàíèå îïåðàöèé òåñíî ñâÿçàíî ñ òåîðèåé óïðàâëåíèÿ, ñèñòåìíûì àíàëèçîì, ìàòåìàòè÷åñêèì ïðîãðàììèðîâàíèåì, òåîðèåé èãð, òåîðèåé îïòèìàëüíûõ ðåøåíèé, ýâðèñòè÷åñêèìè ïîäõîäàìè è ìåòîäàìè èñêóññòâåííîãî èíòåëëåêòà.  êà÷åñòâå êàíîíè÷åñêèõ çàäà÷, êîòîðûå ðåøàþòñÿ ìåòîäàìè îïòèìèçàöèè, ìîæíî îòìåòèòü çàäà÷ó êîììèâîÿæ¼ðà, òðàíñïîðòíóþ çàäà÷ó, çàäà÷ó îá óïàêîâêå â êîíòåéíåðû, çàäà÷ó î ðàíöå è äð. Î ïîñëåäíåé êàê ðàç è ïîéä¼ò ðå÷ü â íàñòîÿùåì ðàçäåëå.
Êëàññè÷åñêàÿ çàäà÷à Çàäà÷à î ðàíöå (áûâàåò, ÷òî ãîâîðÿò ¾çàäà÷à î ðþêçàêå¿) ÿâëÿåòñÿ êëàññè÷åñêîé çàäà÷åé èññëåäîâàíèÿ îïåðàöèé è êîìáèíàòîðíîé îïòèìèçàöèè. Çàäà÷à ïîëó÷èëà ñâî¼ íàçâàíèå îò ìàêñèìèçàöèîííîé ïðîáëåìû óêëàäêè êàê ìîæíî áîëüøåãî ÷èñëà âåùåé â ðþêçàê (ðàíåö) ïðè óñëîâèè, ÷òî îáùèé îáú¼ì (èëè âåñ) âñåõ ïðåäìåòîâ . Ïîäîáíûå çàäà÷è ÷àñòî âîçíèêàþò â ïðèêëàäíîé ìàòåìàòèêå, ýêîíîìèêå, êðèïòîãðàôèè.  îáùåì âèäå çàäà÷ó ìîæíî ñôîðìóëèðîâàòü òàê: èç íåîãðàíè÷åííîãî (èëè îãðàíè÷åííîãî) ìíîæåñòâà ïðåäìåòîâ ñî ñâîéñòâàìè ¾ñòîèìîñòü¿ è ¾âåñ¿ òðåáóåòñÿ îòîáðàòü íåêîå ÷èñëî ïðåäìåòîâ òàêèì îáðàçîì, ÷òîáû ïîëó÷èòü ìàêñèìàëüíóþ ñóììàðíóþ ñòîèìîñòü ïðè îäíîâðåìåííîì ñîáëþäåíèè îãðàíè÷åíèÿ íà ñóììàðíûé âåñ. Ñàìî ñîáîé ðàçóìååòñÿ, ÷òî ê äàííîé êëàññè÷åñêîé ôîðìóëèðîâêå çàäà÷è ìîãóò ñâîäèòüñÿ ìíîãèå èíûå çàäà÷è ðàçíûõ ðàçìåðíîñòåé.  êà÷åñòâå ñòîèìîñòè è âåñà ìîãóò èñïîëüçîâàòüñÿ ñîâåðøåííî ðàçëè÷íûå õàðàêòåðèñòèêè è äàæå èõ êîìáèíàöèè.  ýòîì âîïðîñå íåîáõîäèìî ëèøü íàëè÷èå íåêîòîðîãî ïðåîáðàçîâàíèÿ (ôóíêöèè), êîòîðàÿ ïîâîëèò ñâåñòè òðåáóåìóþ çàäà÷ó ê êëàññè÷åñêîé.  ïðèíöèïå, ñóùåñòâóþò äâå ôîðìóëèðîâêè êëàññè÷åñêîé çàäà÷è î ðàíöå:
îãðàíè÷åí
íóæíûõ
1) êàæäûé ïðåäìåò èç ìíîæåñòâà ìîæíî âûáèðàòü íåîãðàíè÷åííîå êîëè÷åñòâî ðàç (ïîêà åñòü âîçìîæíîñòü óäîâëåòâîðÿòü îãðàíè÷åíèå íà âåñ); 2) êàæäûé ïðåäìåò ìîæíî èñïîëüçîâàòü òîëüêî îäèí ðàç. Ñàìà ïî ñåáå çàäà÷à î ðàíöå ÿâëÿåòñÿ NP-ïîëíîé çàäà÷åé, òî åñòü òàêîé, âðåìÿ ðàáîòû àëãîðèòìà äëÿ ðåøåíèÿ êîòîðîé ñóùåñòâåííî çàâèñèò îò ðàçìåðà âõîäíûõ äàííûõ, ïðè ýòîì åñëè ïðåäîñòàâèòü àëãîðèòìó íåêîòîðûå äîïîëíèòåëüíûå ñâåäåíèÿ, òî îí ñìîæåò çà âðåìÿ, íå ïðåâîñõîäÿùåå íåêîòîðîãî ìíîãî÷ëåíà îò ðàçìåðà âõîäíûõ äàííûõ, ðåøèòü çàäà÷ó. Äîïîëíèòåëüíûå ñâåäåíèÿ â äàííîì ñëó÷àå íàçûâàþòñÿ ¾ñâèäåòåëåì ðåøåíèÿ¿.  ñâîþ î÷åðåäü, ýòî îáîçíà÷àåò, ÷òî çàäà÷ó ìîæíî ðåøèòü ïðè ïîìîùè ìåòîäîâ äèíàìè÷åñêîãî ïðîãðàììèðîâàíèÿ. Äàííûé ðàçäåë èññëåäîâàíèÿ îïåðàöèé ïîçâîëÿåò ðåøàòü çàäà÷è ñ îïòèìàëüíîé ñòðóêòóðîé è ïåðåêðûâàþùèìèñÿ ïîäçàäà÷àìè, ïðè ýòîì ìåòîä ðåøåíèÿ îñíîâàí íà ïîñòåïåííîì ðåøåíèè çàäà÷è ïîñðåäñòâîì âûâîäà ðåøåíèÿ ÷åðåç óæå ðåø¼ííûå ïîäçàäà÷è. Ñëîâî ¾ïðîãðàììèðîâàíèå¿ â íàèìåíîâàíèè äèñöèïëèíû íå èìååò íè÷åãî îáùåãî ñ íàïèñàíèåì êîäà, ïîñêîëüêó îáîçíà÷àåò îïòèìàëüíóþ ïîñëåäîâàòåëüíîñòü äåéñòâèé äëÿ ïîèñêà ðåøåíèÿ çàäà÷è (ìîæíî ñðàâíèòü ñ òàêèìè òåðìèíàìè, êàê ¾ëèíåéíîå ïðîãðàììèðîâàíèå¿, ¾ìàòåìàòè÷åñêîå ïðîãðàììèðîâàíèå¿). Èòàê, ôîðìóëèðîâêà çàäà÷è î ðàíöå ñ âîçìîæíîñòüþ íåîãðàíè÷åííîãî âûáîðà çâó÷èò òàê. Ïî çàäàííîìó íàáîðó èç n ïðåäìåòîâ ñî ñòîèìîñòÿìè v1 , v2 , . . . , vn è âåñàìè w1 , w2 , . . . , wn íåîáõîäèìî íàéòè òàêîé ïîäíàáîð (ñ ó÷¼òîì òîãî, ÷òî ìîæíî áðàòü ëþáîé ïðåäìåò íåîãðàíè÷åííîå ÷èñëî ðàç), ÷òî åãî ñòîèìîñòü áóäåò ìàêñèìàëüíà ñðåäè âñåõ ïîäíàáîðîâ ñ îáùèì âåñîì íå áîëåå W . Ðåøåíèå òàêîé çàäà÷è íåñëîæíî. Ïóñòü Kw ìàêñèìàëüíàÿ ñòîèìîñòü, êîòîðóþ ìîæíî íàáðàòü ïðè âåñå íå áîëåå w. Ñëåäóþùåå ðåêóððåíòíîå ñîîòíîøåíèå ïîçâîëÿåò íàéòè ðåøåíèå:
Ðåàëèçàöèÿ ðåøåíèÿ íà ÿçûêå Haskell
105
1) K0 = 0 (ïðè âåñå íå áîëåå 0 ìàêñèìàëüíàÿ ñòîèìîñòü ðàâíà 0) áàçèñ ðåêóðñèè; 2) Kw = max{Kw−wi + vi }ni=1 , wi 6 w, ãäå n ðàçìåð íàáîðà øàã ðåêóðñèè. Ñ äðóãîé ñòîðîíû, çàäà÷à î ðàíöå ñ âîçìîæíîñòüþ èñïîëüçîâàòü ëþáîé ïðåäìåò èç íàáîðà íå áîëåå îäíîãî ðàçà ôîðìóëèðóåòñÿ ñëåäóþùèì îáðàçîì. Ïóñòü Kw,i ìàêñèìàëüíàÿ ñòîèìîñòü, êîòîðóþ ìîæíî íàáðàòü ïðè âåñå íå áîëåå w ñðåäè i ïåðâûõ ïðåäìåòîâ. Ñëåäóþùåå ðåêóððåíòíîå ñîîòíîøåíèå íàõîäèò ðåøåíèå: 1) K0,i = 0, 0 6 i 6 n; 2) Kw,0 = 0, 0 6 w 6 W ; 3) Kw,i = max{Kw,i−1 , Kw−wi ,i−1 + vi }, 0 6 w 6 W, wi 6 w; 4) Kw,i = Kw,i−1 , åñëè wi > w (íåâîîçìîæíî äîáàâèòü ýëåìåíò ýòîãî âåñà). Ñîáñòâåííî, íà ñëåäóþùåì ðèñóíêå èäåîãðàôè÷åñêè ïðîèëëþñòðèðîâàíà òàêàÿ çàäà÷à.
Ðèñ. 5. Èëëþñòðàöèÿ çàäà÷è î ðàíöå èñõîäíûå äàííûå
Ðåàëèçàöèÿ ðåøåíèÿ íà ÿçûêå Haskell Êëàññè÷åñêàÿ ìàòåìàòè÷åñêàÿ çàäà÷à òàê è áóäåò îñòàâàòüñÿ ¾èíòåðåñíîé àáñòðàêöèåé¿, åñëè íå ðåàëèçîâàòü àëãîðèòì äëÿ ðåøåíèÿ, ÷òî íàçûâàåòñÿ, â êîäå. Êàê îáû÷íî, äëÿ èëëþñòðàöèè ìåòîäîâ ðåøåíèÿ îïèñàííîé çàäà÷è ìîæíî âîñïîëüçîâàòüñÿ ôóíêöèîíàëüíûì ïîäõîäîì è ðåàëèçîâàòü âîçìîæíûé àëãîðèòì íà ÿçûêå ïðîãðàììèðîâàíèÿ Haskell. Ðåàëèçàöèþ àëãîðèòìà íåîáõîäèìî íà÷àòü ñ íåáîëüøîãî ïðîåêòèðîâàíèÿ òåõ ïðîãðàììíûõ ñóùíîñòåé, êîòîðûå äîëæíû áûòü îïðåäåëåíû â ïðîãðàììå. Äåëî â òîì, ÷òî ìàòåìàòè÷åñêîå îïèñàíèå çàäà÷è ãîâîðèò î ïðîèçâîëüíûõ îáúåêòàõ, êîòîðûå ìîãóò ôèãóðèðîâàòü â ïðîöåññå óïàêîâêè â ðàíåö. Äëÿ òàêèõ îáúåêòîâ íåîáõîäèìî èìåòü äâå îïåðàöèè ïîëó÷åíèå ñòîèìîñòè è ïîëó÷åíèå âåñà. Íà îñíîâàíèè ýòèõ îïåðàöèé ìîæíî ïðîèçâåñòè âû÷èñëåíèÿ è íàéòè ðåøåíèå.
106
Çàäà÷à î ðàíöå
Èòàê, ÿçûê Haskell èìååò ìåõàíèçì äëÿ àáñòðàêöèè ïîäîáíûõ òðåáîâàíèé ýòî êëàññû, îïèñûâàþùèå íåîáõîäèìûå ìåòîäû (ïîäðîáíî î êëàññàõ â ÿçûêå Haskell ìîæíî îçíàêîìèòüñÿ â ðàçäåëå ¾Îáúåêòíîîðèåíòèðîâàííîå è ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå¿, ñòð. 30). Òàê ÷òî îïèñàòü êëàññ äëÿ îáúåêòîâ, êîòîðûå ìîãóò áûòü óïàêîâàíû â ðàíåö, ìîæíî òàê:
c l a s s KnapsackItem a where cost : : a −> Integer weight : : a −> Integer Ëþáîé òèï äàííûõ, èìåþùèé ýêçåìïëÿð êëàññà KnapsackItem, ìîæíî áóäåò èñïîëüçîâàòü â ôóíêöèÿõ, êîòîðûå ïðîèçâîäÿò ïîèñê ðåøåíèÿ â çàäà÷å î ðàíöå. Êîíå÷íî, è ñîîòâåòñòâóþùèå ôóíêöèè íåîáõîäèìî ðåàëèçîâàòü ñ ó÷¼òîì ýòîãî òðåáîâàíèÿ. Íî ýòî áóäåò ñäåëàòü óæå ñîâñåì íåñëîæíî.  îïðåäåëåíèè óêàçàííîãî êëàññà èìååòñÿ îäíà òîíêîñòü. Ôóíêöèè cost (¾ñòîèìîñòü¿) è weight (¾âåñ¿) âîçâðàùàþò öåëîå ÷èñëî íåîãðàíè÷åííîãî ðàçìåðà.  êëàññè÷åñêîé ôîðìóëèðîâêå çàäà÷è íè÷åãî íå ãîâîðèòñÿ î òèïå ñâîéñòâ ¾ñòîèìîñòü¿ è ¾âåñ¿, à ïîòîìó èõ òèïàìè ìîãóò áûòü öåëûå ÷èñëà, äåéñòâèòåëüíûå ÷èñëà, äà è âîîáùå ïðîèçâîëüíûå òèïû, äëÿ êîòîðûõ îïðåäåëåíû íåêîòîðûå îïåðàöèè: äëÿ ñòîèìîñòè ñëîæåíèå, äëÿ âåñà ñðàâíåíèå (ýòî ñëåäóåò èç ôîðìóë ðåøåíèÿ çàäà÷è, ïðåäñòàâëåííûõ â ïðåäûäóùåì ðàçäåëå). Ê ñîæàëåíèþ, íå òàê ïðîñòî ðåàëèçîâàòü äàííóþ âîçìîæíîñòü íà ÿçûêå Haskell, ïîñêîëüêó ñòàíäàðò ÿçûêà Haskell-98 íå ïîçâîëÿåò ñäåëàòü ýòî óäîáíûì ñïîñîáîì. Òåì íå ìåíåå íåêîòîðûå ðàñøèðåíèÿ ÿçûêà äàþò âîçìîæíîñòü íàïèñàòü íå ìåíåå ýôôåêòèâíîå îïðåäåëåíèå. Íàïðèìåð:
c l a s s KnapsackItem a where cost : : Num b => a −> b weight : : Ord b => a −> b Èëè:
c l a s s Num b => KnapsackItem a b where cost : : a −> b weight : : a −> b  ïåðâîì èç ýòèõ ñëó÷àÿõ â ñèãíàòóðû ìåòîäîâ ââîäÿòñÿ îãðàíè÷åíèÿ íà òèïû âîçâðàùàåìûõ çíà÷åíèé (ïðè ýòîì ìåòîäû ìîãóò âîîáùå âîçâðàùàòü çíà÷åíèÿ ðàçëè÷íûõ òèïîâ îäèíàêîâîå îáîçíà÷åíèå b íå äîëæíî ñìóùàòü). Ìåòîä cost äîëæåí âîçâðàùàòü çíà÷åíèå, íàä êîòîðûì ìîæíî ïðîèçâîäèòü àðèôìåòè÷åñêèå îïåðàöèè (êëàññ Num). Ñîîòâåòñòâåííî, ìåòîä weight âîçâðàùàåò çíà÷åíèå, êîòîðîå ìîæíî ñðàâíèâàòü (êëàññ Ord). Íî ñòàíäàðò Haskell-98 íå ðàçðåøàåò ââîäèòü îãðàíè÷åíèÿ íà òèïû â ñèãíàòóðû ìåòîäîâ, îãðàíè÷åíèå ìîæåò áûòü òîëüêî íà ïàðàìåòðè÷åñêóþ ïåðåìåííóþ êëàññà. Âî âòîðîì ñëó÷àå êëàññ KnapsackItem ïàðàìåòðèçóåò äâà òèïà, ïðè÷¼ì íà âòîðîé íàëîæåíî îãðàíè÷åíèå îí äîëæåí èìåòü ýêçåìïëÿð êëàññà Num (÷òî àâòîìàòè÷åñêè âëå÷¼ò íàëè÷èå ýêçåìïëÿðà êëàññà Ord). Íî îïÿòü æå ñòàíäàðò Haskell-98 íå ðàçðåøàåò èñïîëüçîâàòü ìíîãîïàðàìåòðè÷åñêèå êëàññû. Ýòî âîçìîæíî òîëüêî â ðàñøèðåíèÿõ êîìïèëÿòîðà GHC. Èñïîëüçîâàíèå ëþáîãî èç óêàçàííûõ ïîäõîäîâ âëå÷¼ò íåîáõîäèìîñòü íå òîëüêî ïîäêëþ÷åíèÿ òîãî èëè èíîãî ðàñøèðåíèÿ ÿçûêà Haskell, íî è äîïîëíèòåëüíîãî óäîâëåòâîðåíèÿ òðåáîâàíèé ïðè íàïèñàíèè ôóíêöèé. Òàêèì îáðàçîì, èçíà÷àëüíîå îïðåäåëåíèå êëàññà ïîä÷èíÿåòñÿ ñòàíäàðòó, íî âìåñòå òåì ïîçâîëÿåò íàïèñàòü ïðîñòûå è ïîíÿòíûå ôóíêöèè. Òàêæå ýòî îïðåäåëåíèå êëàññà KnapsackItem âïîëíå äîñòàòî÷íî è íå ñêàçûâàåòñÿ íà îáùíîñòè ðàññóæäåíèé ïðè ðåøåíèè çàäà÷. Òåïåðü ìîæíî ðåàëèçîâàòü íåïîñðåäñòâåííóþ ôóíêöèþ, êîòîðàÿ áóäåò ïðîèçâîäèòü ïîèñê ðåøåíèÿ çàäà÷è î ðàíöå. Ðàäè óäîáñòâà òàêàÿ ôóíêöèÿ áóäåò âûáèðàòü ïî îäíîìó ïðåäìåòó èç çàäàííîãî ñïèñêà ýëåìåíòîâ (íåîãðàíè÷åííûé âûáîð ýëåìåíòîâ ìîæíî ñäåëàòü èç òîé æå ôóíêöèè, óáðàâ âûçîâ ôóíêöèè óäàëåíèÿ ýëåìåíòà èç ñïèñêà delete). Ñîáñòâåííî, òàêàÿ ôóíêöèÿ âûãëÿäèò ñëåäóþùèì îáðàçîì:
knapsack 0 _
= 0
Ðåàëèçàöèÿ ðåøåíèÿ íà ÿçûêå Haskell
107
knapsack _ [ ] = 0 knapsack w vs | null l = 0 | otherwise = maximum l
where
l = [ knapsack ( w − weight v ) ( delete v vs ) + cost v | v <− vs , weight v <= w ] Êàê âèäíî, äâà ïåðâûõ êëîçà îïðåäåëÿþò áàçèñ ðåêóðñèè, ïðè ýòîì îòñëåæèâàòü ïóñòîé ñïèñîê ýëåìåíòîâ òàêæå íàäî (ìàòåìàòè÷åñêîå îïèñàíèå çàäà÷è ýòî ïîäðàçóìåâàåò). Òðåòèé êëîç íàèáîëåå èíòåðåñåí, ïîñêîëüêó îïðåäåëÿåò øàã ðåêóðñèè, è â í¼ì ïðîèçâîäÿòñÿ äèíàìè÷åñêèé ïåðåáîð è ïîèñê ðåøåíèÿ. Äâà âûðàæåíèÿ îõðàíû îïðåäåëÿþò ðåçóëüòàò ôóíêöèè â ñëó÷àå, åñëè ñïèñîê âîçìîæíûõ çíà÷åíèé, ïîëó÷åííûõ ïðè ðåêóðñèâíîì âûçîâå, ïóñò è íåïóñò.  ïåðâîì ñëó÷àå ðåçóëüòàòîì âñ¼ òàê æå äîëæåí áûòü 0, âî âòîðîì íåîáõîäèìî âûáðàòü ìàêñèìàëüíîå çíà÷åíèå, êàê òî ïðåäïèñûâàåò ìàòåìàòè÷åñêîå ðåêóððåíòíîå ñîîòíîøåíèå. Âûðàæåíèå l, êîòîðîå âûíåñåíî â ëîêàëüíîå îïðåäåëåíèå â îïòèìèçàöèîííûõ öåëÿõ (â òåëå ôóíêöèè îíî âñòðå÷àåòñÿ äâà ðàçà), êàê ðàç è çàïóñêàåò ïðîöåññ ðåêóðñèâíîãî âûçîâà ôóíêöèè knapsack äëÿ âñåõ ýëåìåíòîâ âõîäíîãî ñïèñêà, ÷üè âåñà íå áîëüøå çàäàííîãî âåñà. Âû÷èñëåíèå îñíîâàíî íà ãåíåðàòîðå ñïèñêà (ïîäðîáíî î ãåíåðàöèè ñïèñêîâ ìîæíî îçíàêîìèòüñÿ â ðàçäåëå ¾Ìàãè÷åñêèå êâàäðàòû è ðåøåíèå ïåðåáîðíûõ çàäà÷¿, ñòð. 90). Òó æå ñàìóþ ôóíêöèþ ìîæíî íàïèñàòü è ñ ïðåôèêñíûì îïðåäåëåíèåì ëîêàëüíîãî âûðàæåíèÿ l.  ìåòîäè÷åñêèõ öåëÿõ áóäåò èíòåðåñíî ðàññìîòðåòü òàêîé âàðèàíò:
knapsack 0 _ = 0 knapsack _ [ ] = 0 knapsack w vs = l e t l = [ knapsack ( w − weight v ) ( delete v vs ) + cost v | v <− vs , weight v <= w ] in i f ( null l ) then 0 el se maximum l Ïîíÿòíî, ÷òî ýòîò âàðèàíò íè÷åì íå îòëè÷àåòñÿ îò ïðåäûäóùåãî, êðîìå ñâîåé ôîðìû. Âñ¼ õîðîøî, òîëüêî îïðåäåë¼ííàÿ ëþáûì èç ïðåäñòàâëåííûõ âàðèàíòîâ ôóíêöèÿ knapsack íå èìååò âûñîêîãî ïðàêòè÷åñêîãî çíà÷åíèÿ. Ýòî ñâÿçàíî ñ òåì, ÷òî îíà âîçâðàùàåò ëèøü ìàêñèìàëüíî âîçìîæíóþ ñòîèìîñòü óïàêîâàííûõ â îãðàíè÷åííûé ðàíåö ýëåìåíòîâ. Íî â ïðèêëàäíûõ çàäà÷àõ îáû÷íî íåîáõîäèìî çíàòü íå òîëüêî òàêóþ ìàêñèìàëüíóþ ñòîèìîñòü, íî è òîò íàáîð ýëåìåíòîâ, êîòîðûé ïðèâîäèò ê òàêîé ñòîèìîñòè. Äëÿ ðåøåíèÿ ýòîé çàäà÷è ôóíêöèþ ïðèä¼òñÿ ñëåãêà ïðåîáðàçîâàòü îíà áóäåò âîçâðàùàòü ïàðó, ïåðâûì çíà÷åíèåì êîòîðîé ÿâëÿåòñÿ ìàêñèìàëüíàÿ ñòîèìîñòü, à âòîðûì íàáîð ýëåìåíòîâ.
knapsack ' 0 vs = ( 0 , [ ] ) knapsack ' _ [ ] = ( 0 , [ ] ) knapsack ' w vs = getMaxCost [ ( ( fst prevKS ) + cost v , v : ( snd prevKS ) ) | v <− vs , l e t prevKS = knapsack ' ( w − weight v ) ( delete v vs ) , weight v <= w ]
where
getMaxCost [ ] = (0 , [ ] ) getMaxCost ( ( c , v ) : vs ) = l e t ( c ' , v ' ) = getMaxCost vs
108
Çàäà÷à î ðàíöå
in
if (c > c ') then ( c , v ) el se ( c ' , v ' )
Êàê âèäíî, èç-çà òîãî, ÷òî ðåçóëüòàòîì âûïîëíåíèÿ ôóíêöèè ñòàëà ïàðà, îïðåäåëåíèå ñäåëàëîñü ñëîæíåå. Âñ¼ ïî ïðè÷èíå òîãî, ÷òî ïàðó íåîáõîäèìî ñîáèðàòü íåïîñðåäñòâåííî â ãåíåðàòîðå ñïèñêà (à äëÿ ýòîãî å¼ íåîáõîäèìî ðàçáèðàòü åñòü ñòàíäàðòíûå ôóíêöèè fst è snd), à íàä êàæäûì ýëåìåíòîì ïàðû íàäî ïðîèçâîäèòü ñâîè îïåðàöèè. Íàä ïåðâûì ñëîæåíèå âåñîâ, íàä âòîðûì äîáàâëåíèå ýëåìåíòà â ñïèñîê. Ýòî òàêæå âëå÷¼ò íåîáõîäèìîñòü ðåàëèçàöèè ñîáñòâåííîé ôóíêöèè ïîèñêà ìàêñèìóìà, ïîñêîëüêó ñòàíäàðòíàÿ maximum ðàáîòàåò òîëüêî ñî ñïèñêàìè ñðàâíèâàåìûõ ýëåìåíòîâ. Ëîêàëüíàÿ ôóíêöèÿ getMaxCost èùåò ìàêñèìàëüíóþ ñòîèìîñòü â ñïèñêå ïàð, â êîòîðûõ ñòîèìîñòü ñòîèò íà ïåðâîì ìåñòå. Íó è, ñîáñòâåííî, ïðè ïîìîùè ýòèõ ôóíêöèé òåïåðü ìîæíî ðåøàòü çàäà÷è î ðàíöå. Íàïðèìåð, òà çàäà÷à, êîòîðàÿ ïîêàçàíà íà ðèñ. 5, êîäèðóåòñÿ ñëåäóþùèìè ïðîãðàììíûìè ñóùíîñòÿìè:
data KI = KI Integer Integer deriving ( Eq , Show ) instance KnapsackItem KI where cost ( KI c w ) = c weight ( KI c w ) = w example = [ KI 4 1 2 , KI 2 2 , KI 2 1 , KI 1 1 , KI 10 4 ] Çäåñü òèï KI ñîäåðæèò â ñåáå äâà ïîëÿ: îäíî äëÿ ñòîèìîñòè, âòîðîå äëÿ âåñà. Äëÿ ñîîòâåòñòâèÿ òðåáîâàíèÿì íà òèïû çíà÷åíèé, èñïîëüçóþùèõñÿ â ôóíêöèÿõ knapsack è knapsack', íåîáõîäèìî îïðåäåëèòü ýêçåìïëÿð êëàññà KnapsackItem. Ôóíêöèÿ example ïðîñòî îïðåäåëÿåò ñïèñîê ýëåìåíòîâ, êîòîðûå èçîáðàæåíû íà ðèñ. 5. Òåïåðü ìîæíî çàïóñòèòü ôóíêöèè íà ïðîâåðêó: > knapsack 15 example 15 >knapsack ' 15 example ( 1 5 , [ KI 10 4 , KI 1 1 , KI 2 1 , KI 2 2 ] )
Çàêëþ÷åíèå Êàê âèäíî, ÿçûê ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ Haskell â î÷åðåäíîé ðàç ïîêàçàë ñâîþ áëèçîñòü ê ìàòåìàòèêå è ïðîñòîòó â èñïîëüçîâàíèè äëÿ ðåøåíèÿ çàäà÷. Ïîëó÷åííûå ôóíêöèè ìîãóò áûòü èñïîëüçîâàíû äëÿ ðàçëè÷íûõ öåëåé äîñòàòî÷íî ëèøü çàêîäèðîâàòü èñõîäíûå äàííûå â ñîîòâåòñòâèè ñ òðåáîâàíèÿìè. Òàê, ê ïðèìåðó, àâòîð èñïîëüçîâàë ôóíêöèþ knapsack' äëÿ îïòèìàëüíîãî ðàñïðåäåëåíèÿ ìóçûêàëüíûõ àëüáîìîâ â ôîðìàòå MP3 íà íåñêîëüêèõ êîìïàêò-äèñêàõ (çàäà÷à î ðàíöå ïðèìåíÿëàñü ðåêóðñèâíî) äëÿ íåóòîìèòåëüíîãî ïðîñëóøèâàíèÿ, ïðè ýòîì êðèòåðèåì ñòîèìîñòè âûñòóïàëà äîñòàòî÷íî ñëîæíàÿ ôîðìóëà, ïðèíèìàþùàÿ âî âíèìàíèå ðàçìåð àëüáîìà, åãî æàíð, ñóáúåêòèâíóþ îöåíêó ñëóøàòåëÿ è íåêîòîðûå èíûå ôàêòîðû. Òàêèì îáðàçîì, ÿçûê Haskell âïîëíå óñïåøíî ìîæíî èñïîëüçîâàòü â êà÷åñòâå èíñòðóìåíòà áûñòðîé ðàçðàáîòêè íåáîëüøèõ óòèëèò, ïðåäíàçíà÷åííûõ äëÿ ðåøåíèÿ êàêîé-òî îäíîé íåñëîæíîé çàäà÷è.
Êðèâàÿ Äðàêîíà Ñòàòüÿ áûëà îïóáëèêîâàíà â 09 (45) æóðíàëà ¾Ïîòåíöèàë¿ â ñåíòÿáðå 2008 ãîäà.
 äàííîì ýññå â î÷åðåäíîé ðàç ðàññìàòðèâàþòñÿ ïðàêòè÷åñêèå àñïåêòû ïðèìåíåíèÿ ÿçûêà Haskell ïðè ðåøåíèè ðàñ÷¼òíûõ çàäà÷.  êà÷åñòâå ïðèìåðà èçó÷àåòñÿ îäèí èç âèäîâ ôðàêòàëîâ, èìåþùèé ïîýòè÷åñêîå íàèìåíîâàíèå ¾Êðèâàÿ Äðàêîíà¿. Ïðèâîäÿòñÿ òåîðåòè÷åñêèå àñïåêòû, ðàññìàòðèâàåòñÿ ïîñòðîåíèå àëãîðèòìà íà ìàòåìàòè÷åñêîì óðîâíå, ïîñëå ÷åãî àëãîðèòì ðåàëèçóåòñÿ íà ÿçûêå Haskell.
Ââåäåíèå  ìàòåìàòèêå èìååòñÿ îäíà èíòåðåñíåéøàÿ îòðàñëü, êîòîðàÿ çàíèìàåòñÿ èçó÷åíèåì ñàìîïîäîáíûõ îáúåêòîâ, êàæäàÿ ìåëü÷àéøàÿ ÷àñòü êîòîðûõ ïîäîáíà âñåìó îáúåêòó. Ïîä ïîäîáèåì çäåñü ïîíèìàåòñÿ ïîõîæåñòü äî íåêîòîðîé ñòåïåíè. Ñàìà ñòåïåíü ïîäîáèÿ â äàííîì ñëó÷àå ìîæåò ÿâëÿòüñÿ ôàêòîðîì, ïðè ïîìîùè êîòîðîãî ìîæíî êëàññèôèöèðîâàòü èçó÷àåìûå îáúåêòû. Íó à ñàìè òàêèå îáúåêòû íàçûâàþòñÿ . Îäíèì èç íàèáîëåå èçâåñòíûõ ôðàêòàëîâ ÿâëÿåòñÿ , êîòîðîå ñòðîèòñÿ ïðè ïîìîùè äîñòàòî÷íî ïðîñòîé ïðîöåäóðû (ïîäðîáíîñòè ñì., íàïðèìåð, â [13]). Äëÿ ïðîèçâîëüíîãî êîìïëåêñíîãî ÷èñëà z0 ñòðîèòñÿ îòîáðàæåíèå ïî ôîðìóëå:
ôðàêòàëàìè
ìíîæåñòâî Ìàíäåëüáðîòà
zi+1 = zi2 + c,
(21)
ãäå c íåêîòîðàÿ êîíñòàíòà.  ýòîé ïðîöåäóðå èíäåêñ i ïîñëåäîâàòåëüíî ïðîáåãàåò âñå íàòóðàëüíûå çíà÷åíèÿ îò 0 è äàëåå. Òàê èòåðàòèâíî ñòðîèòñÿ ïîñëåäîâàòåëüíîñòü z0 , z1 , z2 , . . .. Åñëè çàôèêñèðîâàòü z0 , òî ïîëó÷àåìûå íà î÷åðåäíîì øàãå çíà÷åíèÿ áóäóò ïîëíîñòüþ çàâèñåòü îò âûáîðà êîíñòàíòû c, êîòîðàÿ íà ëþáîì øàãå äîëæíà áûòü îäèíàêîâîé. Íàïðèìåð, åñëè z0 = 0, òî ïîñëåäîâàòåëüíîñòü áóäåò âûãëÿäåòü òàê:
• z0 = 0; • z1 = c; • z2 = c2 + c; • z3 = c4 + 2c3 + c2 + c; • z4 = c8 + 4c7 + 6c6 + 6c5 + 5c4 + 2c3 + c2 + c; • ... È âîò îêàçûâàåòñÿ, ÷òî äëÿ íåêîòîðûõ çíà÷åíèé c ïðè ôèêñèðîâàííîì z0 îïèñàííàÿ ïðîöåäóðà ñîçäà¼ò áåñêîíå÷íóþ ïîñëåäîâàòåëüíîñòü, â êîòîðîé ëþáîå ÷èñëî îãðàíè÷åíî íåêîòîðîé íåáîëüøîé îáëàñòüþ îêîëî íà÷àëà êîîðäèíàò êîìïëåêñíîãî ÷èñëà 0 + 0i. Íàïðèìåð, òðèâèàëüíûì çíà÷åíèåì êîíñòàíòû c
110
Êðèâàÿ Äðàêîíà
ÿâëÿåòñÿ 0, ïîñêîëüêó â äàííîì ñëó÷àå ëþáîé ÷ëåí ïîñëåäîâàòåëüíîñòè òàêæå ðàâåí 0. Äðóãîé ïðèìåð: c = −1. Ìíîæåñòâî Ìàíäåëüáðîòà åñòü ìíîæåñòâî âñåõ çíà÷åíèé êîíñòàíòû c, äëÿ êîòîðûõ ïîëó÷àåìàÿ ïî îïèñàííîé ïðîöåäóðå ïîñëåäîâàòåëüíîñòü ÿâëÿåòñÿ îãðàíè÷åííîé. Íà ðèñ. 6 ïîêàçàíî ìíîæåñòâî Ìàíäåëüáðîòà äëÿ z0 = 0. Êàê âèäíî, ìíîæåñòâî Ìàíäåëüáðîòà âïå÷àòëÿåò ñâîåé ñëîæíîñòüþ, îñîáåííî ó÷èòûâàÿ, êàê ýòî ÷àñòî áûâàåò â ìàòåìàòèêå, óäèâèòåëüíóþ ïðîñòîòó åãî îïðåäåëåíèÿ.
Ðèñ. 6. Îáùèé âèä ìíîæåñòâà Ìàíäåëüáðîòà äëÿ z
0
=0
Äðóãîé ïðèìåð ôðàêòàëà ïðèâîäèò â ñâîåé êíèãå [5] çàìå÷àòåëüíûé àìåðèêàíñêèé ïîïóëÿðèçàòîð íàóêè Ìàðòèí Ãàðäíåð. Îí ñòðîèò ñíåæèíêó, íà÷èíàÿ îò ïðîñòîãî ðàâíîñòîðîííåãî òðåóãîëüíèêà, çàêàí÷èâàÿ ôèãóðîé ñ áåñêîíå÷íûì ïåðèìåòðîì, íî îãðàíè÷åííîé ïëîùàäüþ. Íà êàæäîé èòåðàöèè ïîñòðîåíèÿ ïåðèìåòð ôèãóðû ñòàíîâèòñÿ âñ¼ ñëîæíåå è çàìûñëîâàòåå, ïîâûøåíèå òî÷íîñòè åãî èçìåðåíèÿ âëå÷¼ò íåîãðàíè÷åííûé ðîñò åãî äëèíû, à ïëîùàäü îñòà¼òñÿ îãðàíè÷åííîé î÷åíü íåáîëüøîé îáëàñòüþ. Êàê ïèøåò ñàì Ì. Ãàðäíåð, òàêàÿ ôèãóðà ìîæåò áûòü èçîáðàæåíà íà îáû÷íîé ïî÷òîâîé ìàðêå, à ñóììà äëèí å¼ ñòîðîí áóäåò ñðàâíèìà ñ äèàìåòðîì íàøåé ãàëàêòèêè (åñòåñòâåííî, ïðè äîëæíîé òî÷íîñòè íàíåñåíèÿ èçîáðàæåíèÿ è ïîñëåäóþùåãî èçìåðåíèÿ). Ïðèìåðíûé âèä ôðàêòàëà ¾Ñíåæèíêà¿ èçîáðàæ¼í íà ðèñ. 7.
Ðèñ. 7. Ïðèìåðíûé âèä ôðàêòàëà ¾Ñíåæèíêà¿ äëÿ íåáîëüøîãî ÷èñëà èòåðàöèé
×òî òàêîå Êðèâàÿ Äðàêîíà?
111
Åù¼ îäèí ôðàêòàë â ñâî¼ âðåìÿ ðàçðàáîòàí àâòîðîì ïî ìîòèâàì ïðî÷ò¼ííîãî îïèñàíèÿ ôðàêòàëà ¾Ñíåæèíêà¿. Äëÿ åãî ïîñòðîåíèÿ èñïîëüçóþòñÿ óæå íå ðàâíîñòîðîííèå òðåóãîëüíèêè, à êâàäðàòû. Åãî ïåðèìåòð òàêæå ñòðåìèòñÿ ê áåñêîíå÷íîñòè, õîòÿ ïëîùàäü âñåãäà îãðàíè÷åíà. Ïðèìåðíûé âèä ýòîãî ôðàêòàëà ïîêàçàí íà ðèñ. 8.
Ðèñ. 8. Ïðèìåðíûé âèä êâàäðàòíîãî ôðàêòàëà äëÿ íåáîëüøîãî ÷èñëà èòåðàöèé Âñå ýòè ïðèìåðû ñëîæíûõ ôèãóð îáúåäèíÿåò îäíî ñâîéñòâî îíè ñàìîïîäîáíû. Åñëè ðàññìîòðåòü êàêóþ-ëèáî ÷àñòü ôèãóðû ïðîèçâîëüíîãî ðàçìåðà íà ãðàíèöå, òî ïðè äîëæíîì ïðèáëèæåíèè è äîñòàòî÷íîé òî÷íîñòè áóäåò âèäíî, ÷òî ìàëàÿ ÷àñòü î÷åíü ïîõîäà íà âñþ ôèãóðó ïîäîáíà åé. Ôðàêòàëû èìåþò ìíîæåñòâî îáëàñòåé ïðèìåíåíèÿ êàê â ÷èñòîé íàóêå, òàê è íà ïðàêòèêå. Íàïðèìåð, íåêîòîðûå ñîâðåìåííûå òåõíèêè øèôðîâàíèÿ èíôîðìàöèè îñíîâàíû íà ðåçóëüòàòàõ, ïîëó÷åííûõ ïðè èçó÷åíèè ôðàêòàëîâ. Íî, êðîìå íàó÷íîãî è ïðàêòè÷åñêîãî ïðèìåíåíèÿ, ó ýòèõ ôèãóð èìååòñÿ åù¼ îäíî ýñòåòè÷åñêîå. Îíè íåîáû÷àéíî êðàñèâû. Äàëåå â íàñòîÿùåì ðàçäåëå ðàññìàòðèâàåòñÿ åù¼ îäèí âèä ôðàêòàëà, èìåþùèé íàçâàíèå ¾Êðèâàÿ Äðàêîíà¿.
×òî òàêîå Êðèâàÿ Äðàêîíà? Êàê è ðàññìîòðåííûå âî ââåäåíèè ôðàêòàëû, Êðèâàÿ Äðàêîíà ñòðîèòñÿ âåñüìà ïðîñòûì ñïîñîáîì. Ëþáîé ìîæåò ïîñòðîèòü íà÷àëüíûå èòåðàöèè ïðè ïîìîùè áóìàæíîé ëåíòû. Ëþáîçíàòåëüíîìó ÷èòàòåëþ ìîæíî ïîñîâåòîâàòü ñëåäóþùèé ñïîñîá ïîñòðîåíèÿ Êðèâîé Äðàêîíà. Íåîáõîäèìî âçÿòü áóìàæíóþ ëåíòó, ñêàæåì, ðàçìåðà 100 × 1 ñì. ×åì òîíüøå áóäåò áóìàãà, òåì ëó÷øå, ïîñêîëüêó òàêóþ ëåíòó ïðèä¼òñÿ ìíîãîêðàòíî ñãèáàòü, à ïðè ñãèáàíèè òîëùèíà áóìàãè áóäåò ìíîãîêðàòíî ñêëàäûâàòüñÿ, âíîñÿ ïîãðåøíîñòè â ñîçäàâàåìóþ ôèãóðó. Ëó÷øå âñåãî ïîäîéä¼ò òîíêàÿ êàëüêà äîñòàòî÷íî òîíêàÿ, íî â òî æå âðåìÿ ïðî÷íàÿ áóìàãà. Èòàê, èìååòñÿ ëåíòà äëèíîé â 100 ñàíòèìåòðîâ. Îäèí êîíåö ýòîé ëåíòû íåîáõîäèìî çàêðåïèòü (èëè äåðæàòü â óìå, ÷òî ýòîò êîíåö çàêðåïë¼ííûé; â äåéñòâèòåëüíîñòè çàêðåïëÿòü êëååì èëè ÷åì-òî ïîäîáíûì íå ñëåäóåò, ïîñêîëüêó âïîñëåäñòâèè ëåíòó ïðèä¼òñÿ ðàçâîðà÷èâàòü). Âòîðîé êîíåö ëåíòû ÿâëÿåòñÿ ñâîáîäíûì. Êàæäàÿ èòåðàöèÿ ïî ïîñòðîåíèþ Êðèâîé Äðàêîíà çàêëþ÷àåòñÿ â ïðîñòîé ïðîöåäóðå. Ëåíòà ñêëàäûâàåòñÿ ïîïîëàì ñâîáîäíûé êîíåö ñîâìåùàåòñÿ ñ çàêðåïë¼ííûì. Íà ïåðâîì øàãå ïîëó÷àåòñÿ ñëîæåííàÿ âäâîå ëåíòà ðàçìåðà 50 × 1 ñì. Ïåðâîíà÷àëüíûé ñâîáîäíûé êîíåö îêàçàëñÿ ñîâìåù¼ííûì ñ çàêðåïë¼ííûì êîíöîì. Ýòîò ñîâìåù¼ííûé êîíåö ëåíòû îñòà¼òñÿ çàêðåïë¼ííûì, à ñâîáîäíûì òåïåðü ñ÷èòàåòñÿ ìåñòî ñãèáà ëåíòû. Âòîðàÿ èòåðàöèÿ ïîâòîðÿåò ïåðâóþ ñâîáîäíûé êîíåö ñîâìåùàåòñÿ ñ çàêðåïë¼ííûì. Ïîëó÷àåòñÿ ñëîæåííàÿ â÷åòâåðî ëåíòà ðàçìåðà 25 × 1 ñì. Ìåñòà ñëîæåíèÿ íåîáõîäèìî òùàòåëüíî ïðîãëàæèâàòü, ÷òîáû îíè áûëè êàê ìîæíî áîëåå ïëîñêèìè (èìåííî òóò íàðàñòàåò íåòî÷íîñòü ïðè äàëüíåéøèõ ñëîæåíèÿõ,
112
Êðèâàÿ Äðàêîíà
ïîñêîëüêó íà ñãèá íåîáõîäèì ìàòåðèàë, è íà ñàìîì äåëå ñëîæåííàÿ â÷åòâåðî ëåíòà èìååò ìåíüøèé ðàçìåð, íî ïîêà ýòà íåòî÷íîñòü íåçàìåòíà). Îïèñàííóþ èòåðàöèþ íåîáõîäèìî ïîâòîðÿòü ñòîëüêî, ñêîëüêî ýòî âîçìîæíî.  èäåàëå äëÿ äîñòàòî÷íî òîíêîé áóìàãè ìîæíî ïîëó÷èòü ñëîæåííóþ â øåñòüäåñÿò ÷åòûðå ðàçà ëåíòó ðàçìåðà 1.5625 × 1 ñì. Íî äî ýòîãî âðÿä ëè äîéä¼ò ïîìåøàåò èìåííî òîëùèíà áóìàãè. Ïóñòü ïîëó÷èòñÿ ñëîæåííàÿ â øåñòíàäöàòü ðàç ëåíòà ðàçìåðà 6.25 × 1 ñì. Ïîñëå ýòèõ ñëîæåíèé ëåíòà áóäåò óæå íàïîìèíàòü áðóñîê. Íî íåîáõîäèìî ïîìíèòü, ÷òî ýòî âñåãî ëèøü ãðóáàÿ ôèçè÷åñêàÿ ìîäåëü ìàòåìàòè÷åñêîãî ïðîöåññà. Ìàòåìàòè÷åñêàÿ ëåíòà íå èìååò òîëùèíû, å¼ ìîæíî ñêëàäûâàòü äî áåñêîíå÷íîñòè. Íàêîíåö, ìîæíî ïðèñòóïèòü ê ñàìîìó ïîñòðîåíèþ Êðèâîé Äðàêîíà. Äëÿ ýòîãî íåîáõîäèìî ðàçâåðíóòü ïîëó÷èâøèéñÿ áðóñîê áóìàãè, îçàáîòèâøèñü òåì, ÷òîáû êàæäûé óãîë íà ñãèáå ðàâíÿëñÿ 90◦ . Ðàçâîðà÷èâàòü, åñòåñòâåííî, íåîáõîäèìî, ïîñòàâèâ ñîãíóòóþ ëåíòó ¾íà ïîïà¿, à íå ïðîñòî ïîëîæèâ å¼. Ýòî ñäåëàòü íå òàê ïðîñòî, íî ïðè äîëæíîì òåðïåíèè ëåíòà ðàçâåðí¼òñÿ â Êðèâóþ Äðàêîíà äëÿ îïðåäåë¼ííîãî øàãà ïîñòðîåíèÿ (â èäåàëå ñãèáàíèå ëåíòû íóëåâîé òîëùèíû ïðîèçâîäèòñÿ áåñêîíå÷íîå êîëè÷åñòâî ðàç). Íà ðèñ. 9 ïîêàçàíà Êðèâàÿ Äðàêîíà ïðè ñãèáàíèè ëåíòû â øåñòíàäöàòü (÷àñòü à) è â øåñòüäåñÿò ÷åòûðå ðàçà (÷àñòü á) ñîîòâåòñòâåííî.
Ðèñ. 9. Êðèâàÿ Äðàêîíà ïðè ñãèáàíèè ëåíòû â øåñòíàäöàòü è øåñòüäåñÿò ÷åòûðå ðàçà Èíòåðåñ ïðåäñòàâëÿåò òî ôàêò, ÷òî, ñêîëüêî áû íè ñãèáàëè ëåíòó, ïðè ðàçâîðà÷èâàíèè å¼ óêàçàííûì îáðàçîì îíà íèêîãäà íå ïåðåñå÷¼òñÿ ñàìà ñ ñîáîé. Ëåíòà ïîðàçèòåëüíûì îáðàçîì âûñòðàèâàåòñÿ â çàìûñëîâàòóþ êðèâóþ, íåñêîëüêî íàïîìèíàþùóþ ðàññìîòðåííîå ðàíåå ìíîæåñòâî Ìàíäåëüáðîòà. Åñëè ðàññìîòðåòü ìàòåìàòè÷åñêîå îïèñàíèå ýòîé êðèâîé, òî å¼ âíåøíÿÿ ãðàíèöà îïÿòü ïîëó÷èòñÿ ñàìîïîäîáíîé êàæäàÿ ìåëü÷àéøàÿ ÷àñòü íàïîìèíàåò âñþ êðèâóþ. Îáùèé âèä ìàòåìàòè÷åñêîé Êðèâîé Äðàêîíà ïðåäñòàâëåí íà ðèñ. 10.
Ðèñ. 10. Ìàòåìàòè÷åñêè òî÷íàÿ Êðèâàÿ Äðàêîíà
Àëãîðèòì ïîñòðîåíèÿ
113
Äðóãèì èíòåðåñíûì ôàêòîì îòíîñèòåëüíî ýòîé êðèâîé ÿâëÿåòñÿ òî, ÷òî ñàìó êðèâóþ ìîæíî ïîñòðîèòü èç îòðåçêà ëþáîé äëèíû. Äëèíà îòðåçêà ïîëíîñòüþ îïðåäåëÿåò ïëîùàäü êðèâîé. Ñîáñòâåííî, äëèíà îòðåçêà ýòî è åñòü äëèíà êðèâîé, óëîæåííîé çàìûñëîâàòûì îáðàçîì. ×åì äëèííåå êðèâàÿ, òåì áîëüøóþ ïëîùàäü îíà çàõâàòèò. Îäíàêî èäåàëüíûé ìàòåìàòè÷åñêèé îáúåêò ýòîé çàìûñëîâàòîé ôîðìû ìîæåò áûòü ïîñòðîåí èç îòðåçêà ëþáîé äëèíû. Îáû÷íî èñïîëüçóåòñÿ åäèíè÷íûé îòðåçîê.
Àëãîðèòì ïîñòðîåíèÿ Ðàññìîòðåííûé â ïðåäûäóùåì ïîäðàçäåëå ñïîñîá ïîñòðîåíèÿ Êðèâîé Äðàêîíà ïîçâîëÿåò ñôîðìóëèðîâàòü àëãîðèòì å¼ ïîñòðîåíèÿ äëÿ íåêîòîðîãî ÿçûêà ïðîãðàììèðîâàíèÿ. Ñîáñòâåííî, ïðè ðàçâîðà÷èâàíèè ëåíòû ýòîò àëãîðèòì äîëæåí áûë ïîÿâèòüñÿ â ãîëîâå âäóì÷èâîãî ýêñïåðèìåíòàòîðà, ïîñêîëüêó êàæäûé î÷åðåäíîé ðàçâîðîò ïîêàçûâàåò, êàê èìåííî ñòðîèòñÿ êðèâàÿ íà ïðîèçâîëüíîì øàãå. Àëãîðèòì äîñòàòî÷íî ïðîñò. Îäíàêî â öåëÿõ óïðîùåíèÿ äàëåå áóäåò ïðåäïîëàãàòüñÿ, ÷òî íà êàæäîì î÷åðåäíîì øàãå äëèíà êðèâîé óâåëè÷èâàåòñÿ â äâà ðàçà, à íå îñòà¼òñÿ ïîñòîÿííîé, êàê â ñëó÷àå ñãèáàíèÿ ëåíòû. Ýòî íåïðèíöèïèàëüíî, ïîñêîëüêó íà îáùíîñòü ðàññóæäåíèé íèêàê íå âëèÿåò. Ïîñòðîåííàÿ äëÿ êàêîãî-òî øàãà êðèâàÿ áóäåò èìåòü îïðåäåë¼ííóþ äëèíó, è ýòó äëèíó ìîæíî ñ÷èòàòü äëèíîé ïåðâîíà÷àëüíîé ëåíòû. Èòàê, àëãîðèòì ïîñòðîåíèÿ Êðèâîé Äðàêîíà èä¼ò íå îò ñãèáàíèÿ ëåíòû, à îò ðàçâîðà÷èâàíèÿ åäèíè÷íîãî îòðåçêà â êðèâóþ. Îí ñîñòîèò âñåãî èç äâóõ øàãîâ: 1) íà íóëåâîì øàãå ñòðîèòñÿ åäèíè÷íûé îòðåçîê ñ êîíöàìè â êîîðäèíàòàõ (0, 0) è (1, 0) ñîîòâåòñòâåííî. Ýòîò îòðåçîê íàçûâàåòñÿ Êðèâîé Äðàêîíà íóëåâîé èòåðàöèè; 2) ïîëó÷åííàÿ íà ïðåäûäóùåì øàãå Êðèâàÿ Äðàêîíà n-îé èòåðàöèè äóáëèðóåòñÿ, è äóáëèêàò ïîâîðà÷èâàåòñÿ âîêðóã íà÷àëà êîîðäèíàò (0, 0) ïðîòèâ ÷àñîâîé ñòðåëêè íà 90◦ , ïîñëå ÷åãî ñäâèãàåòñÿ ê êîíöó îðèãèíàëà êðèâîé ñâîèì ñâîáîäíûì êîíöîì. Ñâîáîäíûé êîíåö ýòî òîò êîíåö, êîòîðûé ëåæèò âíå íà÷àëà êîîðäèíàò. Îí ñâîáîäåí ïîòîìó, ÷òî ñâîáîäíî âðàùàåòñÿ. Ïåðâàÿ òî÷êà Êðèâîé Äðàêîíà ëåæèò â íà÷àëå êîîðäèíàò, à ïîòîìó ïðè âðàùåíèè íå èçìåíÿåò ñâîåãî ïîëîæåíèÿ, ïîýòîìó îíà è íàçûâàåòñÿ çàêðåïë¼ííîé. Îðèãèíàë è äóáëèêàò ñøèâàþòñÿ â îäíó êðèâóþ. Ïîëó÷àåòñÿ Êðèâàÿ Äðàêîíà (n + 1)-îé èòåðàöèè. Äàííûé ïðîöåññ ïîâòîðÿåòñÿ äî òåõ ïîð, ïîêà íå äîñòèãíóòà òðåáóåìàÿ òî÷íîñòü (â èäåàëå äî áåñêîíå÷íîñòè). Ïðèìåíåíèå ýòîãî àëãîðèòìà äëÿ ÷åòûð¼õ èòåðàöèé ïîêàçàíî íà ðèñ. 11.
Ðèñ. 11. Ïîñëåäîâàòåëüíîå ïîñòðîåíèå Êðèâîé Äðàêîíà ïðè ïîìîùè îïèñàííîãî àëãîðèòìà
Ðåàëèçàöèÿ íà ÿçûêå Haskell Îïèñàííûé â ïðåäûäóùåì ïîäðàçäåëå àëãîðèòì íà ïåðâûé âçãëÿä âûãëÿäèò äîñòàòî÷íî èìïåðàòèâíî. Øàã çà øàãîì ñòðîèòñÿ êðèâàÿ, ïîñëåäîâàòåëüíî íàðàùèâàÿ ñâîþ ñëîæíîñòü. Îäíàêî íà ñàìîì äåëå ýòîò
114
Êðèâàÿ Äðàêîíà
àëãîðèòì äîñòàòî÷íî ëåãêî ïðåîáðàçóåòñÿ â ðåêóðñèâíûé äåêëàðàòèâíûé àëãîðèòì, ïðè÷¼ì ïðàêòè÷åñêè áåç êàêèõ-ëèáî äîïîëíåíèé è èçìåíåíèé. Íèæå â ïîñëåäóþùèõ ïîäðàçäåëàõ áóäåò íàïèñàíà íåáîëüøàÿ ïðîãðàììà íà ôóíêöèîíàëüíîì ÿçûêå Haskell, êîòîðàÿ âû÷èñëÿåò êîîðäèíàòû ïîñëåäîâàòåëüíûõ òî÷åê Êðèâîé Äðàêîíà.
Ïîäãîòîâèòåëüíûå îïèñàíèÿ ãåîìåòðè÷åñêèõ îáðàçîâ Ïðåæäå ÷åì íà÷àòü ðåàëèçàöèþ ôóíêöèè, âîçâðàùàþùåé ïîñëåäîâàòåëüíîñòü êîîðäèíàò òî÷åê Êðèâîé Äðàêîíà, íåîáõîäèìî ïðîâåñòè íåêîòîðûå ïîäãîòîâèòåëüíûå ðàáîòû. Äëÿ ïîñòðîåíèÿ êðèâîé íóæíî îïðåäåëèòü ñïåöèàëüíûå òèïû äàííûõ, êîòîðûå áóäóò èñïîëüçîâàòüñÿ äëÿ îïèñàíèÿ ïðèìèòèâíûõ ýëåìåíòîâ, èç êîòîðûõ áóäåò ñîñòîÿòü êðèâàÿ, à òàêæå äëÿ îïèñàíèÿ ñàìîé êðèâîé. Ðåçîííî âñå òàêèå îïèñàíèÿ âûíåñòè â îòäåëüíûé ìîäóëü, îòâåòñòâåííûé çà ãåîìåòðè÷åñêèå îïèñàíèÿ:
module Geometry where Ïåðâûì äåëîì íåîáõîäèìî ïîäóìàòü, ÷òî èìååòñÿ îáùåãî âî âñåõ òåõ îáúåêòàõ, êîòîðûå áóäóò èñïîëüçîâàòüñÿ â àëãîðèòìå. Ñàì àëãîðèòì ïîäñêàçûâàåò âñå îáúåêòû ìîæíî ïîâîðà÷èâàòü íà 90◦ ïðîòèâ ÷àñîâîé ñòðåëêè îòíîñèòåëüíî íà÷àëà êîîðäèíàò è ñäâèãàòü íà çàäàííîå ðàññòîÿíèå. Ñàì àëãîðèòì íè÷åãî íå ãîâîðèò î òèïå êîîðäèíàò öåëî÷èñëåííûå ëè îíè èëè ïðîèçâîëüíûå. Äëÿ îïèñàíèÿ òàêèõ ñèòóàöèé â ÿçûêå Haskell èìååòñÿ îòëè÷íûé ôîðìàëèçì êëàññû ñ ïàðàìåòðèçàöèåé òèïîâ. Ïîýòîìó äëÿ îïèñàíèÿ èíòåðôåéñà ê îáúåêòàì, êîòîðûå ìîæíî âðàùàòü è äâèãàòü, ìîæíî îïðåäåëèòü ñëåäóþùèé êëàññ:
c l a s s Figure f where shift : : Num a => a −> a −> f a −> f a rotate90 : : Num a => f a −> f a Çäåñü, â ýòîì îïðåäåëåíèè, ñäåëàíî íåáîëüøîå äîïóùåíèå. Ïðåäïîëàãàåòñÿ, ÷òî ïðîèçâîëüíàÿ ôèãóðà òèïà f ïàðàìåòðèçóåò ñîáîé íåêîòîðûé ñïåöèàëüíûé òèï a, ñî çíà÷åíèÿìè êîòîðîãî ìîæíî ñîâåðøàòü àðèôìåòè÷åñêèå îïåðàöèè (òåì ÷èòàòåëÿì, êîòîðûì ñëîæíî ïîíèìàòü âûøåïðèâåä¼ííûå îïðåäåëåíèÿ, íåîáõîäèìî îáðàòèòüñÿ ê ïðåäûäóùèì ðàçäåëàì äàííîãî ñáîðíèêà ëèáî ê èñòî÷íèêàì [6, 7]). Ïàðàìåòðèçàöèÿ òèïà a ñäåëàíà èìåííî äëÿ òîãî, ÷òîáû íå îãðàíè÷èâàòü êîîðäèíàòû îáúåêòîâ êàêèìëèáî ñïåöèàëèçèðîâàííûì òèïîì, ïîñêîëüêó â èçíà÷àëüíîì àëãîðèòìå î òèïå íè÷åãî íå ñêàçàíî. Òî, ÷òî íàä êîîðäèíàòàìè íåîáõîäèìî ñîâåðøàòü àðèôìåòè÷åñêèå îïåðàöèè, ñëåäóåò èç òîãî, ÷òî èõ íåîáõîäèìî ñäâèãàòü, òî åñòü ê êîîðäèíàòàì íåîáõîäèìî ïðèáàâëÿòü çíà÷åíèÿ ñäâèãîâ ïî äâóì îñÿì. Ñëåäóþùèé øàã îïðåäåëåíèå òèïà äàííûõ äëÿ ïðåäñòàâëåíèÿ òî÷êè íà ïëîñêîñòè. Äëÿ ýòèõ öåëåé ìîæíî áûëî áû âîñïîëüçîâàòüñÿ îáû÷íîé ïàðîé, îäíàêî ýòîò ïóòü íå ñîâñåì ïðàâèëüíûé, ïîñêîëüêó íå èñïîëüçóåò âîçìîæíîñòè ÿçûêà Haskell ïî àáñòðàêöèè äàííûõ. È, íåñìîòðÿ íà òî ÷òî â îïèñûâàåìîì äîñòàòî÷íî ïðîñòîì ïðèìåðå âîçìîæíîñòè ïî àáñòðàêöèè áóäóò èñïîëüçîâàíû ñëàáî, õîðîøèé òîí â ïðîãðàììèðîâàíèè íà ÿçûêå Haskell òðåáóåò ïðèìåíåíèÿ ãðàìîòíûõ èäèîì âñåãäà, êîãäà ýòî âîçìîæíî. Èòàê, àëãåáðàè÷åñêèé òèï äàííûõ äëÿ ïðåäñòàâëåíèÿ îäíîé òî÷êè ìîæíî îïðåäåëèòü òàê:
data Point a = Point { x :: a, y :: a } Ýòî îïðåäåëåíèå îçíà÷àåò, ÷òî òèï äëÿ ïðåäñòàâëåíèÿ òî÷êè Point ïàðàìåòðèçóåò íåêîòîðûé òèï a, êîòîðûé èñïîëüçóåòñÿ äëÿ ïðåäñòàâëåíèÿ òèïîâ äâóõ êîîðäèíàò x è y.
Ðåàëèçàöèÿ íà ÿçûêå Haskell
115
Äëÿ òîãî ÷òîáû çíà÷åíèÿìè òîëüêî ÷òî ñîçäàííîãî òèïà Point ìîæíî áûëî îïåðèðîâàòü â ñîîòâåòñòâèè ñ îïèñàííûì ðàíåå àëãîðèòìîì, äëÿ ýòîãî òèïà íåîáõîäèìî îïðåäåëèòü ýêçåìïëÿð êëàññà Figure. Ýòî äåëàåòñÿ äîñòàòî÷íî ïðîñòî:
instance Figure Point where shift dx dy ( Point x y ) = Point ( x + dx ) ( y + dy ) rotate90 ( Point x y ) = Point (− y ) x Òåïåðü â ýòîì îïðåäåëåíèè âèäíî, ÷òî ìåòîä shift èñïîëüçóåòñÿ äëÿ ñäâèãà îáúåêòà íà çàäàííûå çíà÷åíèÿ ïî îñÿì àáñöèññ è îðäèíàò, à ìåòîä rotate90 âñåãî ëèøü ïîâîðà÷èâàåò çàäàííûé îáúåêò íà 90◦ ïðîòèâ ÷àñîâîé ñòðåëêè. Äëÿ ðåàëèçàöèè îïèñàííîãî àëãîðèòìà íåò íàäîáíîñòè ñîçäàâàòü ìåòîä äëÿ âðàùåíèÿ íà ïðîèçâîëüíîå êîëè÷åñòâî ãðàäóñîâ, ïîñêîëüêó ýòî íå ïîòðåáóåòñÿ. Åñëè áû ýòî áûëî íåîáõîäèìî, òî áûëî áû íåâîçìîæíî èñïîëüçîâàòü äëÿ ïðåäñòàâëåíèÿ êîîðäèíàò ïðîèçâîëüíûå òèïû, íàä çíà÷åíèÿìè êîòîðûõ ìîæíî ïðîèçâîäèòü òîëüêî àðèôìåòè÷åñêèå îïåðàöèè, ïîñêîëüêó äëÿ âðàùåíèÿ íà ïðîèçâîëüíîå ÷èñëî ãðàäóñîâ íåîáõîäèìî èñïîëüçîâàòü ôóíêöèè sin è cos, êîòîðûå â ÿçûêå Haskell îïðåäåëåíû íàä äåéñòâèòåëüíûìè çíà÷åíèÿìè. Äîïîëíèòåëüíî æåëàòåëüíî îïðåäåëèòü äëÿ òèïà Point ýêçåìïëÿð êëàññà Show, ÷òîáû áûëî âîçìîæíî âûâîäèòü ðåçóëüòàòû ðàáîòû ñ òî÷êàìè íà êîîðäèíàòíîé ïëîñêîñòè íà ýêðàí. Ðåàëèçàöèÿ ýêçåìïëÿðà ïî óìîë÷àíèþ ïðåîáðàçóåò çíà÷åíèÿ íå î÷åíü ïðèÿòíûì ñïîñîáîì, ïîýòîìó â íèæåñëåäóþùåì îïðåäåëåíèè èñïîëüçóåòñÿ îáû÷íàÿ ìàòåìàòè÷åñêàÿ íîòàöèÿ äëÿ çàïèñè òî÷åê íà ïëîñêîñòè.
instance Show a => Show ( Point a ) where show ( Point x y ) = " ( " ++ show x ++ " , " ++ show y ++ " ) " Òàêæå íåîáõîäèìî îïðåäåëèòü óòèëèòàðíóþ ôóíêöèþ, êîòîðàÿ âîçâðàùàëà áû ðàññòîÿíèå ïî äâóì îñÿì ìåæäó äâóìÿ òî÷êàìè. Ýòà ôóíêöèÿ ïîòðåáóåòñÿ ïðè îïðåäåëåíèè òîãî, íà êàêîå ðàññòîÿíèå ñäâèãàòü îäèí èç ýêçåìïëÿðîâ êðèâîé íà î÷åðåäíîì øàãå ïîñòðîåíèÿ. Ôóíêöèÿ distance âûãëÿäèò ñëåäóþùèì îáðàçîì:
distance : : Num a => Point a −> Point a −> ( a , a ) distance ( Point x1 y1 ) ( Point x2 y2 ) = ( x1 − x2 , y1 − y2 ) Ýòà ôóíêöèÿ âîçâðàùàåò ïàðó ðàññòîÿíèé. Ïåðâîå çíà÷åíèå â ïàðå ñèìâîëèçèðóåò ðàññòîÿíèå ìåæäó òî÷êàìè ïî îñè àáñöèññ, âòîðîå ïî îñè îðäèíàò ñîîòâåòñòâåííî. Òàêîå ïðåäñòàâëåíèå íàèáîëåå ïðîñòî, à òàê êàê áóäåò èñïîëüçîâàòüñÿ òîëüêî â îäíîì ìåñòå, ñîçäàâàòü íîâûé òèï äëÿ ïðåäñòàâëåíèÿ òàêîé ïàðû íå òðåáóåòñÿ. Ñàìà êðèâàÿ ñîñòîèò èç ïîñëåäîâàòåëüíîãî íàáîðà òî÷åê. Ìîæíî áûëî áû èñïîëüçîâàòü îáû÷íûé ñïèñîê çíà÷åíèé òèïà Point, îäíàêî íå äëÿ ýòîãî âíà÷àëå áûë îïðåäåë¼í êëàññ Figure. Ïðîñòîé ñïèñîê èñïîëüçîâàòü íåëüçÿ, ïîñêîëüêó ïî ïðàâèëàì ÿçûêà Haskell åãî íåëüçÿ áóäåò ñäåëàòü ýêçåìïëÿðîì êëàññà. Íåîáõîäèìî îïðåäåëèòü íîâûé òèï, êîòîðûé èìåë àáñîëþòíî òàêîå æå ïîâåäåíèå, êàê è èìåþùèéñÿ òèï [] . Äëÿ ýòèõ öåëåé èñïîëüçóåòñÿ êëþ÷åâîå ñëîâî newtype:
newtype Curve a = Curve [ Point a ] deriving Show Äàííîå îïðåäåëåíèå ãîâîðèò òðàíñëÿòîðó ÿçûêà Haskell, ÷òî íåîáõîäèìî ñîçäàòü òèï, èçîìîðôíûé ñïèñêó çíà÷åíèé òèïà Point a. Èçîìîðôíîñòü îáîçíà÷àåò â äàííîì ñëó÷àå ïîëíóþ òîæäåñòâåííîñòü. Ðàçíèöà çàêëþ÷àåòñÿ ëèøü â òîì, ÷òî äëÿ íîâîãî òèïà Curve ìîæíî îïðåäåëèòü ýêçåìïëÿð êëàññà Figure, ÷òî ïîçâîëèò îïåðèðîâàòü çíà÷åíèÿìè ýòîãî òèïà àáñîëþòíî òàê æå, êàê ïðîñòûìè òî÷êàìè, âðàùàòü è ñäâèãàòü èõ. Äåëàåòñÿ ýòî íàìíîãî ïðîùå, ÷åì äëÿ òî÷åê òèïà Point:
instance Figure Curve where shift dx dy ( Curve ps ) = Curve ( map ( shift dx dy ) ps ) rotate90 ( Curve ps ) = Curve ( map rotate90 ps )
116
Êðèâàÿ Äðàêîíà
Íàêîíåö, áûëî áû î÷åíü íåïëîõî îïðåäåëèòü åù¼ îäíó óòèëèòàðíóþ ôóíêöèþ, êîòîðàÿ âîçâðàùàëà áû ñïèñîê òî÷åê èç çíà÷åíèÿ òèïà Curve. Ýòà ôóíêöèÿ ïðîñòî ¾ðàçâîðà÷èâàåò¿ òèï Curve, âîçâðàùàÿ åãî ñîäåðæèìîå:
points : : Curve a −> [ Point a ] points ( Curve ps ) = ps Òàêèì îáðàçîì, âåñü ìîäóëü Geometry âûãëÿäèò ñëåäóþùèì îáðàçîì:
module Geometry where c l a s s Figure f where shift : : Num a => a −> a −> f a −> f a rotate90 : : Num a => f a −> f a
data Point a = Point { x :: a, y :: a }
instance Figure Point where shift dx dy ( Point x y ) = Point ( x + dx ) ( y + dy ) rotate90 ( Point x y ) = Point (− y ) x
instance Show a => Show ( Point a ) where show ( Point x y ) = " ( " ++ show x ++ " , " ++ show y ++ " ) " distance : : Num a => Point a −> Point a −> ( a , a ) distance ( Point x1 y1 ) ( Point x2 y2 ) = ( x1 − x2 , y1 − y2 )
newtype Curve a = Curve [ Point a ] deriving Show instance Figure Curve where shift dx dy ( Curve ps ) = Curve ( map ( shift dx dy ) ps ) rotate90 ( Curve ps ) = Curve ( map rotate90 ps ) points : : Curve a −> [ Point a ] points ( Curve ps ) = ps
Ïîñòðîåíèå Êðèâîé Äðàêîíà Òåïåðü âñ¼ ãîòîâî, ÷òîáû ðåàëèçîâàòü îïèñàííûé â ïðåäûäóùåì ïîäðàçäåëå àëãîðèòì ïîñòðîåíèÿ Êðèâîé Äðàêîíà. Äëÿ å¼ ïîñòðîåíèÿ áóäåò èñïîëüçîâàòüñÿ îäíà ôóíêöèÿ, ïîëíîñòüþ ðåàëèçóþùàÿ àëãîðèòì òàê, êàê îí íàïèñàí:
makeDragonCurve : : Int −> Curve Int makeDragonCurve 0 = Curve [ Point 0 0 , Point 1 0 ] makeDragonCurve n = Curve ( points c ++ ( reverse $
Ðåàëèçàöèÿ íà ÿçûêå Haskell
where
117
init $ points ( shift dx dy rc ) ) )
c = makeDragonCurve ( n − 1 ) rc = rotate90 c ( dx , dy ) = distance ( last $ points c ) ( last $ points rc ) Ïåðâàÿ ñòðîêà îïðåäåëåíèÿ îïèñûâàåò òèï çíà÷åíèÿ, âîçâðàùàåìîãî ôóíêöèåé makeDragonCurve.  ýòîì îïèñàíèè èìååòñÿ îãðàíè÷åíèå íà òèï êîîðäèíàò, èñïîëüçóåìûõ äëÿ ïðåäñòàâëåíèÿ òî÷åê íà êîîðäèíàòíîé ïëîñêîñòè.  ïðåäëîæåííîé ðåàëèçàöèè ôóíêöèè ýòîò òèï Int, òî åñòü îãðàíè÷åííûå öåëûå ÷èñëà. Îäíàêî, êàê ãîâîðèëîñü ðàíåå, â êà÷åñòâå òèïà êîîðäèíàò ìîæåò èñïîëüçîâàòüñÿ ïðîèçâîëüíûé òèï, äëÿ êîòîðîãî èìååòñÿ ýêçåìïëÿð êëàññà Num. Âòîðàÿ ñòðîêà îäèí â îäèí ñîîòâåòñòâóåò ïóíêòó 1 àëãîðèòìà ïîñòðîåíèÿ Êðèâîé Äðàêîíà. Äëÿ íóëåâîé èòåðàöèè â ïîñòðîåíèè ïðîñòî âîçâðàùàåòñÿ åäèíè÷íûé îòðåçîê (0, 0) − (1, 0). Ñîîòâåòñòâåííî, òðåòüÿ ñòðîêà îïðåäåëåíèÿ ôóíêöèè makeDragonCurve ñîîòâåòñòâóåò ïóíêòó 2 àëãîðèòìà. Êàê âèäíî, ýòà ñòðîêà áîëåå ñëîæíàÿ, ðàâíî êàê è âòîðîé ïóíêò àëãîðèòìà çàíèìàåò íàìíîãî áîëüøå ñòðîê â îïèñàíèè, ÷åì ïåðâûé ïóíêò. Ýòà ñòðîêà ãëàñèò, ÷òî Êðèâàÿ Äðàêîíà íà n-îì øàãå ïîñòðîåíèÿ ñîñòîèò èç òî÷åê (ôóíêöèÿ points) íåêîòîðîé êðèâîé c, ê êîòîðûì ïðèñîåäèíåíû îáðàù¼ííîå çàäîì íàïåð¼ä (ôóíêöèÿ reverse èç ñòàíäàðòíîãî ìîäóëÿ Prelude) íà÷àëî (ôóíêöèÿ init èç ñòàíäàðòíîãî ìîäóëÿ Prelude) ñïèñêà òî÷åê ñìåù¼ííîé (ôóíêöèÿ shift) íà çíà÷åíèÿ dx è dy ïî îñÿì àáñöèññ è îðäèíàò ñîîòâåòñòâåííî íåêîòîðîé êðèâîé rc. Ýòî îïðåäåëåíèå íåîáõîäèìî ðàññìîòðåòü ïîäðîáíåå. Íåêîòîðàÿ êðèâàÿ c ÿâëÿåòñÿ ïðîñòî-íàïðîñòî Êðèâîé Äðàêîíà, ïîñòðîåííîé íà ïðåäûäóùåì, (n − 1)-îì øàãå. Êðèâàÿ rc ÿâëÿåòñÿ äóáëèêàòîì êðèâîé c, êîòîðûé ïîâ¼ðíóò íà 90◦ ïðîòèâ ÷àñîâîé ñòðåëêè âîêðóã íà÷àëà êîîðäèíàò. Çíà÷åíèÿ äëÿ ñäâèãà dx è dy ÿâëÿþòñÿ ðàññòîÿíèåì ìåæäó ïîñëåäíèìè òî÷êàìè êðèâûõ c è rc. Ïîñëåäíèå òî÷êè â îïèñàíèè êðèâîé ïðè ïîìîùè òèïà Curve ÿâëÿþòñÿ êàê ðàç ¾ñâîáîäíûìè¿ êîíöàìè, ïîñêîëüêó èìåííî îíè âðàùàþòñÿ âîêðóã íà÷àëà êîîðäèíàò. Ïîêà âñ¼ èä¼ò â òî÷íîñòè ïî àëãîðèòìó. Âñå ýòè äîïîëíèòåëüíûå îáúåêòû ïîëó÷åíû â ëîêàëüíûõ îïðåäåëåíèÿõ, ïåðå÷èñëåííûõ ïîñëå êëþ÷åâîãî ñëîâà where. Ñòàíäàðòíàÿ ôóíêöèÿ init èñïîëüçóåòñÿ äëÿ òîãî, ÷òîáû îòñå÷ü ïîñëåäíþþ òî÷êó â äóáëèêàòå êðèâîé, ïîëó÷åííîé íà ïðåäûäóùåì øàãå. Ýòà òî÷êà ïðè ïîìîùè ñäâèãà ïîäñîåäèíÿåòñÿ ê ïîñëåäíåé òî÷êå îðèãèíàëà êðèâîé. Ïîñêîëüêó òî÷êè ñîâìåùàþòñÿ, â îïèñàíèè êðèâîé íà n-îì øàãå íåò íàäîáíîñòè äóáëèðîâàòü çàïèñü î òî÷êàõ. Èìåííî äëÿ ýòîãî ïðîèçâîäèòñÿ îòñå÷åíèå. Íàêîíåö, îáðàùåíèå ïîâ¼ðíóòîé è ñäâèíóòîé êðèâîé ïðè ïîìîùè ñòàíäàðòíîé ôóíêöèè reverse ïðîèçâîäèòñÿ äëÿ òîãî, ÷òîáû ïåðåâåðíóòü ïîñëåäîâàòåëüíîñòü òî÷åê. Âåäü èìåííî ïåðåâîðîò ïðîèñõîäèò â ïðîöåäóðå ïîñòðîåíèÿ, îïèñàííîé â ïîäðàçäåëå, ïîñâÿù¼ííîì ìàòåìàòè÷åñêîìó îïèñàíèþ êðèâîé, êîãäà ñâîáîäíûé êîíåö ëåíòû ñîâìåùàåòñÿ ñ çàêðåïë¼ííûì. À èç ýòîé ïðîöåäóðû íåïîñðåäñòâåííî ïîëó÷åí àëãîðèòì ïîñòðîåíèÿ. Äëÿ òåõ ÷èòàòåëåé, êòî ïîäçàáûë, îñòà¼òñÿ îòìåòèòü, ÷òî ñòàíäàðòíûé îïåðàòîð ($) îïðåäåë¼í êàê îáû÷íîå ïðèìåíåíèå ôóíêöèè, íî ñ ñàìûì íèçêèì ïðèîðèòåòîì èñïîëíåíèÿ:
infixr 0 $ ( $ ) : : ( a −> b ) −> a −> b f $ x = f x Òàêîå îïðåäåëåíèå ïîçâîëÿåò çàïèñûâàòü ïîñëåäîâàòåëüíîå ïðèìåíåíèå ôóíêöèé ê ðåçóëüòàòàì âûïîëíåíèÿ äðóãèõ ôóíêöèé áåç ëèøíèõ ñêîáîê.  êîíå÷íîì èòîãå ïîëó÷àåòñÿ äîñòàòî÷íî ìèëîâèäíûé ìîäóëü:
module Dragon where import Geometry
118
Êðèâàÿ Äðàêîíà
makeDragonCurve : : Int −> Curve Int makeDragonCurve 0 = Curve [ Point 0 0 , Point 1 0 ] makeDragonCurve n = Curve ( points c ++ ( reverse $ init $ points ( shift dx dy rc ) ) )
where
c = makeDragonCurve ( n − 1 ) rc = rotate90 c ( dx , dy ) = distance ( last $ points c ) ( last $ points rc ) Çàïóñê ôóíêöèè makeDragonCurve ñ íåêîòîðûì ÷èñëîì, îïðåäåëÿþùèì íîìåð èòåðàöèè â ïîñòðîåíèè Êðèâîé Äðàêîíà, âåðí¼ò ñïèñîê òî÷åê ýòîé êðèâîé íà êîîðäèíàòíîé ïëîñêîñòè äëÿ çàäàííîãî øàãà. Ýòà ôóíêöèÿ ÿâëÿåòñÿ ëåíèâîé, ïîýòîìó â èíòåðïðåòàòîðå ÿçûêà Haskell îíà íà÷í¼ò âûâîäèòü ïðîìåæóòî÷íûå ðåçóëüòàòû ñðàçó æå ïîñëå çàïóñêà.
Çàêëþ÷åíèå Íà ýòîì ïðèìåðå â î÷åðåäíîé ðàç ïîêàçàíà ìîùü ÿçûêà Haskell â ÷àñòíîñòè è ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ â îáùåì â ðåøåíèè ðàñ÷¼òíûõ ìàòåìàòè÷åñêèõ çàäà÷. Ê ñîæàëåíèþ, ðàìêè ïðîñòîé íàó÷íî-ïîïóëÿðíîé êíèãè íå ïîçâîëÿþò ïðîâåñòè äàëüíåéøèå èññëåäîâàíèÿ è ïîêàçàòü âîçìîæíîñòè ïî ãðàôè÷åñêîé âèçóàëèçàöèè ïîëó÷åííûõ ðåçóëüòàòîâ. Äëÿ ýòîãî áûëî áû íåîáõîäèìî ïðåäâàðèòåëüíî îïèñàòü ãðàôè÷åñêèå áèáëèîòåêè, ÷òî ïîëíîñòüþ çàíÿëî áû íåñêîëüêî ðàçäåëîâ ïîäðÿä. Îäíàêî âäóì÷èâîìó ÷èòàòåëþ ìîæíî ïîðåêîìåíäîâàòü ñîçäàòü äëÿ òèïà Curve ýêçåìïëÿð êëàññà Show, êîòîðûé âûâîäèë áû çàäàííóþ Êðèâóþ Äðàêîíà â âèäå ïñåâäîãðàôèêè. Ýòî íå òàêàÿ ñëîæíàÿ çàäà÷à.
Íåìíîãî î øàõìàòíûõ çàäà÷àõ Ñòàòüÿ áûëà ïîäãîòîâëåíà ê ïóáëèêàöèè â æóðíàëå ¾Ïîòåíöèàë¿ îñåíüþ 2009 ãîäà. Îïóáëèêîâàíà íå áûëà.
Ýññå â çàíèìàòåëüíîé ôîðìå ðàññêàçûâàåò î ïðèìåíåíèè ïàðàäèãìû ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ è ÿçûêà Haskell äëÿ ðåøåíèÿ òàê íàçûâàåìûõ ¾øàõìàòíûõ çàäà÷¿ (íà ïðèìåðå çàäà÷è î ðàçìåùåíèè ôèãóð è çàäà÷è î õîäå êîíÿ).
Ââåäåíèå Øàõìàòû. Èñòîðèÿ ýòîé çàìå÷àòåëüíîé èãðû íàñ÷èòûâàåò íå îäíî ñòîëåòèå. Óìåíèå èãðàòü â øàõìàòû âñåãäà öåíèëîñü è èíîé ðàç ïî÷èòàëîñü çà äîñòîèíñòâî äååñïîñîáíîãî ÷ëåíà îáùåñòâà. Øàõìàòû èñïîëüçîâàëèñü â êà÷åñòâå ñðåäñòâà èñïûòàíèé è èíèöèàöèé, äëÿ ïðîñòîãî ðàçâëå÷åíèÿ è äëÿ ïëàíèðîâàíèÿ ñòðàòåãè÷åñêèõ äåéñòâèé íà ïîëå áîÿ. Ðóññêèå êíÿçüÿ è öàðè, åâðîïåéñêèå êîðîëè, àçèàòñêèå õàíû è ïàäèøàõè ó÷èëèñü èãðàòü â øàõìàòû ñ ìàëîãî äåòñòâà. Ñàìà èãðà ÿâëÿåòñÿ íåèñòîùèìûì èñòî÷íèêîì äëÿ äîñóãà. È ýòî îòíîñèòñÿ íå òîëüêî ê èãðå ñ ïðîòèâíèêîì, íî è ê ðåøåíèþ âñåâîçìîæíåéøèõ øàõìàòíûõ çàäà÷. È øàõìàòíûå çàäà÷è áûâàþò äâîÿêèå. Ñ îäíîé ñòîðîíû, ðåøåíèå îòíîñèòñÿ ê ïîèñêó êàêîé-ëèáî öåëåâîé ïîçèöèè èç çàäàííîé çà îïðåäåë¼ííîå êîëè÷åñòâî øàãîâ (íàïðèìåð, ïîñòàâèòü ìàò â äâà õîäà, íàéòè âèëêó èëè ñâÿçêó, âçÿòü ôåðçÿ ïðîòèâíèêà è ò. ä.). Ñ äðóãîé ñòîðîíû, ìîæíî ðåøàòü øàõìàòíûå ãîëîâîëîìêè, êîòîðûå îñíîâàíû íà ðàçíîîáðàçèè øàõìàò êàê ñèñòåìû ôèãóð íà äîñêå îïðåäåë¼ííîãî ðàçìåðà. Êëàññè÷åñêèìè ãîëîâîëîìêàìè â ýòîì îòíîøåíèè ÿâëÿþòñÿ çàäà÷à î ðàññòàíîâêå ôèãóð è çàäà÷à îá îáõîäå äîñêè ôèãóðîé (â ÷àñòíîñòè, íåòðèâèàëüíîé èç âñåõ îñòàëüíûõ ÿâëÿåòñÿ çàäà÷à îá îáõîäå âñåõ êëåòîê äîñêè êîí¼ì òàê, ÷òîáû â êàæäîé êëåòêå êîíü ïîáûâàë ëèøü åäèíîæäû, çàäà÷à î õîäå êîíÿ). Äàííûé ðàçäåë ðàññêàçûâàåò î òîì, êàê ðåøèòü îáå óïîìÿíóòûå çàäà÷è ïðè ïîìîùè ÿçûêà ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ Haskell.
Âñïîìîãàòåëüíûå ïðîãðàììíûå ñóùíîñòè Äëÿ ðåøåíèÿ çàäà÷ íåîáõîäèìî ïîäãîòîâèòü îïðåäåëåíèÿ ïðîãðàììíûõ ñóùíîñòåé, êîòîðûå íåîáõîäèìû äëÿ îïèñàíèÿ òåõ èëè èíûõ øàõìàòíûõ ïîíÿòèé. Òàê, íàïðèìåð, îäíà êëåòêà øàõìàòíîé äîñêè ìîæåò áûòü îïèñàíà ïàðîé êîîðäèíàòîé ïî âåðòèêàëè (îáû÷íî îáîçíà÷àåìîé ñòðî÷íîé ëàòèíñêîé áóêâîé) è êîîðäèíàòîé ïî ãîðèçîíòàëè (îáîçíà÷àåòñÿ ÷èñëîì). Ýòî ïîíÿòèå ìîæåò áûòü âûðàæåíî íà ÿçûêå Haskell ñëåäóþùèì îáðàçîì:
data Cell = Cell Int Int deriving Eq Íîâûé àëãåáðàè÷åñêèé òèï äàííûõ, à íå, ñêàæåì, ïàðà, áûë âûáðàí ïîòîìó, ÷òî äëÿ ýòîãî òèïà áóäåò íåîáõîäèìî îïðåäåëèòü ýêçåìïëÿðû íåñêîëüêèõ êëàññîâ, â ÷àñòíîñòè êëàññîâ Show (êëàññ òèïîâ,
120
Íåìíîãî î øàõìàòíûõ çàäà÷àõ
çíà÷åíèÿ êîòîðûõ ìîãóò áûòü ïðåîáðàçîâàíû â ñòðîêó) è Enum (êëàññ òèïîâ, çíà÷åíèÿ êîòîðûõ ìîãóò áûòü ïåðåñ÷èòàíû ïî ïîðÿäêó). Ýêçåìïëÿð äëÿ êëàññà Show îïðåäåëÿåòñÿ ñëåäóþùèì îáðàçîì:
instance Show Cell where show ( Cell f r ) = ( chr ( f + 9 6 ) ) : ( show r ) Òàêîå îïðåäåëåíèå ïîçâîëÿåò âûâîäèòü êëåòêó â ñòðîêó â ñòàíäàðòíîì âèäå. Íàïðèìåð, êëåòêà ñ êîîðäèíàòàìè (1, 1) ïðåîáðàçóåòñÿ â ñòðîêó ¾a1¿, êëåòêà ñ êîîðäèíàòàìè (8, 8) ïðåîáðàçóåòñÿ â ñòðîêó ¾h8¿ è ò. ä. Çäåñü ôóíêöèÿ chr èç ìîäóëÿ Data.Char ïîçâîëÿåò ïîëó÷èòü ñèìâîë òèïà Char ïî åãî êîäó. Ñèìâîë ¾a¿ èìååò äåñÿòè÷íûé êîä ASCII 97, ïîýòîìó äëÿ ïîëó÷åíèÿ ýòîãî ñèìâîëà è íåîáõîäèìî ïðèáàâèòü ê çàäàííîìó ÷èñëó äåëüòó 96. Äîïîëíèòåëüíî æåëàòåëüíî ðåàëèçîâàòü äâå óòèëèòàðíûå ôóíêöèè äëÿ ïîëó÷åíèÿ îòäåëüíûõ êîìïîíåíòîâ òèïà Cell. Ôóíêöèÿ file ¾äîñòà¼ò¿ âåðòèêàëü, à ôóíêöèÿ rank ãîðèçîíòàëü ñîîòâåòñòâåííî. Ýòî ìîæíî áûëî áû àáñîëþòíî òàê æå ñäåëàòü ïðè ïîìîùè îïðåäåëåíèÿ ñòðóêòóðû ñ èìåíîâàííûìè ïîëÿìè.
−− Âåðòèêàëü file : : Cell −> Int file ( Cell v h ) = v −− Ãîðèçîíòàëü rank : : Cell −> Int rank ( Cell v h ) = h Ñëåäóþùèì òèïîì, êîòîðûé íåîáõîäèìî îïðåäåëèòü, ÿâëÿåòñÿ ïåðå÷èñëåíèå äëÿ îáîçíà÷åíèÿ òèïîâ øàõìàòíûõ ôèãóð. Ýòî äîñòàòî÷íî ïðîñòî:
data Figure = Pawn | | | | |
Knight Bishop Rock Queen King
−− −− −− −− −− −−
Ïåøêà Êîíü Ñëîí Ëàäüÿ Ôåðçü Êîðîëü
Äëÿ ýòîãî òèïà îïÿòü æå íåîáõîäèìî îïðåäåëèòü ýêçåìïëÿð êëàññà Show äëÿ ïðåäñòàâëåíèÿ ôèãóð â ñîîòâåòñòâèè ñ ïðàâèëàìè øàõìàòíîé àëãåáðàè÷åñêîé íîòàöèè. Ýòî òàêæå íåñëîæíî:
instance Show Figure where show show show show show show
Pawn Knight Bishop Rock Queen King
= = = = = =
"p" "N" "B" "R" "Q" "K"
Äâå ñëåäóþùèå êîíñòàíòíûå ôóíêöèè íåîáõîäèìû äëÿ îáëåã÷åíèÿ ðàáîòû. Ïåðâàÿ, boardSize âîçâðàùàåò ðàçìåð øàõìàòíîé äîñêè (ïðåäïîëàãàåòñÿ, ÷òî ñàìà äîñêà êâàäðàòíàÿ), ÷òî ïîçâîëÿåò ñäåëàòü ãåíåðàëèçîâàííûå ôóíêöèè ðåøåíèÿ çàäà÷ äëÿ ëþáîãî ðàçìåðà äîñêè. Ïîêà ýòî áóäåò êîíñòàíòíàÿ ôóíêöèÿ, íåãàòèâíûì ìîìåíòîì ÷åãî ÿâëÿåòñÿ íåîáõîäèìîñòü ïåðåêîìïèëÿöèè èñõîäíîãî êîäà â ñëó÷àå èçìåíåíèÿ óñëîâèé.  ¾õîðîøåì¿ ðåøåíèè ðàçìåð øàõìàòíîé äîñêè ìîæíî áûëî áû ñ÷èòûâàòü èç ôàéëà èëè èç ñòàíäàðòíîãî ïîòîêà ââîäà, êîãäà ýòîò ïàðàìåòð ââîäèòñÿ ïîëüçîâàòåëåì (ñîîòâåòñòâåííî, îí äîëæåí ïåðåäàâàòüñÿ èç ôóíêöèè â ôóíêöèþ äëÿ ñëåäîâàíèÿ ïðàâèëüíîìó ñòèëþ ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ).
Âñïîìîãàòåëüíûå ïðîãðàììíûå ñóùíîñòè
121
boardSize : : Int boardSize = 8 Âòîðàÿ ôóíêöèÿ initialBoard âîçâðàùàåò ïîëíûé ñïèñîê ÿ÷ååê ïóñòîé äîñêè çàäàííîãî ðàçìåðà. Ýòà êîíñòàíòà áóäåò íåîáõîäèìà äëÿ íà÷àëüíîãî çàïóñêà ôóíêöèé ðåøåíèÿ çàäà÷.
initialBoard : : [ Cell ] initialBoard = [ Cell f r | f <− [ 1 . . boardSize ] , r <− [ 1 . . boardSize ] ] Íàêîíåö, íåîáõîäèìà ôóíêöèÿ, êîòîðàÿ äëÿ çàäàííîé ôèãóðû, êëåòêè, íà êîòîðîé òà ðàñïîëàãàåòñÿ, è òåêóùåãî ñîñòîÿíèÿ äîñêè âîçâðàùàåò ñïèñîê êëåòîê, íà êîòîðûõ ôèãóðà ìîæåò ïîõîäèòü. Ýòó ôóíêöèþ íàïèñàòü óæå íå òàê ïðîñòî, ïîñêîëüêó îíà äîëæíà îïèñûâàòü ïðàâèëà õîæäåíèÿ ôèãóð. Äëÿ êàæäîé ôèãóðû ñâîè ïðàâèëà, ïîýòîìó öåëåñîîáðàçíî ðàññìîòðåòü îïðåäåëåíèå ýòîé ôóíêöèè êëîç çà êëîçîì. Ïåðâûé êëîç îïèñûâàåò äâèæåíèå ïåøêè. Ïåøêà äâèæåòñÿ íà îäèí øàã âïåð¼ä, è ëèøü íà ïåðâîì õîäå, êîãäà îíà ñòîèò íà âòîðîé ãîðèçîíòàëè, ïåøêà ìîæåò ïîõîäèòü íà îäíó èëè íà äâå êëåòêè. Ýòîò ôàêò çàïèñûâàåòñÿ ñëåäóþùèì îáðàçîì:
legalMoves Pawn c@ ( Cell f r ) cs = i f ( r == 2 ) then intersect [ Cell r ( f + 1 ) , Cell r ( f + 2 ) ] cs el se intersect [ Cell f ( r + 1 ) ] cs Ôóíêöèÿ intersect èç ìîäóëÿ Data.List âîçâðàùàåò ïåðåñå÷åíèå äâóõ ñïèñêîâ, òî åñòü ñïèñîê òàêèõ è òîëüêî òàêèõ ýëåìåíòîâ, êîòîðûå èìåþòñÿ â îáîèõ ñïèñêàõ. Ýòà ôóíêöèÿ áóäåò èñïîëüçîâàòüñÿ âî âñåõ êëîçàõ ôóíêöèè legalMoves äëÿ îòñå÷åíèÿ òåõ âîçìîæíûõ õîäîâ, êîòîðûå íå âõîäÿò â ïåðå÷åíü êëåòîê òåêóùåãî ñîñòîÿíèÿ äîñêè (ýòî ñâîéñòâî áóäåò èñïîëüçîâàòüñÿ äëÿ òîãî, ÷òîáû íå ñòàâèòü ôèãóðû íà òå êëåòêè, êîòîðûå íå ïîäõîäÿò ïî óñëîâèÿì çàäà÷è, òàêèå êëåòêè ïðîñòî áóäóò èñêëþ÷àòüñÿ èç òåêóùåãî ñîñòîÿíèÿ äîñêè). Êîíü õîäèò áóêâîé ¾Ã¿, òî åñòü íà äâå êëåòêè â îäíîì íàïðàâëåíèè è íà îäíó â íàïðàâëåíèè, ïåðïåíäèêóëÿðíîì èñõîäíîìó. Ñ êëåòêè â ñåðåäèíå äîñêè êîíü ìîæåò ïîõîäèòü íà âîñåìü äðóãèõ êëåòîê, à èç óãëîâîé êëåòêè êîíü ìîæåò ïîõîäèòü íà äâå êëåòêè. Ñâîéñòâî, êîòîðîå ìîæíî èñïîëüçîâàòü äëÿ îïðåäåëåíèÿ íóæíûõ êëåòîê, çàêëþ÷àåòñÿ â òîì, ÷òî ñóììà àáñîëþòíûõ çíà÷åíèé ðàçíèö êîîðäèíàò èñõîäíîé è öåëåâîé êëåòîê âñåãäà ðàâíà òð¼ì.  ñâÿçè ñ ýòèì îïðåäåëåíèå ôóíêöèè ìîæåò áûòü òàêèì:
legalMoves Knight c@ ( Cell f r ) cs = intersect [ Cell f ' r ' | f ' <− [ f − 2 , f − 1 , f + 1 , f + 2 ] , r ' <− [ r − 2 , r − 1 , r + 1 , r + 2 ] , abs ( f ' − f ) + abs ( r ' − r ) == 3 ] cs Ñëîí õîäèò ïî äèàãîíàëè. Îáùåå ñâîéñòâî âñåõ êëåòîê, íà êîòîðûå ìîæåò ïîõîäèòü ñëîí ñ èñõîäíîé, çàêëþ÷àåòñÿ â òîì, ÷òî ëèáî ñóììà, ëèáî ðàçíîñòü êîîðäèíàò ýòèõ êëåòîê ðàâíà ñîîòâåòñòâåííî ñóììå èëè ðàçíîñòè êîîðäèíàò èñõîäíîé êëåòêè. Ñóììà âû÷èñëÿåò êëåòêè îñíîâíîé äèàãîíàëè, ðàçíîñòü ïîáî÷íîé ñîîòâåòñòâåííî. Îïðåäåëåíèå ôóíêöèè âûãëÿäèò òàê:
legalMoves Bishop c@ ( Cell f r ) cs = intersect [ Cell f ' r ' | f ' <− [ 1 . . boardSize ] , r ' <− [ 1 . . boardSize ] , ( ( f ' + r ' ) == ( f + r ) ) | | ( ( f ' − r ' ) == ( f − r ) ) , ( f ' /= f ) && ( r ' /= r ) ] cs Ëàäüÿ õîäèò ïî ãîðèçîíòàëè èëè âåðòèêàëè. Ñàìî ñîáîé ðàçóìååòñÿ, ÷òî ïðàâèëî äëÿ íå¼ âûãëÿäèò äîñòàòî÷íî ïðîñòî: âñå êëåòêè ñ îäèíàêîâîé êîîðäèíàòîé ïî ãîðèçîíòàëè èëè ïî âåðòèêàëè. Îïðåäåëåíèå
122
Íåìíîãî î øàõìàòíûõ çàäà÷àõ
íåñëîæíî (ôóíêöèÿ union èç ìîäóëÿ Data.List âîçâðàùàåò îáúåäèíåíèå äâóõ ñïèñêîâ, òî åñòü ñïèñîê, ñîñòîÿùèé èç ýëåìåíòîâ îáîèõ ñïèñêîâ):
legalMoves Rock c@ ( Cell f r ) cs = intersect ( union [ Cell f ' r | f ' <− [ 1 . . boardSize ] , f ' /= f ] [ Cell f r ' | r ' <− [ 1 . . boardSize ] , r ' /= r ] ) cs Ôóíêöèþ äëÿ ôåðçÿ íàïèñàòü åù¼ ïðîùå îí õîäèò êàê ñëîí è ëàäüÿ îäíîâðåìåííî:
legalMoves Queen c@ ( Cell f r ) cs = union ( legalMoves Bishop c cs ) ( legalMoves Rock c cs ) Îñòàëñÿ îäèí êîðîëü. Êîðîëü õîäèò íà îäíó êëåòêó â ëþáîì íàïðàâëåíèè. Äëÿ îïèñàíèÿ ýòîãî ïðîùå âñåãî ïåðå÷èñëèòü âñå âîçìîæíûå âîñåìü õîäîâ:
legalMoves King c@ ( Cell f r ) cs = intersect [ Cell ( f − 1 ) ( r − Cell f (r − Cell ( f + 1 ) ( r − Cell ( f − 1 ) r , Cell ( f + 1 ) r , Cell ( f − 1 ) ( r + Cell f (r + Cell ( f + 1 ) ( r +
1) , 1) , 1) ,
1) , 1) , 1 ) ] cs
Çäåñü (è â îïðåäåëåíèè ôóíêöèè äëÿ ïåøêè è êîíÿ) íåò íóæäû áåñïîêîèòüñÿ, ÷òî â íåêîòîðûõ ñëó÷àÿõ â ñïèñîê ìîãóò ïîïàñòü êëåòêè ñ îòðèöàòåëüíûìè çíà÷åíèÿìè èëè çíà÷åíèÿìè, âûõîäÿùèìè çà ãðàíèöû äîñêè. Ôóíêöèÿ intersect îòñå÷¼ò èõ. Èìåÿ âñå ïðèâåä¼ííûå â íàñòîÿùåì ðàçäåëå îïðåäåëåíèÿ ïðîãðàììíûõ ñóùíîñòåé, ìîæíî ïðèñòóïèòü ê ðåàëèçàöèè îñíîâíûõ ôóíêöèé äëÿ ðåøåíèÿ ïîñòàâëåííûõ çàäà÷.
Çàäà÷à î ðàññòàíîâêå ôèãóð Çàäà÷à î ðàññòàíîâêå øàõìàòíûõ ôèãóð ôîðìóëèðóåòñÿ äîñòàòî÷íî ïðîñòî. Äëÿ äîñêè ðàçìåðà n íåîáõîäèìî ðàññòàâèòü ìàêñèìàëüíîå ÷èñëî ýêçåìïëÿðîâ çàäàííîé øàõìàòíîé ôèãóðû òàê, ÷òîáû íè îäèí èç ýêçåìïëÿðîâ íå áèë íèêàêîé äðóãîé. Îáû÷íî çàäà÷à ôîðìóëèðóåòñÿ äëÿ ñòàðøèõ ôèãóð ôåðçÿ, ëàäüè, íî èíîãäà çàäà÷ó ìîæíî ñôîðìóëèðîâàòü è äëÿ ñëîíà è êîíÿ. Òàêæå îáû÷íî òðåáóåòñÿ íàéòè òàêîå ìàêñèìàëüíîå ÷èñëî ôèãóð, êîòîðîå ìîæíî óìåñòèòü íà äîñêå. Òàê, íàïðèìåð, äîêàçàíî, ÷òî íà äîñêå 8 × 8 ìîæíî ðàññòàâèòü ìàêñèìóì 8 ôåðçåé òàê, ÷òîáû íè îäèí èç íèõ íå áèë íèêàêîãî äðóãîãî (ìàòåìàòè÷åñêèì ïóò¼ì íàéäåíî, ÷òî òàêèõ ðàññòàíîâîê èìååòñÿ ðîâíî 92). Òî æå ñàìîå êàñàåòñÿ è ëàäåé, èõ ìîæíî ðàññòàâèòü 8 øòóê. Ïðè ýòîì çàäà÷à äëÿ ëàäåé èçîìîðôíà çàäà÷å î ïîèñêå òàê íàçûâàåìûõ ¾ëàòèíñêèõ êâàäðàòîâ¿. Ôóíêöèÿ arrangement äîëæíà âîçâðàùàòü âñå âîçìîæíûå ðàññòàíîâêè ýêçåìïëÿðîâ çàäàííîé øàõìàòíîé ôèãóðû íà äîñêå òàê, ÷òîáû íè îäèí èç íèõ íå áèë ëþáîé äðóãîé. Äëÿ ðåøåíèÿ ýòîé çàäà÷è ìîæíî âîñïîëüçîâàòüñÿ òåõíîëîãèåé ãåíåðàöèè ñïèñêîâ, êîòîðàÿ ïîäðîáíî îïèñàíà â ðàçäåëå ¾Ìàãè÷åñêèå êâàäðàòû è ðåøåíèå ïåðåáîðíûõ çàäà÷¿ (ñòð. 90). ż îïðåäåëåíèå òàêîâî:
arrangement : : Figure −> [ [ Cell ] ] arrangement f = arrangement ' f initialBoard
where
arrangement ' _ [ ] = [ [ ] ] arrangement ' f cs = [ cell : cells | cell <− cs ,
Çàäà÷à î õîäå êîíÿ
123
cells <− arrangement ' f ( cs \\ ( cell : legalMoves f cell cs ) ) ] Çäåñü ëîêàëüíîå îïðåäåëåíèå arrangement' îñóùåñòâëÿåò ïåðåáîð è ãåíåðàöèþ âàðèàíòîâ ìåòîäîì ¾ãðóáîé ñèëû¿. Íà êàæäîì øàãå èç ïåðå÷íÿ ÿ÷ååê òåêóùåé äîñêè âûáèðàåòñÿ î÷åðåäíàÿ ÿ÷åéêà, äëÿ êîòîðîé ðåøàåòñÿ òà æå ñàìàÿ çàäà÷à, íî ñîñòîÿíèå äîñêè óæå ïîäïðàâëåíî èç ïåðå÷íÿ ñâîáîäíûõ ÿ÷ååê èñêëþ÷åíà òåêóùàÿ ÿ÷åéêà, à òàêæå âñå òå, êîòîðûå íàõîäÿòñÿ ïîä áîåì çàäàííîé ôèãóðû. Èñêëþ÷åíèå ÿ÷ååê îñóùåñòâëÿåò îïåðàöèÿ (\\) èç ìîäóëÿ Data.List.  ïðèíöèïå, íè÷åãî ñëîæíîãî. Äðóãîå äåëî, ÷òî ýòà ôóíêöèÿ âîçâðàùàåò âñå âîçìîæíûå ðàññòàíîâêè, â òîì ÷èñëå è òàêèå, êîòîðûå ìîãóò íå ñîîòâåòñòâîâàòü äîïîëíèòåëüíûì òðåáîâàíèÿì. Íàïðèìåð, äëÿ ôåðçÿ äîïîëíèòåëüíûì óñëîâèåì ÿâëÿåòñÿ íàëè÷èå êîëè÷åñòâà ôåðçåö, ðàâíîãî ðàçìåðó äîñêè. À ôóíêöèÿ arrangement âîçâðàòèò âñå ðàññòàíîâêè ôåðçåö, äàæå òàêèå, êîëè÷åñòâî ôåðçåé â êîòîðûõ ìåíüøå. Äëÿ îòñå÷åíèÿ (ôèëüòðàöèè) íåíóæíûõ ðåçóëüòàòîâ ìîæíî ïîëüçîâàòüñÿ ñòàíäàðòíûìè ôóíêöèÿìè ÿçûêà Haskell (â ÷àñòíîñòè, ôóíêöèåé filter, êîòîðàÿ îïèñàíà â ñòàíäàðòíîì ìîäóëå Prelude), íî äëÿ ýòîãî òàêæå íåîáõîäèìî ðåàëèçîâàòü òðåáóåìûå ïðåäèêàòû, îïðåäåëÿþùèå äîïîëíèòåëüíûå óñëîâèÿ çàäà÷è. Íàïðèìåð, ïðåäèêàò, ïðîâåðÿþùèé êîëè÷åñòâî ôåðçåé â ðàññòàíîâêå, âûãëÿäèò òðèâèàëüíî:
validQueenArrangement : : [ Cell ] −> Bool validQueenArrangement cs = ( length cs ) == boardSize Åù¼ ìîæíî ðåàëèçîâàòü ôóíêöèþ, êîòîðàÿ áóäåò âûâîäèòü ðàññòàíîâêó ôèãóð â óäîáî÷èòàåìîì âèäå. ż ðåàëèçàöèÿ íå áóäåò ïðèâîäèòüñÿ â êíèãå, ïîñêîëüêó ðàáîòà íàä íåé ÿâëÿåòñÿ èíòåðåñíûì óïðàæíåíèåì, êîòîðîå ðåêîìåíäóåòñÿ çàèíòåðåñîâàííûì ÷èòàòåëÿì äëÿ ñàìîñòîÿòåëüíîãî ðåøåíèÿ.  ÷àñòíîñòè, ðåçóëüòàòîì ðàáîòû ïîäîáíîé ôóíêöèè äëÿ ïåðâîãî ýëåìåíòà ñïèñêà âîçìîæíûõ ðàññòàíîâîê âîñüìè ôåðçåé íà äîñêå ðàçìåðà 8 × 8 ÿâëÿåòñÿ ñëåäóþùàÿ ñòðîêà (êàê ðàç äëÿ îïðåäåëåíèÿ òàêîé ôóíêöèè è ïðèãîäèòñÿ ýêçåìïëÿð êëàññà Show äëÿ òèïà Figure): ..Q ..... ..... Q.. ...Q.... .Q . . . . . . .......Q ....Q... . . . . . . Q. Q.......
Çàäà÷à î õîäå êîíÿ Çàäà÷à î õîäå êîíÿ áûëà ðàñïðîñòðàíåíà â Ñðåäíèå âåêà â êà÷åñòâå äîñòàòî÷íî ñëîæíîé ãîëîâîëîìêè. Óñëîâèå ïðîñòîå: íåîáõîäèìî îáîéòè âñå êëåòêè øàõìàòíîé äîñêè ïðè ïîìîùè êîíÿ òàê, ÷òîáû êîíü ïîáûâàë â êàæäîé êëåòêå äîñêè ðîâíî îäèí ðàç. Íà÷èíàòü îáõîä äîñêè ìîæíî ñ ëþáîé êëåòêè. Îñîáûì øèêîì ñ÷èòàëîñü ðåøåíèå çàäà÷è òàê, ÷òîáû èç êîíå÷íîé êëåòêè ìàðøðóòà êîíÿ ìîæíî áûëî îïÿòü æå ïðè ïîìîùè ïîñëåäíåãî øàãà ïîïàñòü íà íà÷àëüíóþ êëåòêó (òàêèì îáðàçîì, ìàðøðóò ñòàíîâèëñÿ çàìêíóòûì). Ñ òî÷êè çðåíèÿ òåîðèè ãðàôîâ, ìàðøðóò êîíÿ íà äîñêå ÿâëÿåòñÿ ãàìèëüòîíîâûì ïóò¼ì (ëèáî ãàìèëüòîíîâûì öèêëîì, åñëè ìàðøðóò çàìêíóò). Çàäà÷à ïîèñêà ãàìèëüòîíîâà ïóòè â öèêëå ÿâëÿåòñÿ NP-ïîëíîé çàäà÷åé, òî åñòü òàêîé, âðåìÿ ðàáîòû àëãîðèòìà äëÿ ðåøåíèÿ êîòîðîé ñóùåñòâåííî çàâèñèò îò ðàçìåðà âõîäíûõ äàííûõ (â äàííîì ñëó÷àå îò ðàçìåðà øàõìàòíîé äîñêè). Äëÿ íåáîëüøèõ ðàçìåðîâ
124
Íåìíîãî î øàõìàòíûõ çàäà÷àõ
âõîäíûõ äàííûõ çàäà÷ó îïÿòü æå ìîæíî íåñëîæíî ðåøèòü ìåòîäîì ¾ãðóáîé ñèëû¿ (ïðîñòûì ïåðåáîðîì ñ îòñå÷åíèåì ÿâíî íåïðàâèëüíûõ ðåøåíèé). Ôóíêöèÿ, êîòîðàÿ ðåàëèçóåò ïåðåáîð äëÿ ïîèñêà ìàðøðóòà êîíÿ, ìîæåò áûòü ðåàëèçîâàíà íà îñíîâå ôóíêöèè äëÿ ïîèñêà ðàññòàíîâîê ôèãóð. Ó íèõ åñòü îáùàÿ âíóòðåííÿÿ ñòðóêòóðà, ñîáñòâåííî, è ñàìè çàäà÷è ÿâëÿþòñÿ â êàêîé-òî ìåðå ñõîæèìè. Òàê ÷òî îïðåäåëåíèå ôóíêöèè knightMoves âûãëÿäèò òàê:
knightMoves : : Cell −> [ [ Cell ] ] knightMoves c = knightMoves ' c initialBoard
where
knightMoves ' _ [ ] = [ [ ] ] knightMoves ' c b = i f ( null lm ) then [ [ c ] ] els e [ c : cells | cell <− lm , cells <− ( knightMoves ' cell ( delete c b ) ) ]
where
lm = legalMoves Knight c b Ôóíêöèÿ delete îïÿòü æå âçÿòà èç ìîäóëÿ Data.List (â í¼ì, êñòàòè, îïðåäåëåíî î÷åíü ìíîãî ïîëåçíûõ ôóíêöèé äëÿ ðàáîòû ñî ñïèñêàìè ïðîèçâîëüíîé ïðèðîäû). Ýòà ôóíêöèÿ óäàëÿåò èç ñïèñêà çàäàííûé ýëåìåíò (åãî ïåðâîå âõîæäåíèå). Çäåñü îïÿòü, êàê è â ñëó÷àå ôóíêöèè arrangement, ôóíêöèÿ âîçâðàùàåò âñå âîçìîæíûå ïóòè êîíÿ ïî øàõìàòíîé äîñêå, äàæå òå, äëèíà êîòîðûõ ìåíüøå êîëè÷åñòâà ÿ÷ååê íà äîñêå. Äëÿ îòðàæåíèÿ äîïîëíèòåëüíûõ óñëîâèé, êàê è â ïåðâîì ñëó÷àå, íåîáõîäèìî ðåàëèçîâàòü ñîîòâåòñòâóþùèå ïðåäèêàòû. Ïðåäèêàò äëÿ ïîèñêà è ôèëüòðàöèè ïóòåé, êîòîðûå ïîêðûâàþò âñå ÿ÷åéêè äîñêè, ðåàëèçîâàòü ïðîñòî:
validKnightMoves : : [ Cell ] −> Bool validKnightMoves cs = ( length cs ) == ( boardSize ^2) Íàêîíåö, çàèíòåðåñîâàííîìó ÷èòàòåëþ òàêæå ðåêîìåíäóåòñÿ ðåàëèçîâàòü ôóíêöèþ, êîòîðàÿ áóäåò âûâîäèòü ìàðøðóò êîíÿ íà äîñêå â óäîáî÷èòàåìîì âèäå. Íàïðèìåð, òàêîì (ôóíêöèÿ íå äîëæíà íàïðÿìóþ çàâèñåòü îò ðàçìåðà äîñêè, åãî íåîáõîäèìî áðàòü èç óæå îïðåäåë¼ííîé êîíñòàíòû): +−−+−−+−−+−−+−−+−−+−−+−−+ |20|15|22|45|58|47|38|43| +−−+−−+−−+−−+−−+−−+−−+−−+ |17|04|19|48|37|44|59|56| +−−+−−+−−+−−+−−+−−+−−+−−+ |14|21|16|23|46|57|42|39| +−−+−−+−−+−−+−−+−−+−−+−−+ |03|18|05|36|49|40|55|60| +−−+−−+−−+−−+−−+−−+−−+−−+ |06|13|08|29|24|35|50|41| +−−+−−+−−+−−+−−+−−+−−+−−+ |09|02|11|32|27|52|61|54| +−−+−−+−−+−−+−−+−−+−−+−−+ |12|07|28|25|30|63|34|51| +−−+−−+−−+−−+−−+−−+−−+−−+ |01|10|31|64|33|26|53|62| +−−+−−+−−+−−+−−+−−+−−+−−+
Çàäà÷à î õîäå êîíÿ
125
Çàêëþ÷åíèå Òàêèì îáðàçîì, â ðàçäåëå íàïèñàíû äâå îáîáù¼ííûå ôóíêöèè äëÿ ðåøåíèÿ èíòåðåñíûõ è ÷àñòî âñòðå÷àþùèõñÿ íà ïðàêòèêå øàõìàòíûõ çàäà÷. ×èòàòåëè ìîãóò èñïîëüçîâàòü èõ äëÿ ïîèñêà ðåøåíèé ïîäîáíûõ øàõìàòíûõ çàäà÷ äëÿ ïðîèçâîëüíûõ ôèãóð. Êàê îáû÷íî, êîäèðîâàíèå ñóùíîñòåé ïðîáëåìíîé îáëàñòè íà ÿçûêå Haskell ïîêàçûâàåò ýôôåêòèâíîñòü è ïðèñïîñîáëåííîñòü ýòîãî ÿçûêà äëÿ âûðàæåíèÿ çàäà÷. Íàïðèìåð, èíòåðåñíîé çàäà÷åé áóäåò ïîèñê äëÿ çàäàííîé ïîçèöèè õîäà, ñòàâÿùåãî ìàò êîðîëþ ïðîòèâíèêà (ìàò â îäèí õîä). Èñïîëüçóÿ ôóíêöèè, îïèñàííûå â äàííîì ðàçäåëå, à òàêæå òåõíèêè ïåðåáîðà (ñì. ðàçäåë ¾Ìàãè÷åñêèå êâàäðàòû è ðåøåíèå ïåðåáîðíûõ çàäà÷¿, ñòð. 90), ìîæíî äîñòàòî÷íî òðèâèàëüíî íàéòè òàêîå ðåøåíèå. Ñëåäóþùèì øàãîì áóäåò ðåøåíèå çàäà÷è î ìàòå â äâà è áîëåå õîäîâ. Òàê ÷òî åñòü ïðîñòîð äëÿ òâîð÷åñòâà.
Ãåíåðàöèÿ ðåêóðñèâíûõ ñêàçîê Ñòàòüÿ áûëà îïóáëèêîâàíà â 11 (47) è 12 (48) æóðíàëà ¾Ïîòåíöèàë¿ â íîÿáðå è äåêàáðå 2008 ãîäà.
 íàñòîÿùåì ýññå îïèñûâàåòñÿ îäíà èç èíòåðåñíåéøèõ ïðèêëàäíûõ çàäà÷ ãåíåðàöèÿ åñòåñòâåííîÿçûêîâûõ òåêñòîâ íà ïðèìåðå òàê íàçûâàåìûõ ðåêóðñèâíûõ ñêàçîê èç ÷èñëà ðóññêèõ íàðîäíûõ. Ïðèâîäÿòñÿ ïðîãðàììû íà ôóíêöèîíàëüíîì ÿçûêå ïðîãðàììèðîâàíèÿ Haskell, êîòîðûå ïðîèçâîäÿò ãåíåðàöèþ òåêñòîâ ñêàçîê ¾Êîëîáîê¿, ¾Òåðåìîê¿ è ¾Ðåïêà¿ íà îñíîâå ñïèñêà äåéñòâóþùèõ ëèö.
Ââåäåíèå Çà ñîòíè è äàæå òûñÿ÷è ëåò ñâîåãî ñóùåñòâîâàíèÿ ðóññêèé íàðîä ñîçäàë øèðî÷àéøèé ïëàñò ôîëüêëîðíîãî òâîð÷åñòâà ðóññêèå íàðîäíûå ñêàçêè.  ñâîþ î÷åðåäü, îíè ïîäðàçäåëÿþòñÿ íà íåñêîëüêî êëàññîâ âîëøåáíûå, áûòîâûå, ñêàçêè î æèâîòíûõ è äð. Åù¼ îäíèì èç òàêèõ êëàññîâ ÿâëÿþòñÿ òàê íàçûâàåìûå ðåêóðñèâíûå ñêàçêè, êîòîðûå îáû÷íî ðàññêàçûâàþòñÿ ñàìûì ìàëåíüêèì äåòÿì, ïîñòîÿííîå ïîâòîðåíèå îäíîãî è òîãî æå ñþæåòà ñ ïîñòåïåííûì íàðàùèâàíèåì ïîçâîëÿåò äåòÿì çàó÷èâàòü ñëîâà; ðàçìåðåííûé ðèòì ñêàçêè ïîìîãàåò óñíóòü. Ðåêóðñèâíûå ñêàçêè òîæå ðàçäåëÿþòñÿ íà íåñêîëüêî âèäîâ, íåêîòîðûå èç êîòîðûõ íå òàê èíòåðåñíû (íàïðèìåð, ñêàçêà ïðî áåëîãî áû÷êà, êîòîðàÿ íèêîãäà íå çàêàí÷èâàåòñÿ). Áîëåå èíòåðåñíû ñêàçêè ñ ¾ðàñêðó÷èâàþùèìñÿ¿ ñþæåòîì, â êîòîðûõ îñíîâíîå äåéñòâèå ïîâòîðÿåòñÿ ñ êàæäûì íîâûì äåéñòâóþùèì ëèöîì, ïîêà íå íàñòóïàåò êóëüìèíàöèÿ. Òàêîâû âñåì èçâåñòíûå ñêàçêè ïðî êîëîáêà, ïðî òåðåìîê (â íåêîòîðûõ âàðèàíòàõ ïðî ïîòåðÿííóþ ìóæèêîì â ëåñó ðóêàâè÷êó), ïðî ðåïêó. È êòî â äåòñòâå íå ïûòàëñÿ ïðîíèêíóòü â ñóòü òàêèõ ñêàçîê, åù¼ íå ïîíèìàÿ ïðèíöèïà , êîãäà ïî ñîáñòâåííîìó ðàçóìåíèþ äîáàâëÿë â ïåðå÷åíü äåéñòâóþùèõ ëèö íîâûõ è íîâûõ ïåðñîíàæåé? Èññëåäîâàòåëè íàðîäíîãî òâîð÷åñòâà äàâíî ïðèìåòèëè òàêóþ îñîáåííîñòü ðåêóðñèâíûõ ñêàçîê, êàê ¾ðàñêðó÷èâàíèå¿ ñþæåòà äî êóëüìèíàöèè. Áîëåå òîãî, âî âñåõ ñêàçêàõ âûäåëÿåòñÿ îäíà ñòðóêòóðà, îäèí ¾ ¿. Åñëè îïèñûâàòü êðàòêî, òî òàêîé ïàòòåðí çàêëþ÷àåòñÿ â òîì, ÷òî íà îáû÷íóþ ñòðóêòóðó ïîâåñòâîâàíèÿ ïðîçàè÷åñêîãî ïðîèçâåäåíèÿ (ïðîëîã äåéñòâèå ýïèëîã) íàêëàäûâàåòñÿ äîïîëíèòåëüíûé ðåêóðñèâíûé ïåðåáîð äåéñòâóþùèõ ëèö, èíîãäà ñ çàãëÿäûâàíèåì âïåð¼ä. Ïåðâîå äåéñòâóþùåå ëèöî îñóùåñòâëÿåò ¾çà÷èí¿, âñå ïîñëåäóþùèå äåëàþò ñâî¼ äåëî, à ïîñëåäíèé ïåðñîíàæ ïðèâîäèò âñ¼ äåéñòâèå ê ñâîåé êóëüìèíàöèè. Íà îñíîâå ðåçóëüòàòîâ òàêèõ èññëåäîâàíèé ìîæíî ïîïðîáîâàòü íàïèñàòü íåáîëüøèå êîìïüþòåðíûå ïðîãðàììû, êîòîðûå, áóäó÷è ñàìè íåáîëüøèìè ïî ðàçìåðó, ïîçâîëÿëè áû ãåíåðèðîâàòü ñêàçêè íà îñíîâå âõîäíûõ ñïèñêîâ äåéñòâóþùèõ ëèö íåîãðàíè÷åííîé äëèíû. Ñàìî ñîáîé ðàçóìååòñÿ, ÷òî äëÿ òàêèõ öåëåé â ñèëó ðåêóðñèâíîñòè ìîòèâà ñêàçîê öåëåñîîáðàçíî ïðèìåíÿòü ôóíêöèîíàëüíóþ ïàðàäèãìó ïðîãðàììèðîâàíèÿ. Íèæå â íàñòîÿùåì ðàçäåëå ïðèâîäÿòñÿ ïðèìåðû ãåíåðàòîðîâ ñêàçîê íà ÿçûêå ïðîãðàììèðîâàíèÿ Haskell, à òàêæå äåëàåòñÿ ïîïûòêà ñîçäàíèÿ îáîáù¼ííîãî ãåíåðàòîðà â âèäå .
âû÷èñëåíèé
ðåêóðñèâíûõ
ïàòòåðí
âûñøåãî ïîðÿäêà
ôóíêöèè
Êîëîáîê
127
Âñå ïðåäëàãàåìûå ê èçó÷åíèþ ïðèìåðû ïðèâîäÿòñÿ â êëàññè÷åñêîì âàðèàíòå. Çàèíòåðåñîâàííûé ÷èòàòåëü ìîæåò ñàìîñòîÿòåëüíî ãåíåðèðîâàòü íîâûå âàðèàíòû ñîîòâåòñòâóþùèõ ñêàçîê, ïðîèçâîëüíî ìåíÿÿ ñïèñîê äåéñòâóþùèõ â íèõ ëèö.
Êîëîáîê Êîëîáîê áûë èñïå÷¼í áàáêîé ïî íàêàçó äåäà èç ìàëîé ãîðñòêè ìóêè. Íå äîæäàâøèñü òîãî, ÷òî äåä ïðèñòóïèò ê òðàïåçå, êîëîáîê ñîñêî÷èë íà òðîïèíêó îêîëî èçáóøêè è ïîêàòèëñÿ â ëåñ.  ëåñó îí ïîñòîÿííî âñòðå÷àë ðàçëè÷íûõ ïåðñîíàæåé, êàæäîìó èç êîòîðûõ ïåë ïåñåíêó, óïîìèíàÿ ïðè ýòîì âñåõ ïðåäûäóùèõ âñòðå÷åííûõ ëèö ( ), ÷åì ââîäèë èõ â ñìÿòåíèå, è óñêîëüçàë îò õèùíîé ïàñòè. Íàêîíåö, êîëîáîê âñòðåòèë íàèáîëåå õèòðîãî çâåðÿ (ëèñó), êîòîðûé åãî îáìàíóë è ñúåë (êóëüìèíàöèÿ). Êàê óêàçàíî âî ââåäåíèè, âñÿ êàíâà ñêàçêè óêëàäûâàåòñÿ â ïðîñòóþ ñõåìó ¾ïðîëîã äåéñòâèå ýïèëîã¿. Ýòîò ôàêò çàïèñàòü íà ÿçûêå Haskell ïðîùå âñåãî. Ñ ýòîãî ìîæíî è íà÷àòü:
ðåêóðñèÿ
kolobok : : String kolobok = prologue ++ act ++ epilogue Åñòåñòâåííî, ÷òî íèêàêèõ òàêèõ ôóíêöèé prologue, act è epilogue åù¼ íåò, èõ íåîáõîäèìî òîëüêî ñîçäàòü. Ïåðâàÿ è ïîñëåäíÿÿ ðåàëèçóþòñÿ î÷åíü ïðîñòî:
prologue : : String prologue = " Æèëè−áûëè äåä è áàáà . Âîò îäíàæäû äåä è ãîâîðèò áàáå : \ n " ++ "− Èñïåêè−êà ìíå , ñòàðàÿ , êîëîáîê . \ n " ++ "− Äà èç ÷åãî æ ÿ åãî èñïåêó−òî ? Ìóêè âåäü íåò . \ n " ++ "− À òû ïî àìáàðàì ïîìåòè , ïî ñóñåêàì ïîñêðåáè , " ++ " àâîñü ìóêà è íàáåð¼òñÿ . \ n " ++ " Íó , áàáà ïî àìáàðàì ïîìåëà , ïî ñóñåêàì ïîñêðåáëà , " ++ " íàáðàëà ãîðñòè äâå ìóêè . " ++ " Çàìåñèëà òåñòî íà ñìåòàíå , ñëåïèëà êîëîáîê , " ++ " èçæàðèëà åãî â ìàñëå è ïîñòàâèëà íà îêíî ïðîñòûíóòü . \ n " ++ " Êîëîáîê ëåæàë−ëåæàë , ñêó÷íî åìó ñòàëî , " ++ " âîò îí è ïðûãíóë ñ îêíà íà çàâàëèíêó , " ++ " ñ çàâàëèíêè íà ëàâêó , ñ ëàâêè íà äîðîæêó " ++ " è ïîêàòèëñÿ ïî íåé â ëåñ . \ n " è
epilogue : : String epilogue = "" Ýïèëîã ó ýòîé ñêàçêè íå ðåàëèçîâàí, ïîòîìó êàê, êîãäà ëèñà ñúåäàåò êîëîáêà, íè÷åãî áîëüøå íå ïðîèñõîäèò. À âîò â ôóíêöèè prologue ñêðûòà îäíà íåïðèÿòíàÿ ëîãè÷åñêàÿ îøèáêà â íåé â âèäå êîíñòàíò óïîìèíàþòñÿ òàêèå äåéñòâóþùèå ïåðñîíàæè, êàê ¾äåä¿ è ¾áàáà¿, ÷òî ìîæåò ïðèâåñòè ê íåïðèÿòíûì ïîñëåäñòâèÿì, åñëè èìåòü æåëàíèå âíåñòè èõ â ñïèñîê äåéñòâóþùèõ ëèö. Íî ïîêà ïðîâîäèòñÿ èññëåäîâàíèå âíóòðåííåé ñòðóêòóðû ñêàçêè, ïóñòü áóäåò òàê ñïèñîê ïåðñîíàæåé íà÷í¼òñÿ ñ çàéöà. Ñàìîå èíòåðåñíîå íà÷èíàåòñÿ ïðè ïîïûòêå ðåàëèçîâàòü ôóíêöèþ act, êîòîðàÿ äîëæíà ïåðåáèðàòü ïåðå÷åíü äåéñòâóþùèõ ëèö. Äëÿ å¼ ðàáîòû ïðåæäå âñåãî íåîáõîäèì êàê ðàç ýòîò ïåðå÷åíü, à äëÿ åãî ñîçäàíèÿ â âèäå ñïèñêà íåîáõîäèì òèï, îïèñûâàþùèé îäíî äåéñòâóþùåå ëèöî. Òàêîé òèï ïðîùå âñåãî îïðåäåëèòü â âèäå ñòðóêòóðû ñ èìåíîâàííûìè ïîëÿìè, êîòîðûõ áóäåò ÷åòûðå òðè äëÿ íàèìåíîâàíèÿ
128
Ãåíåðàöèÿ ðåêóðñèâíûõ ñêàçîê
ïåðñîíàæà â èìåíèòåëüíîì, ðîäèòåëüíîì è âèíèòåëüíîì ïàäåæàõ (âñå ýòè ôîðìû âñòðå÷àþòñÿ â òåêñòå ñêàçêè), à òàêæå äëÿ óêàçàíèÿ ïîëà ïåðñîíàæà, ÷òîáû ïðàâèëüíî ãåíåðèðîâàòü ôîðìó ãëàãîëà â ïðîøåäøåì âðåìåíè. Òàêèì îáðàçîì òèï Actor âûãëÿäèò ñëåäóþùèì îáðàçîì:
data Actor = Actor {
name name_g name_a gender
:: :: :: ::
String , String , String , Gender
}
deriving Eq Íó è âñïîìîãàòåëüíûé òèï Gender ÿâëÿåòñÿ ïðîñòûì ïåðå÷èñëåíèåì:
data Gender = Male | Female | It
deriving Eq
Ïîñêîëüêó ïîë èñïîëüçóåòñÿ äëÿ ãåíåðàöèè îêîí÷àíèÿ ãëàãîëà â ïðîøåäøåì âðåìåíè, öåëåñîîáðàçíî ñðàçó ðåàëèçîâàòü ñîîòâåòñòâóþùèå ôóíêöèè. Èõ áóäåò äâå, ïîñêîëüêó â ðóññêîì ÿçûêå èìååòñÿ ðÿä íåðåãóëÿðíûõ ãëàãîëîâ, ó êîòîðûõ íåò êàíîíè÷åñêîãî îêîí÷àíèÿ ¾-ë¿ äëÿ ìóæñêîãî ðîäà: ¾ñìîã¿, ¾ïðåíåáð¼ã¿, ¾í¼ñ¿ è ò. ä., ýòî ãëàãîëû ñ îêîí÷àíèÿìè íà ¾-÷ü¿ è ¾-òè¿ â íåîïðåäåë¼ííîé ôîðìå. Èòàê, ôóíêöèè:
ending ending ending ending ending ' ending ' ending ' ending '
: : Gender −> String Male = "" Female = " à " It = "î" : : Gender −> String Male = "" Female = " ëà " It = " ëî "
Ôóíêöèÿ ending' áóäåò èñïîëüçîâàòüñÿ êàê ðàç äëÿ íåðåãóëÿðíûõ ãëàãîëîâ. Òåïåðü ìîæíî îïðåäåëèòü ïåðå÷åíü äåéñòâóþùèõ ëèö (åù¼ ðàç íåîáõîäèìî íàïîìíèòü, ÷òî èñïîëüçóåòñÿ òðàäèöèîííîå ïðåäñòàâëåíèå ýòîé ñêàçêè):
actors : : [ Actor ] actors = [ Actor " Çàÿö " Actor " Âîëê " Actor " Ìåäâåäü " Actor " Ëèñà "
" Çàéöà " " Âîëêà " " Ìåäâåäÿ " " Ëèñû "
" Çàéöó " " Âîëêó " " Ìåäâåäþ " " Ëèñå "
Male , Male , Male , Female ]
Âðîäå áû âñ¼ ãîòîâî, ÷òîáû ðåàëèçîâàòü ôóíêöèþ act, äëÿ êîòîðîé áûëà ïðîèçâåäåíà ïîäãîòîâèòåëüíàÿ ðàáîòà. Îäíàêî, åñëè âñïîìíèòü å¼ òèï, êîòîðûé ÿâëÿåòñÿ ïðîñòîé ñòðîêîé String, ñòàíîâèòñÿ ïîíÿòíî, ÷òî ýòà ôóíêöèÿ äîëæíà ñîñòîÿòü èç åäèíñòâåííîãî êëîçà, êîòîðûé âûçûâàåò äîïîëíèòåëüíóþ (è âîçìîæíî, äàæå ëîêàëüíóþ) ôóíêöèþ act', â êîòîðîé è îñóùåñòâëÿåòñÿ ðåêóðñèâíûé ïåðåáîð óæå èìåþùåãîñÿ ñïèñêà actors. Äðóãèìè ñëîâàìè, ðåàëèçàöèÿ ôóíêöèè act èñïîëüçóåò òåõíîëîãèþ , ïåðåäàâàÿ â äîïîëíèòåëüíóþ ôóíêöèþ ñïèñîê îñòàâøèõñÿ äåéñòâóþùèõ ëèö, ñïèñîê óæå ïåðå÷èñëåííûõ ïåðñîíàæåé, à òàêæå íà÷àëüíîå çíà÷åíèå ðåçóëüòàòà:
íàêàïëèâàþùåãî ïàðàìåòðà
Êîëîáîê
129
act : : String act = act ' actors [ ] ""
where
act ' act ' act ' act '
: : [ Actor ] −> [ Actor ] −> String −> String [] _ result = result [a] i result = result ++ ( finalAct a i ) ( a : as ) i result = act ' as ( i ++ [ a ] ) ( result ++ ( interimAct a i ) )
Ôóíêöèè interimAct è finalAct åù¼ äîëæíû áûòü îïðåäåëåíû. Ýòè ôóíêöèè âîçâðàùàþò, ñîîòâåòñòâåííî, ñòðîêè, îïèñûâàþùèå ïðîìåæóòî÷íîå äåéñòâèå è îêîí÷àòåëüíîå äåéñòâèå ïîñëåäíåãî äåéñòâóþùåãî ëèöà (êóëüìèíàöèþ). Êàê âèäíî, îáå ýòè ôóíêöèè ïðèíèìàþò íà âõîä òåêóùåãî ïåðñîíàæà, à òàêæå ñïèñîê óæå ïðîéäåííûõ äåéñòâóþùèõ ëèö (îáîçíà÷åí ïàðàìåòðîì i). Ñàìà ôóíêöèÿ act' ïðîñòî ñîáèðàåò ðåçóëüòàò ðåêóðñèâíîãî ïåðåáîðà ñïèñêà ïåðñîíàæåé â ïàðàìåòðå result, çíà÷åíèå êîòîðîãî âîçâðàùàåòñÿ ôóíêöèåé ïðè äîñòèæåíèè ïóñòîãî ñïèñêà.  ýòîì è ñîñòîèò ñóòü òåõíîëîãèè èñïîëüçîâàíèÿ íàêàïëèâàþùåãî ïàðàìåòðà (èíà÷å íàçûâàåìîãî ). Åñëè ïîñìîòðåòü íà ïîñëåäíèé êëîç ôóíêöèè act', òî âèäíî, ÷òî ïðîèçâîäèòñÿ íåïîñðåäñòâåííî ðåêóðñèâíûé âûçîâ òîé æå ôóíêöèè, à âñå âû÷èñëåíèÿ ïðîèçâîäÿòñÿ ïðè ïåðåäà÷å íîâûõ çíà÷åíèé ïàðàìåòðîâ. Ñîâðåìåííûå êîìïèëÿòîðû ÿçûêà Haskell ïðîèçâîäÿò îïòèìèçàöèþ ïîäîáíûõ âû÷èñëåíèé, ïðîèçâîäÿ èõ â ïîñòîÿííîì îáú¼ìå ïàìÿòè (ïðè ïîìîùè èòåðàöèé). Ïðîñòî ðåàëèçîâàòü ôóíêöèþ interimAct.  íåé áóäåò èñïîëüçîâàòüñÿ åù¼ îäíà äîïîëíèòåëüíàÿ ôóíêöèÿ meet, êîòîðàÿ âîçâðàùàåò ñòàíäàðòíîå äëÿ âñåõ ïåðñîíàæåé ñêàçêè îïèñàíèå âñòðå÷è êîëîáêà ñ íèìè. Ïîñêîëüêó äëÿ ïîñëåäíåãî ïåðñîíàæà (ëèñû) îïèñàíèå âñòðå÷è àáñîëþòíî òàêîå æå, öåëåñîîáðàçíî âûíåñòè îäèíàêîâûå ñòðîêè â îäíó ñòðîêó. Ïðè ýòîì íàäî âñïîìíèòü, ÷òî äëÿ ïåðâîãî äåéñòâóþùåãî ëèöà âñ¼-òàêè èìååòñÿ íåáîëüøîå îòëè÷èå, êîòîðîå ìîæíî îáðàáîòàòü ïðè ïîìîùè áàíàëüíîãî óñëîâèÿ if :
àêêóìóëÿòîðîì
interimAct : : Actor −> [ Actor ] −> String interimAct actor i = meet actor i ++ " Ïðûãíóë êîëîáîê , òîëüêî " ++ an ++ " åãî è âèäåë " ++ ae ++ " . \ n "
where
an = name actor ae = ending $ gender actor meet : : Actor −> [ Actor ] −> String meet actor i = " Êàòèòñÿ êîëîáîê " ++ ( i f ( i == [ ] ) then " ïî òðîïèíêå " el se " äàëüøå " ) ++ " , à íàâñòðå÷ó åìó " ++ an ++ " . " ++ " Óâèäåë " ++ ae ++ " " ++ an ++ " êîëîáêà è ãîâîðèò åìó : \ n " ++ "− Êîëîáîê , êîëîáîê , ÿ òåáÿ ñúåì . \ n " ++ " À êîëîáîê îòâå÷àåò : \ n " ++ "− Íå åøü ìåíÿ , " ++ an ++ " , ëó÷øå ïîñëóøàé , êàêóþ ÿ òåáå ïåñåíêó ñïîþ . \ n " ++ " È çàïåë : \ n " ++ song actor i
where
an = name actor ae = ending $ gender actor
130
Ãåíåðàöèÿ ðåêóðñèâíûõ ñêàçîê
Ñàìàÿ èíòåðåñíàÿ ôóíêöèÿ song îïÿòü âûäåëåíà îòäåëüíî, íî òåïåðü óæå áîëüøå äëÿ ýñòåòè÷åñêèõ öåëåé (îíà èñïîëüçóåòñÿ òîëüêî â ôóíêöèè meet.  ýòîé ôóíêöèè êàê ðàç è ïðîèñõîäèò ðåêóðñèâíûé ïåðåáîð óæå âñòðå÷åííûõ ðàíåå ïåðñîíàæåé êîëîáîê ïî¼ò ñâîþ ïåñåíêó:
song : : Actor −> [ Actor ] −> String song actor i = " ß − êîëîáîê , êîëîáîê . \ n " ++ " Êîëîáîê − ðóìÿíûé áîê . \ n " ++ " Ïî àìáàðàì ìåò¼í . \ n " ++ " Ïî ñóñåêàì ñêðåá¼í . \ n " ++ " Íà ñìåòàíå ìåø¼í . \ n " ++ "  æàðêîé ïå÷êå ïå÷¼í . \ n " ++ " Íà îêîøêå ñòóæ¼í . \ n " ++ " ß îò áàáóøêè óø¼ë . \ n " ++ " ß îò äåäóøêè óø¼ë . \ n " ++ song ' actor i ""
where
song ' actor [ ] = result ++ " À ", è song ' actor ( i : is ) = song ' actor is
result îò òåáÿ , " ++ ( name actor ) ++ ïîäàâíî óéäó ! \ n " result ( result ++ " ß îò " ++ ( name_g i ) ++ " óø¼ë . \ n " )
Òåïåðü îñòàëîñü íàïèñàòü êîä ôóíêöèè finalAct, êîòîðûé, âïðî÷åì, áóäåò ñîñòîÿòü èç âûçîâà âñ¼ òîé æå ôóíêöèè meet è ñòðîê ñ îïèñàíèåì êóëüìèíàöèè:
finalAct : : Actor −> [ Actor ] −> String finalAct actor i = meet actor i ++ " À " ++ an ++ " è ãîâîðèò åìó : \ n " ++ "− Àõ , êàêàÿ õîðîøàÿ ïåñåíêà . Òîëüêî âîò ñëàá " ++ ae ++ " ÿ íà óøè ñòàë " ++ ae ++ " . " ++ " Áóäü ëþáåçåí , ïðûãíè êî ìíå íà íîñ " ++ " è ñïîé ñâîþ ïåñåíêó åù¼ ðàç . \ n " ++ " À êîëîáîê è ðàä , ÷òî åãî ïåñåíêó ïîõâàëèëè . " ++ " Ïðûãíóë îí " ++ ( name_a actor ) ++ " íà íîñ è òîëüêî õîòåë ñíîâà çàïåòü , " ++ " à " ++ an ++ " åãî \" Öàï ! \ " è ñúåë " ++ ae ++ " . \ n "
where
an = name actor ae = ending $ gender actor Ãåíåðàòîð ñêàçêè ¾Êîëîáîê¿ ãîòîâ. Êîíå÷íî, ìîæíî çàäàòüñÿ âîïðîñîì â ÷¼ì ïðåëåñòü? À ñóòü â òîì, ÷òî ýòîò ãåíåðàòîð áóäåò ñîçäàâàòü íîâûå ñêàçêè âíîâü è âíîâü, êàê òîëüêî ìåíÿåòñÿ ñïèñîê ïåðñîíàæåé. Ãëàâíîå îïèñûâàòü èõ ñ íåîáõîäèìîé òî÷íîñòüþ, çàäàâàÿ òðè ïàäåæà èõ èì¼í è ïîë äëÿ ãåíåðàöèè ïðàâèëüíîãî îêîí÷àíèÿ ãëàãîëîâ â ïðîøåäøåì âðåìåíè. È ýòîò êîä íà ïîëòîðû ñòðàíèöû ìîæåò ãåíåðèðîâàòü ñêàçêè íà ìíîãèå è ìíîãèå ñòðàíèöû. Êîíå÷íî, äàííûé êîä íå áåç îãðåõîâ ê ïðèìåðó, â òð¼õ ôóíêöèÿõ âñòðå÷àþòñÿ àáñîëþòíî èäåíòè÷íûå ëîêàëüíûå îïðåäåëåíèÿ. Íî â öåëîì îí ïðåäñòàâëÿåò ñîáîé äîñòàòî÷íî ïðîñòîé è ýôôåêòèâíûé ïðèìåð ãåíåðàòîðà åñòåñòâåííî-ÿçûêîâîãî òåêñòà ñïåöèàëüíîãî âèäà.
Òåðåìîê
131
Òåðåìîê  ëåñó îðãàíèçîâàëîñü íåêîòîðîå ìåñòî äëÿ æèëüÿ òåðåìîê (òî ëè ãíèëîé ïåíü, òî ëè îáðîíåííûé ïðîõîäÿùèì ìóæ÷èíîé ÷óãóíîê èëè ïîòåðÿííàÿ ðóêàâè÷êà). Ê ýòîìó òåðåìêó íà÷àëè ïîäáåãàòü ðàçëè÷íûå æèòåëè ëåñà, êîòîðûå ñïðàøèâàëè, êòî ïðîæèâàåò â òàêîì çíàòíîì äîìèêå. Âñå, êòî óæå ïîñåëèëñÿ â í¼ì, âûõîäèëè íàðóæó è ïðåäñòàâëÿëèñü ( ), ïîñëå ÷åãî ïðèçûâàëè âíîâü ïðèáûâøåãî ïðèñîåäèíèòüñÿ ê èõ âåñ¼ëîé êîìïàíèè. Íàêîíåö ê òåðåìêó ïîäõîäèò îãðîìíûé çâåðü (ìåäâåäü), êîòîðûé íó íèêàê íå ìîã âòèñíóòüñÿ è â áåç òîãî óæå òåñíîå ïðîñòðàíñòâî, à ïîòîìó ïîëåç íà êðûøó. Ýòî äåéñòâèå ïàãóáíî îòðàæàåòñÿ íà ñòðîåíèè, êîòîðîå ëîìàåòñÿ, à æèëüöû âíåçàïíî îêàçûâàþòñÿ íà óëèöå (êóëüìèíàöèÿ). Ðåàëèçàöèþ ãåíåðàòîðà äëÿ ýòîé ñêàçêè ìîæíî îñíîâàòü íà óæå ðåàëèçîâàííûõ ïðîãðàììíûõ ñóùíîñòÿõ äëÿ ñêàçêè ¾Êîëîáîê¿. Ê òàêîâûì, áåç ñîìíåíèé, îòíîñÿòñÿ òèï äàííûõ Gender è ôóíêöèè ending è ending'. Áîëåå òîãî, ôóíêöèÿ act, êîòîðàÿ îñóùåñòâëÿåò çàïóñê ðåêóðñèâíîãî ïåðåáîðà äåéñòâóþùèõ ëèö, áóäåò òàêæå àáñîëþòíî èäåíòè÷íà (è ýòî íå î÷åíü óäèâèòåëüíî). Ñàìî ñîáîé, ÷òî âñå ýòè ôóíêöèè íåîáõîäèìî ïîìåùàòü â íîâûé ìîäóëü, ïîñêîëüêó äëÿ åäèíîîáðàçèÿ îñòàëüíûå ôóíêöèè áóäóò íàçâàíû òàê æå, íî â íèõ, åñòåñòâåííî, áóäåò íîâîå íàïîëíåíèå, ñîîòâåòñòâóþùåå ðàññìàòðèâàåìîé ñêàçêå. Äîïîëíèòåëüíî ê ñëóæåáíûì ôóíêöèÿì íåîáõîäèìî ðåàëèçîâàòü ôóíêöèþ, êîòîðàÿ äëÿ çàäàííîãî ïîëà ïåðñîíàæà âîçâðàùàåò ñîîòâåòñòâóþùåå åìó ìåñòîèìåíèå òðåòüåãî ðîäà åäèíñòâåííîãî ÷èñëà:
ðåêóðñèÿ
third third third third
: : Gender −> String Male = " îí " Female = " îíà " It = " îíî "
Ýòà ôóíêöèÿ ïðèãîäèòñÿ ïðè ðåàëèçàöèè îïèñàíèÿ êóëüìèíàöèè. Íà÷àëüíàÿ æå ôóíêöèÿ âûãëÿäèò ñòàíäàðòíî, â ïîëíîì ñîîòâåòñòâèè ñ óæå óïîìÿíóòîé ñòðóêòóðîé ñêàçêè:
attic : : String attic = prologue ++ act ++ epilogue Ðåàëèçàöèÿ ôóíêöèé prologue è epilogue äëÿ ýòîé ñêàçêè äîñòàòî÷íî ïðîñòà:
prologue : : String prologue = " Ñòîèò â ëåñó òåðåìîê , îí íå íèçîê , íå âûñîê . \ n " epilogue : : String epilogue = " È ðàçáåæàëèñü çâåðè êòî êóäà . " Òåïåðü íåîáõîäèìî ïîäóìàòü íàä ñòðóêòóðîé òèïà Actor, îïèñûâàþùåãî îäíîãî ïåðñîíàæà. Â ýòîé ñêàçêå óæå íå íàäî ïðåäîñòàâëÿòü ïðîãðàììå èìåíà äåéñòâóþùèõ ëèö â ðîäèòåëüíîì è âèíèòåëüíîì ïàäåæàõ, íî çàòî íåîáõîäèìî óêàçàòü, êàêèì èìåííî îáðàçîì ñîîòâåòñòâóþùèé ïåðñîíàæ ñêàçêè ïåðåìåùàëñÿ ïî ëåñó, ïîêà íå íàòêíóëñÿ íà òåðåìîê. Òàê ÷òî îïðåäåëåíèå òèïà Actor áóäåò òàêîâûì:
data Actor = Actor {
name : : String , action : : String , gender : : Gender }
132
Ãåíåðàöèÿ ðåêóðñèâíûõ ñêàçîê
Íó è, ñîáñòâåííî, ïåðå÷åíü äåéñòâóþùèõ ëèö äëÿ ðàññìàòðèâàåìîé ñêàçêè â îäíîì èç å¼ êëàññè÷åñêèõ âàðèàíòîâ (òàêîâûõ íåñêîëüêî, è ñïèñêè ïåðñîíàæåé ðàçëè÷àþòñÿ) âûãëÿäèò ñëåäóþùèì îáðàçîì:
actors : : [ Actor ] actors = [ Actor " Ìûøêà−íîðóøêà " Actor " Ëÿãóøêà−êâàêóøêà " Actor " Çàé÷èê−ïîáåãàé÷èê " Actor " Ëèñè÷êà−ñåñòðè÷êà " Actor " Âîë÷îê − ñåðûé áî÷îê " Actor " Ìåäâåäü "
" Áåæàëà " " Ïðûãàëà " " Ñêàêàë " " Áåæàëà " " Ðûñêàë " " ؼë "
Female , Female , Male , Female , Male , Male ]
Íàáîð ñïåöèôè÷íûõ ôóíêöèé äëÿ ãåíåðàöèè îòäåëüíîãî àêòà â ÷åðåäå ðåêóðñèâíîé ïîñëåäîâàòåëüíîñòè äëÿ ñêàçêè ¾Òåðåìîê¿ áîëåå ñëîæåí, ÷åì äëÿ ïðåäûäóùåé ñêàçêè. Çäåñü íàäî îñóùåñòâèòü ïåðåáîð âñåëèâøèõñÿ æèëüöîâ, êîòîðûå ïðåäñòàâëÿþòñÿ âíîâü ïðèáûâøåìó ïðåòåíäåíòó îäèí çà äðóãèì. Ïîýòîìó ôóíêöèÿ interimAct îïðåäåëÿåòñÿ òàê:
interimAct : : Actor −> [ Actor ] −> String interimAct actor i = ask actor i ++ " Âîò è ñòàë " ++ ae ++ " " ++ an ++ " â òåðåìêå æèòü . \ n "
where
an = name actor ae = ending $ gender actor Ôóíêöèÿ ask âîçâðàùàåò ñòðîêó, â êîòîðîé òåêóùåå äåéñòâóþùåå ëèöî ñïðàøèâàåò î òîì, êòî æèâ¼ò â òåðåìêå. Îíà âûãëÿäèò ñëåäóþùèì îáðàçîì:
ask : : Actor −> [ Actor ] −> String ask actor i = ( action actor ) ++ " " ++ an ++ " . " ++ " Óâèäåë " ++ ae ++ " òåðåìîê è ñïðàøèâàåò : \ n " ++ "− Êòî â òåðåìî÷êå æèâ¼ò ? Êòî â íåâûñîêîì æèâ¼ò ?" ++ "\ n " ++ salute actor i
where an ae
= name actor = ending $ gender actor
 êîíöå îïðåäåëåíèÿ ýòîé ôóíêöèè ïðîèçâîäèòñÿ âûçîâ ôóíêöèè salute, êîòîðàÿ êàê ðàç è ãåíåðèðóåò ïåðå÷èñëåíèå âñåõ óæå âñåëèâøèõñÿ æèëüöîâ:
salute : : Actor −> [ Actor ] −> String salute _ [] = " Íèêòî íå îòçûâàåòñÿ . " salute actor [ i ] = " Âûãëÿíóë " ++ ( ending $ gender i ) ++ " " ++ ( name i ) ++ " è ãîâîðèò : \ n " ++ "− ß − " ++ ( name i ) ++ " . À òû êòî ?\ n " ++ answer actor True salute actor is = " Âûãëÿíóëè æèëüöû è ãîâîðÿò : " ++ salute ' is "" ++ answer actor False
where
salute ' : : [ Actor ] −> String −> String salute ' [ ] result = result ++ " À òû êòî ?\ n " salute ' ( i : is ) result = salute ' is ( result ++ "\ n− ß − " ++ ( name i ) ++ " . " )
Îáîáùåíèå ôóíêöèé è ïîñòðîåíèå ãåíåðàòîðà
133
Ëîêàëüíîå îïðåäåëåíèå salute' ÿâëÿåòñÿ ïåðåáîðíîé ðåêóðñèâíîé ôóíêöèåé, êîòîðàÿ îïÿòü èñïîëüçóåò òåõíîëîãèþ íàêàïëèâàþùåãî ïàðàìåòðà. Âî âñåõ çíà÷èìûõ êëîçàõ ôóíêöèè salute òàêæå ïðîèçâîäèòñÿ âûçîâ ôóíêöèè answer, êîòîðàÿ âûäåëåíà îïÿòü-òàêè áîëüøå â ýñòåòè÷åñêèõ öåëÿõ. Îíà ãåíåðèðóåò îòâåò íîâîãî ïðåòåíäåíòà íà æèòåëüñòâî â òåðåìêå:
answer : : Actor −> Bool −> String answer actor one = "− À ÿ − " ++ ( name actor ) ++ " . Ïóñòè " ++ ( i f one then "" el se " òå " ) ++ " ìåíÿ ê ñåáå æèòü . " ++ "\ n " ++ "− Äà òû íå âëåçåøü . \ n " ++ "− Íó ÿ êàê−íèáóäü . \ n " ++ "− Íó èäè . \ n " Âòîðîé ïàðàìåòð ýòîé ôóíêöèè ÿâëÿåòñÿ áóëåâñêèì è îïðåäåëÿåò, ñêîëüêî æèëüöîâ æèâ¼ò â òåðåìêå îäèí èëè ìíîãî. Ýòà èíôîðìàöèÿ èñïîëüçóåòñÿ äëÿ ïðàâèëüíîé ãåíåðàöèè îêîí÷àíèÿ èìïåðàòèâíîé ôîðìû ãëàãîëà ¾ïóñòèòü¿. Êàê âèäíî, âñå òðè ôóíêöèè ask, salute è answer ìîæíî áûëî âîîáùå îáúåäèíèòü â îäíîì îïðåäåëåíèè, êîòîðîå âûçûâàëîñü áû èç ôóíêöèè interimAct. Òåì íå ìåíåå äëÿ ñòðóêòóðèçàöèè êîäà ðåêîìåíäóåòñÿ òàêèì îáðàçîì âûäåëÿòü ëîãè÷åñêè îáîñîáëåííûå ÷àñòè ïðîãðàììû. Íàêîíåö, çàêëþ÷èòåëüíàÿ ôóíêöèÿ finalAct îïðåäåëÿåòñÿ ñëåäóþùèì îáðàçîì:
finalAct : : Actor −> [ Actor ] −> String finalAct actor i = ask actor i ++ " Ïîëåç " ++ ae ' ++ " " ++ " âíóòðü , äà íå ñìîã " ++ " òóäà ïîìåñòèòüñÿ . " ++ " Òîãäà âëåç " ++ ae ' ++ " " íà òåðåìîê è ðàçäàâèë "
where
an ++ ae ' ++ " ++ ( third actor ) ++ ++ ae ++ " åãî . \ n "
an = name actor ae = ending $ gender actor ae ' = ending ' $ gender actor Îïÿòü æå â ïîñòðîåííîì ãåíåðàòîðå âñòðå÷àþòñÿ òå æå îãðåõè, êîòîðûå áûëè îáíàðóæåíû â ôóíêöèè äëÿ âûâîäà òåêñòà ñêàçêè ¾Êîëîáîê¿. Òåì íå ìåíåå óæå íà ïðèìåðå ýòîãî ãåíåðàòîðà ñòàíîâèòñÿ ïîíÿòíûì, ÷òî îáúÿâëåííàÿ âî ââåäåíèè çàäà÷à èìååò òèïîâîå ðåøåíèå.
Îáîáùåíèå ôóíêöèé è ïîñòðîåíèå ãåíåðàòîðà Ðåàëèçîâàâ äâà ãåíåðàòîðà, óæå ìîæíî óâèäåòü îáùèå ïðèíöèïû, íà îñíîâå êîòîðûõ ìîæíî ïîïûòàòüñÿ ñîçäàòü îáîáù¼ííûé ãåíåðàòîð, îñóùåñòâëÿþùèé ðåêóðñèâíûé ïåðåáîð óíèôèöèðîâàííûõ îïèñàíèé äåéñòâóþùèõ ëèö è ãåíåðèðóþùèé åñòåñòâåííî-ÿçûêîâîé òåêñò ïðè ïîìîùè ïåðåäàííûõ â êà÷åñòâå ïàðàìåòðîâ ñïåöèàëüíûõ ôóíêöèé. Äëÿ ñîçäàíèÿ òèïîâûõ ôóíêöèé âûñøåãî ïîðÿäêà äëÿ ãåíåðàöèè ðåêóðñèâíûõ ñêàçîê ïðåæäå âñåãî íåîáõîäèìî îçàáîòèòüñÿ îïðåäåëåíèåì îáîáù¼ííûõ òèïîâ äàííûõ äëÿ èñïîëüçîâàíèÿ â ñïåöèôè÷åñêèõ ãåíåðàòîðàõ. Ðå÷ü ïðåæäå âñåãî âåä¼òñÿ î òèïå äëÿ ïðåäñòàâëåíèÿ îïèñàíèÿ ïåðñîíàæà ñêàçêè, à òàêæå î âñïîìîãàòåëüíûõ òèïàõ äëÿ ïðåäñòàâëåíèÿ ïîëà (ãðàììàòè÷åñêîãî ðîäà), òèïå îêîí÷àíèÿ ãëàãîëà è ò. ä. Ïîñëåäíèå äâà òèïà îïðåäåëÿþòñÿ ïðîñòî:
data VerbPastType = RegularVerb | IrregularVerb
134
Ãåíåðàöèÿ ðåêóðñèâíûõ ñêàçîê
deriving ( Show , Eq ) data Gender = Male | Female | It
deriving ( Show , Eq )
Ñðàçó ìîæíî îïðåäåëèòü ñïåöèàëüíóþ ôóíêöèþ äëÿ ïîëó÷åíèÿ îêîí÷àíèÿ ãëàãîëà â ïðîøåäøåì âðåìåíè, ïîñêîëüêó òàêàÿ ôóíêöèÿ áóäåò ñ áîëüøîé óâåðåííîñòüþ èñïîëüçîâàòüñÿ âî âñåõ ñïåöèôè÷åñêèõ ãåíåðàòîðàõ. Ðåàëèçàöèþ ýòîé ôóíêöèè íåîáõîäèìî íåìíîãî èçìåíèòü ïî ñðàâíåíèþ ñ ôóíêöèÿìè ending è ending', êîòîðûå ââåäåíû â ïîäðàçäåëå ïðî ñêàçêó ¾Êîëîáîê¿. Ïóñòü îêîí÷àíèå ãëàãîëà íåðåãóëÿðíîãî òèïà â ìóæñêîì ðîäå áóäåò ïóñòûì, à äëÿ ðåãóëÿðíûõ ãëàãîëîâ òàêèì îêîí÷àíèåì áóäåò ¾ë¿. Äëÿ æåíñêîãî è ñðåäíåãî ðîäîâ îêîí÷àíèÿ áóäóò ¾-ëà¿ è ¾-ëî¿ ñîîòâåòñòâåííî. Òîãäà äëÿ êîíêàòåíàöèè ñ ðåçóëüòàòîì âûçîâà ýòîé ôóíêöèè íåîáõîäèìî ïðèìåíÿòü ¾îñíîâó¿ ãëàãîëà áåç ñóôôèêñà: ¾ïîìîã¿, ¾óáåæà¿, ¾ïðèëåòå¿ è ò. ä.
verbPastEnding verbPastEnding verbPastEnding verbPastEnding verbPastEnding
: : VerbPastType −> Gender −> String RegularVerb Male = "ë" IrregularVerb Male = "" _ Female = " ëà " _ It = " ëî "
×òî êàñàåòñÿ îáîáù¼ííîãî òèïà Actor, òî çäåñü íåîáõîäèìî ïîäóìàòü. Ìîæíî ïðèäóìàòü ñïåöèàëèçèðîâàííûé , ïðè ïîìîùè êîòîðîãî ìîæíî áûëî áû ãåíåðàëèçîâàòü ëþáîé òèï (èñïîëüçîâàíèå ). Íî â äàííîì ñëó÷àå ïðîùå îáîéòèñü êîíêðåòíûì òèïîì, êîòîðûé ïîçâîëèò ðåøàòü øèðîêèé êëàññ çàäà÷ ïî ïðåäñòàâëåíèþ ïåðñîíàæåé. Ìîæíî îòìåòèòü, ÷òî â äâóõ èññëåäîâàííûõ ñêàçêàõ êàæäûé ïåðñîíàæ èìåë íàèìåíîâàíèå (èìÿ) è ïîë, à îñòàëüíàÿ èíôîðìàöèÿ â òîì èëè èíîì âèäå ïåðåäàâàëàñü â âèäå íàáîðà ñòðîê, ïðè ýòîì èíòåðïðåòàöèÿ ýòîé ïåðåäàâàåìîé èíôîðìàöèè ïðîèçâîäèòñÿ â êîíêðåòèçèðîâàííûõ ôóíêöèÿõ interimAct è finalAct. Ýòèì è ìîæíî âîñïîëüçîâàòüñÿ:
êëàññ ïîëèìîðôèçìà
data Actor = Actor {
name : : String , gender : : Gender , info : : [ String ] }
deriving ( Show , Eq ) Íà÷èíàåòñÿ ñàìîå èíòåðåñíîå íåîáõîäèìî ðåàëèçîâàòü îáîáù¼ííóþ ôóíêöèþ act è ôóíêöèþ äëÿ ãåíåðàöèè âñåãî òåêñòà ðåêóðñèâíîé ñêàçêè. Ïðåæäå âñåãî íåîáõîäèìî åù¼ ðàç âíèìàòåëüíî èçó÷èòü ôóíêöèþ act, êîòîðàÿ èñïîëüçóåòñÿ â ãåíåðàòîðàõ ñêàçîê ¾Êîëîáîê¿ è ¾Òåðåìîê¿. Îíà ñîäåðæèò íåñêîëüêî íå î÷åíü õîðîøèõ ìîìåíòîâ, îò êîòîðûõ íàäî áû èçáàâèòüñÿ ïðè ðåàëèçàöèè îáîáù¼ííîé ôóíêöèè. Ïåðâûé íåïðèÿòíûé ìîìåíò çàêëþ÷àåòñÿ â òîì, ÷òî îíà èñïîëüçóåò äâå êîíêðåòèçèðîâàííûå ôóíêöèè äëÿ ãåíåðàöèè îòäåëüíûõ äåéñòâèé â ðÿäó ðåêóðñèâíûõ âûçîâîâ interimAct è finalAct, íî ïðè ýòîì â ãåíåðàòîðàõ îáåèõ ñêàçîê â ôóíêöèè interimAct ïðîèçâîäèòñÿ ðàçäåëåíèå íà äåéñòâèå ïåðâîãî ýëåìåíòà ïåðå÷íÿ ïåðñîíàæåé è íà äåéñòâèå îñòàëüíûõ. Ýòî æåëàòåëüíî îòðàçèòü íåïîñðåäñòâåííî â ôóíêöèè act, îñóùåñòâèâ ðàçäåëåíèå íà óðîâíå â å¼ êëîçàõ. Äëÿ ýòèõ öåëåé íåîáõîäèìî âûäåëèòü åù¼ îäèí êëîç.
ñîïîñòàâëåíèÿ ñ îáðàçöàìè
Îáîáùåíèå ôóíêöèé è ïîñòðîåíèå ãåíåðàòîðà
135
Âòîðîé ìîìåíò çàêëþ÷àåòñÿ â òîì, ÷òî â ôóíêöèè interimAct è finalAct ïåðåäàâàëîñü òåêóùåå äåéñòâóþùåå ëèöî è ïåðå÷åíü òåõ, êòî óæå ïðîèçâ¼ë äåéñòâèÿ. Ýòî íå ñîâñåì êîððåêòíî, ïîñêîëüêó â íåêîòîðûõ ñêàçêàõ òåêóùèé ïåðñîíàæ ìîæåò îáðàùàòüñÿ ê áóäóùåìó âðåìåíè, íàçûâàÿ ñëåäóþùèõ çà íèì ïåðñîíàæåé ñêàçêè. Ïîýòîìó â óêàçàííûå ôóíêöèè è ôóíêöèþ initialAct, êîòîðàÿ áóäåò ïðèíèìàòüñÿ íà îñíîâàíèè ðåøåíèÿ ïðåäûäóùåãî ìîìåíòà, íåîáõîäèìî ïåðåäàâàòü äâà ñïèñêà äåéñòâóþùèõ ëèö. Íàêîíåö, òðåòèé ìîìåíò çàêëþ÷àåòñÿ áîëüøå â òåõíè÷åñêîì àñïåêòå. Åñëè ðàññìîòðåòü ïîñëåäíèé êëîç ôóíêöèè act' â îïðåäåëåíèè äëÿ ñêàçêè ¾Êîëîáîê¿, òî áóäåò âèäíî, ÷òî ïðè ðåêóðñèâíîì âûçîâå ïåðåíîñ òåêóùåãî äåéñòâóþùåãî ëèöà â ñïèñîê óæå ñäåëàâøèõ ñâî¼ äåëî ïåðñîíàæåé ïðîèçâîäèòñÿ ïðè ïîìîùè êîíêàòåíàöèè (++), ÷òî íå ñîâñåì îïòèìàëüíî è ìîæåò íåãàòèâíî ñêàçàòüñÿ íà ñêîðîñòè èñïîëíåíèÿ äëÿ áîëüøèõ ñïèñêîâ. Ïîýòîìó íîâîãî ïåðñîíàæà ïðîùå äîáàâëÿòü â ãîëîâó ñïèñêà ïðè ïîìîùè ïðîñòîãî êîíñòðóèðîâàíèÿ (:). Òàê ÷òî òåïåðü, ó÷òÿ âñå ýòè ìîìåíòû, ìîæíî ïðîñòî çàïèñàòü îïðåäåëåíèå îáîáù¼ííîé ôóíêöèè act:
act : : −> −> −> −>
[ Actor ] ( [ Actor ] −> [ Actor ] −> String ) ( [ Actor ] −> [ Actor ] −> String ) ( [ Actor ] −> [ Actor ] −> String )
String
act actors initialAct interimAct finalAct = act ' actors [ ] "" initialAct interimAct finalAct
where
act ' : : −> −> −> −> −> −>
[ Actor ] [ Actor ]
String ( [ Actor ] −> [ Actor ] −> String ) ( [ Actor ] −> [ Actor ] −> String ) ( [ Actor ] −> [ Actor ] −> String ) String
act ' [ ] = result
_
result _
_
_
act ' [ a ] ops result initialAct interimAct finalAct = result ++ ( finalAct [ a ] ops ) act ' actors@ ( a : as ) [ ] result initialAct interimAct finalAct = act ' as [ a ] ( result ++ ( initialAct actors [ ] ) ) initialAct interimAct finalAct act ' actors@ ( a : as ) ops result initialAct interimAct finalAct = act ' as ( a : ops ) ( result ++ ( interimAct actors ops ) ) initialAct interimAct finalAct Âûãëÿäèò âïå÷àòëÿþùå è íåìíîãî óæàñàþùå, íî åñëè ðàçîáðàòüñÿ, òî ñòàíîâèòñÿ ïîíÿòíî, ÷òî ýòî âñ¼ òî æå èñïîëüçîâàíèå òåõíîëîãèè íàêàïëèâàþùåãî ïàðàìåòðà â ôóíêöèè act', ïðè÷¼ì ôóíêöèÿ act èñïîëüçóåòñÿ òîëüêî êàê ¾îá¼ðòêà¿.  ñâîþ î÷åðåäü, ôóíêöèÿ act' ïðîñòî âîçâðàùàåò çíà÷åíèå
136
Ãåíåðàöèÿ ðåêóðñèâíûõ ñêàçîê
íàêàïëèâàþùåãî ïàðàìåòðà result, êîãäà ñïèñîê òåêóùèõ äåéñòâóþùèõ ëèö ñòàíîâèòñÿ ïóñòûì. Âòîðîé êëîç âûçûâàåò êîíêðåòèçèðîâàííóþ ôóíêöèþ finalAct è äîáàâëÿåò å¼ çíà÷åíèå ê îáùåìó ðåçóëüòàòó â ñëó÷àå, åñëè òåêóùèé ñïèñîê äåéñòâóþùèõ ëèö ñîñòîèò èç îäíîãî ýëåìåíòà. Òðåòèé êëîç, ñîîòâåòñòâåííî, îãðàíè÷èâàåò ïåðå÷åíü óæå ïðîñìîòðåííûõ ïåðñîíàæåé ïóñòûì ñïèñêîì è âûçûâàåò äëÿ ýòîãî ñëó÷àÿ ôóíêöèþ initialAct, ïåðåíîñÿ òåêóùåå äåéñòâóþùåå ëèöî â ñïèñîê òåõ, êòî óæå ñäåëàë ñâî¼ äåëî. Íàêîíåö, ÷åòâ¼ðòûé êëîç ïîëíîñòüþ ñîîòâåòñòâóåò òðåòüåìó êëîçó èçíà÷àëüíîé ôóíêöèè act' äëÿ ñêàçêè ¾Êîëîáîê¿ ñ ó÷¼òîì òðåòüåãî íåãàòèâíîãî ìîìåíòà. Âñ¼ ãîòîâî äëÿ ðåàëèçàöèè îáîáù¼ííîé ôóíêöèè äëÿ ãåíåðàöèè ðåêóðñèâíîé ñêàçêè. ×òîáû ïîäâåñòè ÷åðòó ïîä ýòèì, íåîáõîäèìî ïîäóìàòü, êàêèå îáúåêòû îíà äîëæíà ïîëó÷àòü íà âõîä â êà÷åñòâå ïàðàìåòðîâ. Âî-ïåðâûõ, ïåðå÷åíü äåéñòâóþùèõ ëèö, ýòî áåç ñîìíåíèé. Âî-âòîðûõ, êîíêðåòèçèðîâàííûå ôóíêöèè äëÿ ãåíåðàöèè ïðîëîãà è ýïèëîãà, ïðè÷¼ì îíè òàêæå äîëæíû ïðèíèìàòü ïåðå÷åíü äåéñòâóþùèõ ëèö â êà÷åñòâå ïàðàìåòðà, ïîñêîëüêó â òåêñòå ïðîëîãà èëè ýïèëîãà êòî-ëèáî èç ïåðñîíàæåé ìîæåò óïîìèíàòüñÿ. Íó è, â-òðåòüèõ, òðè ôóíêöèè initialAct, interimAct è finalAct òàêæå äîëæíû ïåðåäàâàòüñÿ íà âõîä.  èòîãå ïîëó÷àåòñÿ òàêîå îïðåäåëåíèå:
generateRT : : −> −> −> −> −> −>
[ Actor ] ( [ Actor ] ( [ Actor ] ( [ Actor ] ( [ Actor ] ( [ Actor ]
−> −> −> −> −>
String ) [ Actor ] −> String ) [ Actor ] −> String ) [ Actor ] −> String ) String )
String
generateRT actors prologue initialAct interimAct finalAct epilogue = ( prologue actors ) ++ ( act actors initialAct interimAct finalAct ) ++ ( epilogue actors )
Ðåïêà Îäèí ïðåñòàðåëûé ìóæ÷èíà ïîñàäèë èñêîííûé îâîù ðåïó.  ñèëó îïðåäåë¼ííûõ ïðèðîäíûõ ÿâëåíèé, ïðîèñøåäøèõ â òîì ïðèñíîïàìÿòíîì ãîäó, ðåïà óðîäèëàñü êðàéíå óðîæàéíàÿ, îãðîìíûõ ðàçìåðîâ. Äåä îäèí ðåïó âûäåðíóòü íå ìîã, à ïîòîìó çâàë íà ïîìîùü ñâîèõ äîìî÷àäöåâ îäíîãî çà äðóãèì ( ). Êîãäà âñå äîìàøíèå áûëè ïîçâàíû, ãèãàíòñêèé îâîù áûë ñ óñïåõîì âûíóò èç çåìëè è ñâàðåí íà ðàäîñòü âñåì (êóëüìèíàöèÿ). Èìåÿ â íàëè÷èè ïîäãîòîâëåííûé èíñòðóìåíò â âèäå îáîáù¼ííûõ ôóíêöèé, òåïåðü äîñòàòî÷íî ëèøü ïîäãîòîâèòü ãåíåðàòîðû êîíêðåòíîãî òåêñòà è ïåðåäàòü èõ íà âõîä ôóíêöèè generateRT âìåñòå ñî ñïèñêîì äåéñòâóþùèõ ëèö. Ñ íåãî è íåîáõîäèìî íà÷àòü îïðåäåëåíèå ãåíåðàòîðà ñêàçêè ¾Ðåïêà¿:
ðåêóðñèÿ
actors : : [ Actor ] actors = [ Actor " äåä " Actor " áàáêà " Actor " âíó÷êà " Actor " æó÷êà " Actor " êîøêà "
Male Female Female Female Female
[ " äåäà " ] , [ " áàáêó " ] , [ " âíó÷êó " ] , [ " æó÷êó " ] , [ " êîøêó " ] ,
Ðåïêà
137
Actor " ìûøêà "
Female [ " ìûøêó " ] ]
Êàê âèäíî, â òðåòüåì ïîëå â ñïèñêå èñïîëüçóåòñÿ åäèíñòâåííîå çíà÷åíèå ðîäèòåëüíûé ïàäåæ èìåíè ïåðñîíàæà. Ýòà ôîðìà ïðèìåíÿåòñÿ â òåêñòå ñêàçêè, ïîñêîëüêó êàæäûé ïåðñîíàæ çîâ¼ò ñëåäóþùåãî (òóò, êñòàòè, è ïðèãîäèòñÿ òî, ÷òî â ôóíêöèè initialAct, interimAct finalAct ïåðåäà¼òñÿ ñïèñîê âñåõ ãðÿäóùèõ ïåðñîíàæåé, â ãîëîâå êîòîðîãî ñòîèò òåêóùèé). Áóäåò óäîáíûì ñîçäàòü ñïåöèàëüíóþ ôóíêöèþ äëÿ ïîëó÷åíèÿ ôîðìû ðîäèòåëüíîãî ïàäåæà ïî îïèñàíèþ ïåðñîíàæà:
actorGenitiveCase : : Actor −> String actorGenitiveCase = head . info Ôóíêöèè prologue è epilogue òàêæå ðåàëèçóþòñÿ áåç ïðîáëåì, è òóò îïÿòü ïîìîãàåò òî, ÷òî â íèõ ïåðåäà¼òñÿ ïåðå÷åíü äåéñòâóþùèõ ëèö, ïîñêîëüêó â ïðîëîãå èñïîëüçóåòñÿ ïåðâûé ïåðñîíàæ ñïèñêà îí ñàæàåò ðåïêó:
prologue : : [ Actor ] −> String prologue ( a : as ) = " Ïîñàäè " ++ ae ++ " " ++ an ++ " ðåïêó . Âûðîñëà ðåïêà áîëüøàÿ−ïðåáîëüøàÿ . \ n "
where
an = name a ae = verbPastEnding RegularVerb $ gender a epilogue : : [ Actor ] −> String epilogue _ = " Íàâàðèëè îíè èç ðåïêè êàøè , íàåëèñü äî îòâàëà . " Ïðè ðåàëèçàöèè ôóíêöèé initialAct è interimAct ñòàíåò ÿñíî, ÷òî â íèõ î÷åíü ìíîãî îäèíàêîâîãî êîäà, ïîýòîìó âñ¼ æå öåëåñîîáðàçíåé èõ ðåàëèçîâàòü â âèäå îäíîé ôóíêöèè ñ ïåðåäà÷åé äîïîëíèòåëüíîãî ïåðâîãî ïàðàìåòðà áóëåâñêîãî òèïà äëÿ îòäåëåíèÿ ñïîñîáà âûçîâà, à â äàëüíåéøåì ïåðåäà÷à â ôóíêöèþ generateRT áóäåò ïðîèçâîäèòüñÿ ñ èñïîëüçîâàíèåì òåõíîëîãèè . Òåì íå ìåíåå âûäåëåíèå îòäåëüíûõ ôóíêöèé initialAct è interimAct â îáîáù¼ííûõ ôóíêöèÿõ ñäåëàíî ïðàâèëüíî.
÷àñòè÷íîãî ïðèìåíåíèÿ
act : : Bool −> [ Actor ] −> [ Actor ] −> String act isInitial actors ops = ( i f ( isInitial ) then " Ñòà " ++ ae ++ " " ++ an ++ " ðåïêó òÿíóòü . " ++ " Òÿíåò−ïîòÿíåò , âûòÿíóòü íå ìîæåò . \ n " els e ( capitalize $ queue ( actor : ops ) ) ++ " Òÿíóò−ïîòÿíóò , âûòÿíóòü íå ìîãóò . \ n " ) ++ " Ïîçâà " ++ ae ++ " " ++ an ++ " " ++ next ++ " . "
where
actor an ae next
= = = =
head actors name actor verbPastEnding RegularVerb $ gender actor actorGenitiveCase $ head $ tail actors
 òåëå ýòîé ôóíêöèè èñïîëüçóþòñÿ äâå âñïîìîãàòåëüíûå ôóíêöèè capitalize è queue. Ïåðâàÿ ïðîñòî ïðåîáðàçóåò ïåðâûé ñèìâîë â âåðõíèé ðåãèñòð, ïîñêîëüêó èìåíà ïåðñîíàæåé ñêàçêè èíîãäà íà÷èíàþò ïðåäëîæåíèå (ýòó ôóíêöèè âîîáùå ðåçîííî âûíåñòè â ìîäóëü ñ îáîáù¼ííûìè ôóíêöèÿìè). Îíà îïðåäåëÿåòñÿ ïðîñòî:
capitalize : : String −> String capitalize [ ] = [ ] capitalize ( c : cs ) = ( toUpper c ) : cs
138
Ãåíåðàöèÿ ðåêóðñèâíûõ ñêàçîê Ñòàíäàðòíàÿ ôóíêöèÿ toUpper îïðåäåëåíà â ìîäóëå Data.Char. Ôóíêöèÿ queue îðãàíèçóåò ðåêóðñèâíûé ïåðåáîð äåéñòâóþùèõ ëèö:
queue queue queue queue
: : [ Actor ] −> String [] = "" [o] = ( name o ) ++ " çà ðåïêó . " ( o : os ) = ( name o ) ++ " çà " ++ ( actorGenitiveCase $ head os ) ++ " , " ++ queue os
À âîò ôóíêöèþ finalAct, êàê ýòî îáû÷íî áûâàåò, æåëàòåëüíî ðåàëèçîâàòü îòäåëüíî. Îíà òàêæå íåñëîæíàÿ:
finalAct : : [ Actor ] −> [ Actor ] −> String finalAct actors ops = ( capitalize $ queue ( actor : ops ) ) ++ " Òÿíóò−ïîòÿíóò , âûòÿíóëè ðåïêó . \ n "
where
actor = head actors Íàêîíåö, îñíîâíàÿ ôóíêöèÿ äëÿ ãåíåðàöèè âñåãî òåêñòà ñêàçêè ¾Ðåïêà¿ òåïåðü âûãëÿäèò êðàéíå ïðîñòî:
turnip : : String turnip = generateRT actors prologue ( act True ) ( act False ) finalAct epilogue
Çàêëþ÷åíèå Äëÿ çàêðåïëåíèÿ ïîëó÷åííûõ íàâûêîâ çàèíòåðåñîâàííîìó ÷èòàòåëþ ïðåäëàãàåòñÿ ñàìîñòîÿòåëüíî ðåàëèçîâàòü ôóíêöèè äëÿ ãåíåðàöèè ðåêóðñèâíûõ ñêàçîê íà îñíîâå ñîçäàííîé îáîáù¼ííîé ôóíêöèè âûñøåãî ïîðÿäêà generateRT íà ïðèìåðå äðóãèõ ðåêóðñèâíûõ ðóññêèõ íàðîäíûõ ñêàçîê: ¾Çàþøêèíà èçáóøêà¿, ¾Áû÷îê ñìîëÿíîé áû÷îê¿, ¾Çèìîâüå çâåðåé¿ è äð. Ðåçóëüòàòû ðàáîò àâòîð ñ ðàäîñòüþ ïîëó÷èò íà ñâîé ýëåêòðîííûé àäðåñ è ñêðóïóë¼çíî èçó÷èò. Òàêæå íåîáõîäèìî åù¼ ðàç îòìåòèòü, ÷òî ðåêóðñèâíûå ñêàçêè ÿâëÿþòñÿ âñåãî ëèøü íåáîëüøèì êëàññîì âñåãî ôîëüêëîðíîãî íàñëåäèÿ íàøåãî íàðîäà. Áîëåå èíòåðåñíîé, íî è íåñêîëüêî ñëîæíîé çàäà÷åé ÿâëÿåòñÿ ãåíåðàöèÿ ïðîèçâîëüíûõ ñêàçîê, ïðè÷¼ì íå ñóùåñòâóþùèõ òåêñòîâ (ýòî áûëî áû òðèâèàëüíî), à òåêñòîâ ñêàçîê íà îñíîâå ñþæåòîâ è ìîòèâîâ ñ èìåþùèìèñÿ äåéñòâóþùèìè ëèöàìè è ¾NPC¿ (Èâàí-öàðåâè÷, Öàðåâíà-ëÿãóøêà, Ñåðûé âîëê, ×óäî-þäî, Áàáà ßãà, Êîùåé Áåññìåðòíûé è ò. ä.), àðòåôàêòàìè (êëóáî÷åê, êîâ¼ð-ñàìîë¼ò, ñêàòåðòü-ñàìîáðàíêà, ñàïîãè-ñêîðîõîäû, ìå÷-êëàäåíåö è ò. ä.), ëîêàöèÿìè (òðèäåâÿòîå öàðñòâî, ðåêà Ñìîðîäèíà, äðåìó÷èé ëåñ, çà ñåäüìîé âîäîé è ò. ä.). Çäåñü íåñïðîñòà óïîòðåáëåíû æàðãîííûå òåðìèíû èç ëåêñèêîíà èãðîêîâ â ñòðàòåãè÷åñêèå èãðû è êâåñòû ¾NPC¿ (îò àíãë. íåèãðàþùåå äåéñòâóþùåå ëèöî), ¾àðòåôàêò¿, ¾ëîêàöèÿ¿, ïîñêîëüêó ñêàçêè ÷àñòî ñòàíîâèëèñü îñíîâîé òàêèõ èãð, äà è ñòðóêòóðà ñêàçîê, ïî ìíåíèþ ìíîãèõ èññëåäîâàòåëåé-ôîëüêëîðèñòîâ, ïîäîáíà ñòðóêòóðå òàêèõ èãð. Áîëåå òîãî, íåêîòîðûå äåéñòâóþùèå ëèöà â ñêàçêàõ ìîãóò ðàññêàçûâàòü â êàíâå ñêàçêè ñâîè ðàññêàçû è ñêàçêè íàëèöî ðåêóðñèâíûé âûçîâ.  ýòîì àñïåêòå ñêàçêè ñáîðíèêà ¾Òûñÿ÷à è îäíà íî÷ü¿ î÷åíü ïîêàçàòåëüíû â íåêîòîðûõ èç íèõ íàñ÷èòûâàåòñÿ äî ñåìè óðîâíåé âëîæåííîñòè (Øàõåðåçàäà áûëà îòëè÷íûì ãåíåðàòîðîì ñêàçîê). Òàê ÷òî çàäà÷à ñîçäàíèÿ (ñëîæåíèÿ) íîâûõ ñêàçîê è ñëîæíà, è èíòåðåñíà îäíîâðåìåííî. Íàä å¼ ðåøåíèåì òàêæå ðåêîìåíäóåòñÿ ïîäóìàòü è ðåàëèçîâàòü ñâîé ãåíåðàòîð.
playing character
non
Ëèòåðàòóðà [1] Áàðåíäðåãò X. Ëÿìáäà-èñ÷èñëåíèå. Åãî ñèíòàêñèñ è ñåìàíòèêà / ïåð. ñ àíãë. Ì.: Ìèð, 1985. 606 ñòð. [2] Âèíåð Í. Êèáåðíåòèêà, èëè Óïðàâëåíèå è ñâÿçü â æèâîòíîì è ìàøèíå / ïåð. ñ àíãë. Ì.: Ñîâåòñêîå ðàäèî, 1958. 216 ñòð. [3] Âîëüôåíãàãåí Â. Ý. Ìåòîäû è ñðåäñòâà âû÷èñëåíèé ñ îáúåêòàìè. Àïïëèêàòèâíûå âû÷èñëèòåëüíûå ñèñòåìû. Ì.: ÞðÈíôîðì, 2004. 787 ñòð. ISBN 5-89158-100-0. [4] Âîëüôåíãàãåí Â. Ý. Êîìáèíàòîðíàÿ ëîãèêà â ïðîãðàììèðîâàíèè. Âû÷èñëåíèÿ ñ îáúåêòàìè â ïðèìåðàõ è çàäà÷àõ. Ì.: ÌÈÔÈ, 1994. 204 ñòð. ISBN 5-89158-101-9. [5] Ãàðäíåð Ì. À íó-êà, äîãàäàéñÿ! / ïåð. ñ àíãë. Þ. À. Äàíèëîâà. Ì.: Ìèð, 1984. 212 ñòð., èë. [6] Äóøêèí Ð. Â. Ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå íà ÿçûêå Haskell+ CD. Ì.: ÄÌÊ Ïðåññ, 2007. 608 ñòð., èë. ISBN 5-94074-335-8. [7] Äóøêèí Ð. Â. Ñïðàâî÷íèê ïî ÿçûêó Haskell. Ì.: ÄÌÊ Ïðåññ, 2008. 544 ñòð., èë. ISBN 594074-410-9. [8] Äóøêèí Ð. Â. Ïðàêòèêà ðàáîòû íà ÿçûêå Haskell+ CD. Ì.: ÄÌÊ Ïðåññ, 2009. 288 ñòð., èë. ISBN 978-5-94074-588-4. [9] Çåôèðîâ Ñ. À. Ëåíü áîÿòüñÿ // Ïðàêòèêà ôóíêöèîíàëüíîãî ïðîãðàììèðîâàíèÿ. 2009. Èþëü. 1. ñ. 9-16. [10] Êàðïåíêî À. Ñ. Ìíîãîçíà÷íûå ëîãèêè // Ëîãèêà è êîìïüþòåð. Âûï. 4. Ì.: Íàóêà, 1997. [11] Êèðïè÷¼â Å. Ð. Ìîíàäû // RSDN Magazine. 2008. 3. [12] Ëóêàñåâè÷ ß. Àðèñòîòåëåâñêàÿ ñèëëîãèñòèêà ñ òî÷êè çðåíèÿ ñîâðåìåííîé ôîðìàëüíîé ëîãèêè. Ì.: Èíîñòðàííàÿ ëèòåðàòóðà, 1959. [13] Ïåíðîóç Ð. Íîâûé óì êîðîëÿ: î êîìïüþòåðàõ, ìûøëåíèè è çàêîíàõ ôèçèêè / ïåð. ñ àíãë., îáù. ðåä. Â. Î. Ìàëûøåíêî, ïðåäèñë. Ã. Ã. Ìàëèíåöêîãî. 2-å èçä., èñïð. Ì.: Åäèòîðèàë ÓÐÑÑ, 2005. 400 ñòð. (Ñèíåðãåòèêà: îò ïðîøëîãî ê áóäóùåìó.) ISBN 5-354-00993-6. [14] Ðîãàíîâà Í. À. Ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå: ó÷åá. ïîñîáèå äëÿ ñòóäåíòîâ âûñ. ó÷åá. çàâåäåíèé. Ì.: ÃÈÍÔÎ, 2002. 260 ñòð. [15] Ôèëä À., Õàððèñîí Ï. Ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå / ïåð. ñ àíãë. Ì.: Ìèð, 1993. 637 ñòð., èë. ISBN 5-03-001870-0. [16] Õåíäåðñîí Ï. Ôóíêöèîíàëüíîå ïðîãðàììèðîâàíèå. Ïðèìåíåíèå è ðåàëèçàöèÿ // Ìàòåìàòè÷åñêîå îáåñïå÷åíèå ÝÂÌ / ïåð. ñ àíãë. (Ïåòðîâà Ë. Ò.) Ì.: Ìèð, 1983. 349 ñòð.
140
Ëèòåðàòóðà
[17] Curry H. B. Grundlagen der kombinatorischen Logik // American Journal of Mathematics 52. 1930. P. 509536, 789834. [18] Fokker J. The Systematic Construction of a One-combinator Basis for Lambda-Terms // Formal Aspects of Computing 4. 1992. P. 776-780. [19] Newbern J. All About Monads. [20] Pierce B. C. Types and Programming Languages. The MIT Press. Massachusetts Institute of Technology. Cambridge, Massachusetts 02142. http://mitpress.mit.edu/. ISBN 0-262-16209-1. (â ñåòè Èíòåðíåò ïî àäðåñó http://newstar.rinet.ru/ goga/tapl/ îïóáëèêîâàí ïåðåâîä êíèãè íà ðóññêèé ÿçûê.) [21] Sch onnkel M. Uber die Baustein der mathematischen Logik. Math. Annalen, vol. 92, 1924. P. 305316. [22] Wadler P. Monads for functional programming // J. Jeuring and E. Meijer, editors, Advanced Functional Programming, Proceedings of the B astad Spring School, May. 1995. Springer Verlag Lecture Notes in Computer Science 925.
Ïðèíèìàþòñÿ áëàãîäàðíîñòè Âíèìàíèþ âñåõ ÷èòàòåëåé! Äàííàÿ êíèãà èçäàíà â ýëåêòðîííîì âèäå è ðàñïðîñòðàíÿåòñÿ àáñîëþòíî áåñïëàòíî. Âû ìîæåòå ñâîáîäíî èñïîëüçîâàòü å¼ äëÿ ÷òåíèÿ, êîïèðîâàòü å¼ äëÿ äðóçåé, ðàçìåùàòü â áèáëèîòåêàõ íà ñàéòàõ â ñåòè Èíòåðíåò, ðàññûëàòü ïî ýëåêòðîííîé ïî÷òå è ïðè ïîìîùè èíûõ ñðåäñòâ ïåðåäà÷è èíôîðìàöèè. Âû ìîæåòå èñïîëüçîâàòü òåêñò êíèãè ÷àñòè÷íî èëè ïîëíîñòüþ â ñâîèõ ðàáîòàõ ïðè óñëîâèè ðàçìåùåíèÿ ññûëîê íà îðèãèíàë è äîëæíîì öèòèðîâàíèè. Ïðè ýòîì àâòîð áóäåò íåñêàçàííî ðàä ïîëó÷èòü ÷èòàòåëüñêóþ áëàãîäàðíîñòü, êîòîðàÿ ïîçâîëèò êàê óëó÷øèòü òåêñò äàííîé êíèãè, òàê è áîëåå êà÷åñòâåííî ïîäîéòè ê ïîäãîòîâêå ñëåäóþùèõ êíèã. Áëàãîäàðíîñòè ïðèíèìàþòñÿ íà ñ÷¼ò ßíäåêñ.Äåíüãè, íà êîòîðûé ìîæíî ïåðå÷èñëèòü ìàëóþ ëåïòó, è ïðè ïîìîùè òåðìèíàëîâ:
4100137733052 Óáåäèòåëüíàÿ ïðîñüáà; ïðè ïåðå÷èñëåíèè áëàãîäàðíîñòè óêàçûâàòü â ïîÿñíåíèè ê ïåðåâîäó íàèìåíîâàíèå êíèãè èëè êàêîå-ëèáî èíîå óêàçàíèå íà òî, çà ÷òî èìåííî âûðàæàåòñÿ áëàãîäàðíîñòü.
Книги издательства «ДМК Пресс» можно заказать в торгово$издательском холдинге «АЛЬЯНС$ КНИГА» наложенным платежом, выслав открытку или письмо по почтовому адресу: 123242, Моск ва, а/я 20 или по электронному адресу: orders@alians kniga.ru. При оформлении заказа следует указать адрес (полностью), по которому должны быть высла$ ны книги; фамилию, имя и отчество получателя. Желательно также указать свой телефон и элек$ тронный адрес. Эти книги вы можете заказать и в Internet$магазине: www.alians kniga.ru. Оптовые закупки: тел. (495) 258 91 94, 258 91 95; электронный адрес books@alians kniga.ru.
Душкин Роман Викторович 14 занимательных эссе о языке Haskell и функциональном программировании
Главный редактор Мовчан Д. А. dm@dmk$press.ru Корректор Синяева Г. И. Верстка Душкин Р. В. Дизайн обложки Мовчан А. Г.
Подписано в печать 29.01.2011. Формат 70Х1001/16 . Гарнитура «Петербург». Печать офсетная. Усл. печ. л. 27. Тираж 1000 экз. Издательство ДМК Пресс. Web$сайт издательства: www.dmk$press.ru Internet$магазин: www.alians$kniga.ru
14 занимательных эссе о языке Haskell и функциональном программировании В книге представлено 14 статей автора, которые в разное время были опубликованы или подготовлены к публикации в научно-популярном журнале для школьников и учителей «Потенциал». Статьи расположены и связаны таким образом, чтобы они представляли собой логически последовательное повествование от начал к более сложным темам. Также в книге сделан упор на практические знания, предлагается решение многих прикладных задач при помощи языка функционального программирования Haskell. Книга будет интересна всем, кто живо интересуется функциональным программированием, студентам технических ВУЗов, преподавателям информатики. Кроме того, книга будет полезна всем желающим овладеть пониманием функционального программирования в целом и языка Haskell в частности. И в любом случае книга станет хорошим источником идей, задач и их решений для всех, кто интересуется функциональным программированием.
14 занимательных эссе о языке
Haskell
и функциональном программировании
Роман Викторович Душкин является автором первой книги на русском языке о функциональном программировании на языке Haskell, а также множества научных публикаций по темам нечеткой математики, искусственного интеллекта и функционального программирования в российских и зарубежных научных изданиях. Состоит в Российской Ассоциации Искусственного Интеллекта и участвовал во множестве национальных и международных научных конференциях, проводимых под ее эгидой. С 2001 года читал лекции по функциональному программированию в Московском инженерно-физическом институте (МИФИ). В настоящее время работает в области автоматизации промышленности и государственного управления,на практике используя все методы создания программных средств, применяющиеся в составе парадигм функционального и объектно-ориентированного программирования, а также искусственного интеллекта.
Internet-магазин: www.alians-kniga.ru Книга - почтой: Россия, 123242, Москва, а/я 20 e-mail: [email protected] Оптовая продажа: “Альянс-книга“ (495)258-9194, 258-9195 e-mail: [email protected]
Душкин Р. В.