Адресная книжка на Haskell

Федеральное министерство по образованию РФ

Владимирский Государственный Университет

Кафедра ФиПМ

















ОТЧЕТ

По курсовому проекту

По дисциплине

«Функциональное программирование»







Выполнил: Николаева А. М.

Принял: Медведева О.Н.

















Владимир 2009


Содержание



1. Постановка задачи. Исходные данные

2. Теоретическая часть

2.1 Основы HTML

2.1.1 Структура программы на HTML

2.1.2 Основные Теги

2.1.3 Тег для создания ссылки на почтовый ящик

2.2 Выражения в Haskell

2.2.1 Кортежи

2.2.2 Списки

2.2.3 Do – выражение

2.3 Монада ввода/вывода

2.3.1 Функции ввода

2.3.2 Функции вывода

2.3.3 Обработка исключений

2.3.4 Файлы, каналы и обработчики

2.4 GUI

2.4.1 wxWidgets

2.4.2 wxHaskell

3. Анализ задачи

4. Программная реализация

5. Тестирование программы

Заключение

Список использованной литературы




1. Постановка задачи. Исходные данные



Разработать алгоритм поиска адресов e-mail, ICQ и имен пользователей в файлах и в качестве формата вывода использовать .html страницу. Реализовать его с помощью среды разработки GHCi языка Haskell.

Исходные данные:

Файл icq.txt, содержащий e-mail адреса и номера ICQ.

Файл e-mail.txt, содержащий ИОФ и e-mail.

Где поле ICQ является необязательным, а поле ИОФ может не содержать 1 или 2 составляющих аббревиатуры. Поле e-mail является обязательным для обоих файлов, так как по нему осуществляется поиск.

Содержимое и формат исходных файлов:







Файл вывода с расширением *.html или *.htm или *.mht может быть как существующим на диске или создаваемым пользователем.


2. Теоретическая часть



2.1 Основы HTML



2.1.1 Структура программы на HTML

Структура HTML-документа определяется упорядоченным набором тегов следующего вида:

<HTML>

<HEAD>

</HEAD>

<BODY>

</BODY>

</HTML>

Программа клиент-браузер при просмотре файлов с этими тегами выполняет отображение документа в окне. Каждый такой файл имеет расширение html или htm, а набрать его можно в любом текстовом редакторе. Теги играют роль команд заставляют браузер выполнить предписываемые ими действия. Область действия тега определяется тем местом, где он указан, и тем местом, где он закрыт (записан в угловых скобках с предшествующей косой чертой).



2.1.2 Основные Теги

<html></html>

Тег HTML указывает начало и конец HTML документа.

<head></head>

Тег HEAD (заголовок HTML-документа) содержит информацию, относящуюся к документу в целом.

<body></body>

Тег BODY охватывает ту часть HTML-документа (текст, изображения и элементы формирования), которая будет видна пользователю.

<title></title>

Тег TITLE устанавливает заголовок HTML-документа, выводимый в строке заголовка окна броузера.

<body bgcolor=?>

Атрибут BGCOLOR устанавливает цвет фона HTML-документа. Цвет может быть указан с помощью с помощью названия или шестнадцатиричного кода.

<body text=?>

Атрибут TEXT устанавливает цвет для всего текста HTML-документа. Цвет может быть указан с помощью с помощью названия или шестнадцатиричного кода.

<font size=?></font>

Атрибут SIZE тега FONT устанавливает относительный размер шрифта. Список возможных значений состоит из положительных и отрицательных чисел от 0 до 7.

<font color=?></font>

Атрибут COLOR тега FONT устанавливает цвет текста. Цвет может быть указан с помощью с помощью названия или шестнадцатиричного кода.

<table></table>

Тег TABLE устанавливает начало и конец таблицы. Все теги, определяющие структуру таблицы, должны располагаться между тегами TABLE.

<tr></tr>

Тег TR определяет строку таблицы.

<td></td>

Тег TD определяет колонку таблицы. Текст, заключенный между тегами TD ("table data" - табличные данные), отображается внутри одной ячейки.

<th></th>

Тег TH устанавливает режим отображения текста в виде заголовка таблицы.

<table border=?>

Атрибут BORDER тега TABLE устанавливает ширину рамки таблицы в пикселах.

<tr align=?> or <td align=?>

Атрибут ALIGN устанавливает выравнивание содержимого ячейки по ее левому краю (LEFT), по центру (CENTER) или по ее правому краю (RIGHT).



2.1.3 Тег для создания ссылки на почтовый ящик

<a href="URL"></a>

Тег A устанавливает связь с некоторой точкой внутри того же HTML-документа или с другим URL (гипертествовая ссылка). Атрибут HREF тега A описывает объект, представляющий собой текст или рисунок внутри HTML-документа, либо текст или рисунок во внешнем документе.

<a name="NAME"></a>

Тег A устанавливает связь с некоторой точкой внутри того же HTML-документа или с другим URL (гипертествовая ссылка). Атрибут NAME тега A описывает точку внутри HTML-документа, в которую нужно переместить пользователя.

Поставить ссылку на чей-то адрес электронной почты не составляет труда. Мы просто пишем:

<a href="mailto:foo@mail.com">Спамте меня, ребята!</a>



2.2 Выражения в Haskell



2.2.1 Кортежи

Кортежи записываются в виде (e1 , . . . , ek) и могут быть произвольной длины

k >= 2 . Конструктор для кортежа размером n обозначается (,...,), где n − 1 запятых.

Таким образом, (a,b,c) и (,,) a b c обозначают одно и то же значение. Стандартные операции над кортежами описаны в Prelude.

Трансляция: (e1 , . . . , ek) для k >= 2 является экземпляром кортежа размера

k, в соответствии с определением в Prelude и не требуют трансляции. Если t1 , ...

, tk – соответствующие типы e1 , ... , ek , то типом кортежа будет (t1 , . . . , tk).



2.2.2 Списки

Списки записываются в виде [e1, ..., ek], где k>=1. Конструктором списка является :, пустой список обозначается []. Стандартные операции над списками описаны в Prelude:

Функция head возвращает первый элемент списка.

Функция last возвращает последний элемент списка.

Функция tail возвращает список без первого элемента

Функция init возвращает список без последнего элемента

Функция null проверяет список на пустоту. Если в качестве аргумента этой опера-ции будет задан пустой список, то функция выдаст значение True, в противном случае - False

Функция length возвращает длину списка.

Функция elem проверяет наличие элемента в списке.

Функция take возвращает список, состоящий из n первых элементов исходного списка.

Функция zip возвращает список, состоящий из пар объединенных исходных списков.

Функция !! возвращает элемент, номер которого задан (начиная с 0).

Функции head и tail определены для непустых списков. При попытке применить их к пустому списку интерпретатор сообщает об ошибке.



2.2.3 Do – выражение

exp -> do { stmts } (do-выражение)

stmts -> stmt1 ... stmtn exp [;] (n>=0)

stmt -> exp ;

| pat <- exp ;

| let decls ;

| ; (пустая инструкция)

Перевод:

выражение -> do { список-инструкций } (do-выражение)

список-инструкций -> инструкция1 ... инструкцияn выражение [;] (n>=0)

инструкция -> выражение ;

| образец <- выражение ;

| let список-объявлений ;

| ; (пустая инструкция)

Do-выражения предоставляют более удобный синтаксис для монадического программирования. Оно позволяет записать такое выражение

putStr "x: " >>

getLine >>= \l ->

return (words l)

в более традиционном виде:

do putStr "x: "

l <- getLine

return (words l)

Трансляция:

Для do-выражений выполняются следующие тождества, которые, после удаления пустых stmts, можно использовать в качестве трансляции в ядро:

do {e} =e

do {e;stmts} =e >> do {stmts}

do {p <- e; stmts} =let ok p = do {stmts}

ok _ = fail "..."

in e >>= ok

do {let decls; stmts} =let decls in do {stmts}

Пропуски "..." обозначают генерируемое компилятором сообщение об ошибке, передаваемое функции fail, желательно давая некоторое указание на местоположение ошибки сопоставления с образцом; функции >>, >>= и fail являются операциями в классе Monad, определенными в Prelude; ok является новым идентификатором.

Как показано в трансляции do, переменные, связанные let, имеют полностью полиморфные типы, тогда как те переменные, которые определены с помощью <-, являются связанными лямбда-выражением и поэтому являются мономорфными.



2.3 Монада ввода/вывода



2.3.1.Функции ввода

Эти функции считывают данные из стандартного устройства ввода (обычно это пользовательский терминал).

getChar :: IO Char

getLine :: IO String

getContents :: IO String

interact :: (String -> String) -> IO ()

readIO :: Read a => String -> IO a

readLn :: Read a => IO a

Операция getChar вызывает исключение при появлении признака конца файла, a предикат isEOFError, который распознает это исключение, определен в библиотеке IO. Операция getLine вызывает исключение при тех же обстоятельствах, что и hGetLine, определенная в библиотеке IO.

Операция getContents возвращает весь пользовательский ввод в виде одной строки, которая считывается лениво, по мере надобности. Функция interact принимает в качестве аргумента функцию типа String->String. Весь ввод из стандартного устройства ввода передается этой функции в качестве аргумента, а результирующая строка выводится на стандартное устройство вывода.

Обычно операция read из класса Read используется для преобразования строки в значение. Функция readIO похожа на read, за исключением того, что она предупреждает монаду ввода - вывода об ошибке разбора вместо завершения программы. Функция readLn объединяет getLine и readIO.



2.3.2 Функции вывода

Эти функции записывают в стандартное устройство вывода (обычно это пользовательский терминал).

putChar :: Char -> IO ()

putStr :: String -> IO ()

putStrLn :: String -> IO () -- добавляет символ новой строки

print :: Show a => a -> IO ()

Функция print выводит значение любого пригодного для печати типа на стандартное устройство вывода. Пригодные для печати типы --- это те типы, которые являются экземплярами класса Show; print преобразует значения в строки для вывода, используя операцию show, и добавляет символ новой строки.



2.3.3 Обработка исключений

Что делать, если в процессе операций ввода/вывода возникла неординарная ситуация? Например, функция getChar обнаружила конец файла. В этом случае произойдет ошибка. Haskell предлагает для этих целей механизм обработки исключений. Для этого не используется какой-то специальный синтаксис, но есть специальный тип IOError, который содержит описания всех возникаемых в процессе ввода/вывода ошибок.

Обработчик исключений имеет тип (IOError -> IO a), при этом функция catch ассоциирует (связывает) обработчик исключений с набором действий:

catch:: IO a -> (IOError -> IO a) -> IO a

Аргументами этой функции являются действие (первый аргумент) и обработчик исключений (второй аргумент). Если действие выполнено успешно, то просто возвращается результат без возбуждения обработчика исключений.

Если же в процессе выполнения действия возникла ошибка, то она передается обработчику исключений в качестве операнда типа IOError, после чего выполняется сам обработчик.



2.3.4 Файлы, каналы и обработчики

Для работы с файлами Haskell предоставляет все возможности, что и другие языки программирования. Однако большинство этих возможностей определены в модуле IO, а не в Prelude, поэтому для работы с файлами необходимо явно импортировать модуль IO (import IO).

Открытие файла порождает обработчик (он имеет тип Handle). Закрытие обработчика инициирует закрытие соответствующего файла. Обработчики могут быть также ассоциированы с каналами, т.е. портами взаимодействия, которые не связаны напрямую с файлами. В Haskell'е предопределены три таких канала:

stdin (стандартный канал ввода),

stdout (стандартный канал вывода)

stderr (стандартный канал вывода сообщений об ошибках).

Таким образом, для использования файлов можно пользоваться следующими вещами:

type FilePath= String

openFile:: FilePath -> IOMode -> IO Handle

hClose:: Handle -> IO ()

data IOMode= ReadMode | WriteMode | AppendMode | ReadWriteMode

Есть одна интересная и важная функция - hGetContents, которая берёт содержимое переданного ей в качестве аргумента файла и возвращает его в качестве одной длинной строки.

Получается так, что в Haskell'е заново изобретено императивное программирование...

В некотором смысле - да. Монада IO встраивает в Haskell маленький императивный подъязык, при помощи которого можно осуществлять операции ввода/вывода. И написание программ на этом подъязыке выглядит обычно с точки зрения императивных языков. Но есть существенное различие: в Haskell'е нет специального синтаксиса для ввода в программный код императивных функций, все осуществляется на уровне функциональной парадигмы.

Функции для работы с файлами определенные в модуле Prelude

Эти функции не требуют импортировать модуль IO в программу, так как они определены в модуле Prelude.

Функции writeFile и appendFile соответственно записывают или добавляют в конец строку, свой второй аргумент, в файл, свой первый аргумент. Функция readFile считывает файл и возвращает содержимое файла в виде строки. Файл считывается лениво, по требованию, как в getContents.

type FilePath = String

writeFile :: FilePath -> String -> IO ()

appendFile :: FilePath -> String -> IO ()

readFile :: FilePath -> IO String

Обратите внимание, что writeFile и appendFile записывают литеральную строку в файл. Для того чтобы записать значение любого пригодного для печати типа, как в print, сначала используется функция show для преобразования значения в строку.

main = appendFile "квадраты" (show [(x,x*x) | x <- [0,0.1..2]])



2.4 GUI



2.4.1 wxWidgets

wxWidgets (ранее известная как wxWindows) — это кросс-платформенная библиотека инструментов с открытым исходным кодом для построения графического интерфейса пользователя (GUI).

wxWidgets выпущен под «разрешающей изменения (но явно одобренной OSI) LGPL». Проект был запущен в 1992 Юлианом Смартом (Julian Smart), который до сих пор остаётся главным разработчиком.

wxWidgets позволяет компилировать программы на множестве компьютерных платформ с минимальными изменениями в исходном коде, либо вообще без них. Она поддерживает системы Microsoft Windows, Apple Macintosh, UNIX-подобные (для X11, Motif и GTK+), OpenVMS и OS/2. Внедряемая версия находится в разработке.

Библиотека разработана на C++, но может подключаться ко множеству других распространённых языков, таких, как Ruby (wxRuby, Anvil), Python (wxPython), Smalltalk (wxSqueak), Perl и Java.

Библиотека не имитирует вид компонентов, используя графические примитивы различных поддерживаемых платформ. Вместо этого wxWidgets предоставляет тонкую абстракцию к существующим компонентам системы. Другими словами, основной код wxWidgets предпочитает вызывать «родной» элемент интерфейса платформы, вместо того, чтобы повторно его реализовывать. Это предоставляет быстрый, естественно выглядящий интерфейс по сравнению с библиотеками вроде Swing (для Java).

wxWidgets разработана не только для того, чтобы создавать GUI. Она также имеет набор классов для работы с графическими изображениями, HTML, XML документами, архивами, файловыми системами, процессами, подсистемами печати, мультимедиа, сетями, классы для организации многопоточности, отладки, отправки дампов и множество других инструментов.

WxWidgets - это инструмент разработчика для написания настольных или мобильных приложений с графическим интерфейсом (GUI). Этот фреймворк экономит много времени на написание кроссплатформенных приложений и обеспечивает их стандартное поведение.

Приложения обычно показывают пользователю окна со стандартными элементами управления, изображениями и графиками; реагируют на события от мышки, клавиатуры и других источников; общаются с другими приложениями, запускают другие программы - подобные стандартные блоки отходят на второй план при использовании WxWidgets, позволяя программисту сосредоточить свои усилия на функционале приложения.

Пока WxWidgets называют инструментарием разработки графических интерфейсов пользователя, он действительно им является. Однако на самом деле он не ограничивается этим - фреймворк реализует многие аспекты программирования. И это не является избыточностью, т.к. от WxWidgets требуется, чтобы приложения целиком были переносимыми на разные платформы, а не только их графическая часть. WxWidgets предоставляет классы для файлов, потоков, многопоточности, конфигурирования приложений, межпроцессного взаимодействия, доступа к базам данных и многое другое.

Особенность, которая отличает WxWidgets от многих других фреймворков, таких как MFC и OWL, – это многоплатформенная природа. WxWidgets имеет API, который одинаков или почти одинаков на всех поддерживаемых платформах. Это означает, что вы можете написать приложение, к примеру, под Windows и затем с очень немногими (если они вообще понадобятся) изменениями перекомпилировать его под Linux или Mac OS X. Это дает огромное преимущество по сравнению с раздельным программированием под каждую платформу: вам не придется изучать специализированный API для каждой платформы. Кроме того, при выпуске новых версий операционных систем и версий WxWidgets уже написанные приложения всегда будут выглядеть актуально и использовать последние графические версии элементов управления.

Другая отличительная особенность - WxWidgets использует родные для операционной системы графические элементы интерфейса. Многие фреймворки используют собственные графические элементы управления, снабжая их сменяемыми темами для каждой платформы. Напротив, WxWidgets использует родные графические элементы пользовательского интерфейса всюду где это возможно. В результате они не просто выглядят как родные для ОС - они на самом деле родные. Это очень важно для пользователей, привыкших работать в конкретной среде, поскольку любое, даже самое незначительное, изменение интерфейса сказывается на их способности свободно использовать свой опыт управления в стиле стандарта их ОС.

WxWidgets использует C++. Почему не Java? Java отлично подходит для web-приложений, но не является удачным выбором для десктопа. Прежде всего, C++ приложения, работающие с wxWidgets быстрее, имеют более естественный вид. Они проще в установке, поскольку не требуется специальная виртуальная машина. C++, к тому же, предоставляет простой доступ к низкоуровневой функциональности, и написанный код может быть легко интегрирован с уже имеющимся C/C++ кодом.

Разработчики используют WxWidgets по разным причинам: от замены MFC на одной платформе до обеспечения возможности быстрого переноса приложения с, к примеру, Windows на Unix и Mac OS X. WxWidgets также позволяет переносить приложения на мобильные платформы, такие как встраиваемый Linux, Pocket PC, или Palm OS.

Проект WxWidgets был основан в 1992 году, когда Джулиан Смарт работал в Эдинбургском Университете над инструментом диаграммирования под названием “Hardy”. Он не пожелал выбирать между разработкой его для рабочей станции Sun или для платформы PC, он предпочел написать кросс-платформенный фреймворк.

Поскольку мощность существующих кросс-платформенных фреймворков была ограничена, а отделение не имело необходимого бюджета для написания такового в любом случае, то он решил написать такой самостоятельно. Университет предоставил ему доступ для закачки wxWidgets 1.0 на FTP-сервер отделения в сентябре 1992 и другие разработчики начали использовать его код. В начале wxWidgets был нацелен на Xview и MFC 1.0. Пользователи Borland С++ , жаловавшиеся на привязку к MFC, таким образом стали переписывать программы на чистый Win32. Поскольку XView открывал путь на Motif, то перенос на Motif был запущен весьма оперативно. Тем временем маленькое, однако полное энтузиазма сообщество wxWidgets-программистов уже появилось и обзавелось своей почтовой рассылкой. Добавления и исправления получали распространение в рассылке. WxWidgets постепенно расширял круг своей пользовательской аудитории по всему миру: индивидуальные программисты, академические группы, государственные учреждения, и те кто нашел, что WxWidgets - более удобный продукт с лучшей поддержкой, чем коммерческие продукты, которые они до этого видели или использовали.

В 1997 году новая версия wxWidgets 2 API была спроектирована при помощи Маркуса Холзема(который еще во времена создания рассылки создал Xt направление wxWidgets) . Вольфрам Глогер предложил идею портирования WxWidgets на GTK+ и Роберт Роблинг создал необходимые графические элементы пользователя, адаптированные для GNOME. Он стал основоположником разработки wxGTK, и поныне оставаясь главным специалистом в разработке Unix/Linux-порта WxWidgets. В 1998 году порт для Windows и порт для GTK+ были совмещены и выложены под управлением CVS системы. Вадим Зейтлин присоединился к проекту чтобы поспособоствовать огромной части дизайна и кода, а также Стефан Ксомор начал создание MAC OS порта, тоже в 1998. 1999 обозначен приходом программиста с именем Vaclav Slavik. Он создал внушительные wxHTML классы и HTML-базированный просмотрщик помощи.

В 2000 году фирма SciTech Inc. профинансировала начало разработки wxUniversal.

Собственный для wxWidgets набор графических элементов пользователя для использования на платформах, у которых пока что нет никаких графических элементов пользователя. wxUniversal стал первым используемым в этой фирме портом для MGL, их низкоуровневому графическому слою.

В 2002 году Джулиан Смарт и Роберт Ройблинг добавил wxX11 порт используя wxUniversal графические элементы пользовательского интерфейса.

В июле 2003 года wxWidgets начал запускаться на Windows CE, а Роберт Ройблинг продемонстрировал wxGTK приложение, запущенное на встраиваемой платформе GPE Linux.

В 2004 году WxWidgets по просьбе Microsoft поменял оригинальное название “wxWindows” на WxWidgets, за что получил финансовую помощь.

Также в 2004 Стефан Ксомор и другие его помощники успешно завершили перенос WxWidgets (wxMac) на MAC OS X., значительно улучшив функциональные возможности приложений для OS X. Порт, используяющий Cocoa был заметно улучшен (направление возглавляли Дэвид Еллиот и Виллиам Осборн).

Виллиам Осборн выиграл конкурс по созданию версии wxWidgets для Palm OS 6, задачей ставилась минимальная поддержка платформы.

В апреле 2005 года была выпущена версия 2.6, в которой было осуществлено слияние всех основных портов фреймворка.

20 февраля 2004 г. разработчики wxWindows предупредили, что проект будет переименован в wxWidgets, как результат переговоров Майкрософт и Юлиана Смарта в связи с зарезервированной Майкрософт торговой маркой Windows (за смену имени разработчики wxWidgets и других связанных проектов получили денежную компенсацию).

Проекты поддержки языков программирования:

wxBasic — для Бэйсик

wxPerl — для Perl

wxPython — для Python

wxRuby — для Руби

Anvil — для Руби, на базе wxRuby, с улучшеным синтаксисом

wxSqueak — для Smalltalk

wxLua — для Lua

wx4j — для Java

wxJS — для JavaScript

wxHaskell — для Haskell

wxEiffel — для Эйфель

wxD — для D

wx.NET — для .NET

wxErlang — для Erlang



2.4.2 wxHaskell

wxHaskell является портативной GUI библиотекой для Haskell, построенной на wxWidgets. Очень часто используются для создания графического интерфейса на функциональном языке.

wxHaskell является графической библиотекой среднего уровня. От wxHaskell есть производные библиотеки высокого уровня:

wxFruit

Phooey

В отличие от wxHaskell, на высоком уровне GUI эти библиотеки реализованы на Gtk2Hs, которая основана на gtk2.

Все вышеупомянутые GUI библиотеки являются экспериментальными, с использованием современных математических понятий в их подходе.




3. Анализ задачи



icqTest :: String -> Bool

По наличию @ в строке устанавливает ее принадлежность к полю e-mail.

pare :: [String] -> [(String,String)]

Из входной строки формирует список пар ICQ и e-mail.

pare2 :: [String] -> [(String,String)]

Из входной строки формирует список пар e-mail и ИОФ

comp :: String -> [(String,String)] -> String

Функция алгоритма поиска для получения ИОФ контакта

f :: [(String,String)] -> [(String,String)] -> String

Функция алгоритма поиска, формирует структуру таблицы html документа.

outFile :: String -> String -> String -> IO()

Функция, выводящая результаты поиска в файл и формирующая html документ

main :: IO ()

Входная точка в программу, формирует графический интерфейс пользователя.




4. Программная реализация



import Graphics.UI.WX

import Graphics.UI.WXCore

import System

import Char ( toUpper)

import IO

--test for e-mail? or ICQ?

icqTest :: String -> Bool

icqTest [] = False

icqTest (x:xs) = if x=='@' then True else icqTest xs

--pare ICQ and E-mail

pare :: [String] -> [(String,String)]

pare [] = []

pare [x] = (x," "):[]

pare (x:xs) = if icqTest (head xs)==False then (x,head xs):[]++pare (tail xs) else (x," "):[]++pare xs

--pare E-mail and IOF

pare2 :: [String] -> [(String,String)]

pare2 [] = []

pare2 (x:xs) = if icqTest (head xs)==False then (if icqTest (head(tail xs))==False then (x++" "++(head xs)++" "++(head (tail xs)),head(tail(tail xs))):[]++pare2 (tail(tail(tail xs))) else (x++" "++head xs,head(tail xs)):[]++pare2 (tail(tail xs)) ) else (x,head xs):[]++pare2 (tail xs)

--compare E-mail and return IOF

comp :: String -> [(String,String)] -> String

comp _ [("","")] = []

comp [] _ = []

comp x (y:ys) = if x==snd y then fst y else comp x ys

--compare pares and build html table

f :: [(String,String)] -> [(String,String)] -> String

f [([],[])] _ = ""

f (x:xs) (y:ys) = (("<TR>"++"\n"++"<TD>"++comp (fst x) (y:ys)) ++"</TD>"++"\n"++"<TD>"++ snd x ++ "</TD>" ++"\n"++"<TD>"++"<a href="++"\""++"mailto:"++ fst x ++"\""++">"++fst x++"</a>"++"</TD>"++"\n"++"</TR>"++"\n") ++ (if null xs then "" else f xs (y:ys))

--write html code in out File

outFile :: String -> String -> String -> IO()

outFile x y z = do s <- readFile x; d <- readFile y;writeFile z "<HTML> \n <Body bgcolor = floralwhite> \n <TABLE border=5 alight = center> \n <TR> <TH> FIO </TH> \n <TH> ICQ </TH> \n <TH> E-mail </TH> \n </TR> \n"; appendFile z (f (pare(words s))(pare2(words d)));appendFile z "</TABLE> \n </BODY> \n </HTML>"

--GUI mode

main :: IO ()

main = start gui

gui :: IO ()

gui

= do -- main gui elements: frame, panel, text control, and the notebook

f <- frame [text := "Controls"]

p <- panel f []

nb <- notebook p []

textlog <- textCtrl p [enabled := False, wrap := WrapNone]

-- use text control as logger

textCtrlMakeLogActiveTarget textlog

logMessage "logging enabled"

-- set f [on closing :~ \prev -> do logSetActiveTarget oldlog; logDelete log; prev]

-- first page

p1 <- panel nb []

--textBoxes

txt1 <- textEntry p1 [alignment := AlignLeft, text := "icq file name"]

txt2 <- textEntry p1 [alignment := AlignLeft, text := "e-mail file name"]

txt3 <- textEntry p1 [alignment := AlignLeft, text := "out file name"]

--buttons

ok <- button p1 [text := ">>", on command := do f1 <- get txt1 text;f2 <- get txt2 text;f3 <- get txt3 text; logMessage f1 ;logMessage f2;logMessage f3;outFile f1 f2 f3;]

quit <- button p1 [text := "Close", on command := close f]

-- specify layout

set f [layout :=

container p $

column 0

[ tabs nb

[tab "Sort Contakt List" $

container p1 $ margin 10 $ column 5 [hstretch $ widget txt1,hstretch $ widget txt2,hstretch $ widget txt3,row 5 [floatRight $ widget ok,floatLeft $ widget quit]]

]

, hfill $ minsize (sz 20 80) $ widget textlog

]

, clientSize := sz 400 300 ]

return ()






5. Тестирование программы



Изначальный вид приложения при запуске:





Рис.5.1



Введем Пути файлов в поля ввода:





Рис.5.2



После счелкаем кнопку >> и получаем html документ:






Заключение



В результате проделанной работы было получено приложение, сортирующее список контактов из файлов по ключевому полю e-mail. Для решения поставленной задачи был разработан и реализован алгоритм поиска для файлов с информацией, хранимой в заданном формате. Для реализации приложения была использована среда разработки языка Haskell-98 GHCi 6.10.1.




Список используемой литературы



1. Н.А. Роганова «Функциональное программирование»

2. Курс лекций по функциональному программированию

3. www.intuit.ru/department/pl/haskel98/6/

4. www.rsdn.ru/article/haskell/haskell_part1.xml

5. http://wxhaskell.sourceforge.net/

6. http://en.wikipedia.org/wiki/WxWidgets