Files
functional-programming/coursework/report/report.tex

399 lines
21 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\documentclass[a4paper, final]{article}
%\usepackage{literat} % Нормальные шрифты
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
\usepackage{tabularx}
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\usepackage{amsmath}
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
\usepackage{ragged2e} %для растягивания по ширине
\usepackage{setspace} %для межстрочного интервала
\usepackage{moreverb} %для работы с листингами
\usepackage{indentfirst} % для абзацного отступа
\usepackage{moreverb} %для печати в листинге исходного кода программ
\usepackage{pdfpages} %для вставки других pdf файлов
\usepackage{tikz}
\usepackage{graphicx}
\usepackage{afterpage}
\usepackage{longtable}
\usepackage{float}
% \usepackage[paper=A4,DIV=12]{typearea}
\usepackage{pdflscape}
% \usepackage{lscape}
\usepackage{array}
\usepackage{multirow}
\renewcommand\verbatimtabsize{4\relax}
\renewcommand\listingoffset{0.2em} %отступ от номеров строк в листинге
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
\usepackage[font=small, singlelinecheck=false, justification=centering, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
\usepackage{listings} %листинги
\usepackage{xcolor} % цвета
\usepackage{hyperref}% для гиперссылок
\usepackage{enumitem} %для перечислений
% Настраиваем листинги, чтобы они использовали счётчик figure
% \AtBeginDocument{
% \renewcommand{\thelstlisting}{\thefigure} % Листинги используют тот же счетчик, что и рисунки
% \renewcommand{\lstlistingname}{Рис.} % Меняем подпись на "Рисунок"
% }
% Автоматически увеличиваем счетчик figure перед каждым листингом
% \let\oldlstlisting\lstlisting
% \renewcommand{\lstlisting}[1][]{%
% \refstepcounter{figure}% Увеличиваем счетчик figure
% \oldlstlisting[#1]% Вызываем оригинальную команду lstlisting
% }
\newcommand{\specialcell}[2][l]{\begin{tabular}[#1]{@{}l@{}}#2\end{tabular}}
\setlist[enumerate,itemize]{leftmargin=1.2cm} %отступ в перечислениях
\hypersetup{colorlinks,
allcolors=[RGB]{010 090 200}} %красивые гиперссылки (не красные)
% подгружаемые языки — подробнее в документации listings (это всё для листингов)
\lstloadlanguages{ Haskell}
% включаем кириллицу и добавляем кое−какие опции
\lstset{tabsize=2,
breaklines,
basicstyle=\footnotesize,
columns=fullflexible,
flexiblecolumns,
numbers=left,
numberstyle={\footnotesize},
keywordstyle=\color{blue},
inputencoding=cp1251,
extendedchars=true
}
\lstdefinelanguage{MyC}{
language=Haskell,
% ndkeywordstyle=\color{darkgray}\bfseries,
% identifierstyle=\color{black},
% morecomment=[n]{/**}{*/},
% commentstyle=\color{blue}\ttfamily,
% stringstyle=\color{red}\ttfamily,
% morestring=[b]",
% showstringspaces=false,
% morecomment=[l][\color{gray}]{//},
keepspaces=true,
escapechar=\%,
texcl=true
}
\textheight=24cm % высота текста
\textwidth=16cm % ширина текста
\oddsidemargin=0pt % отступ от левого края
\topmargin=-1.5cm % отступ от верхнего края
\parindent=24pt % абзацный отступ
\parskip=5pt % интервал между абзацами
\tolerance=2000 % терпимость к "жидким" строкам
\flushbottom % выравнивание высоты страниц
% Настройка листингов
\lstset{
language=Haskell,
extendedchars=\true,
inputencoding=utf8,
keepspaces=true,
captionpos=t,
}
\begin{document} % начало документа
% НАЧАЛО ТИТУЛЬНОГО ЛИСТА
\begin{center}
\hfill \break
\hfill \break
\normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ\\
федеральное государственное автономное образовательное учреждение высшего образования «Санкт-Петербургский политехнический университет Петра Великого»\\[10pt]}
\normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt]
\normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt]
\normalsize{Направление: 02.03.01 <<Математика и компьютерные науки>>}\\
\hfill \break
\hfill \break
\hfill \break
\hfill \break
\large{Отчет по курсовой работе}\\
\large{по дисциплине}\\
\large{<<Функциональное программирование>>}\\
\large{Вариант 5}\\
\hfill \break
% \hfill \break
% \hfill \break
\end{center}
\small{
\begin{tabular}{lrrl}
\!\!\!Студент, & \hspace{2cm} & & \\
\!\!\!группы 5130201/20102 & \hspace{2cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
\!\!\!Преподаватель,\\ \hspace{-5pt}к. т. н., доц. & \hspace{2cm} & \underline{\hspace{3cm}} & Моторин Д. Е. \\\\
&&\hspace{4cm}
\end{tabular}
\begin{flushright}
<<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2024г.
\end{flushright}
}
\hfill \break
% \hfill \break
\begin{center} \small{Санкт-Петербург, 2024} \end{center}
\thispagestyle{empty} % выключаем отображение номера для этой страницы
% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
\newpage
\tableofcontents
% \newpage
% \section*{Введение}
% \addcontentsline{toc}{section}{Введение}
\newpage
\section {Постановка задачи}
В рамках курсовой работы необходимо реализовать два синтаксических анализатора, решающих следующие задачи:
\begin{enumerate}
\item Разработка синтаксического анализатора для обработки строк из текстового файла. Требуется:
\begin{itemize}
\item Читать строки, содержащие значения и бинарные операции, из текстового файла (.txt), название которого вводит пользователь.
\item Разбирать значения, представленные целыми числами в десятичной системе счисления.
\item Обрабатывать бинарные операции: сложение, вычитание, умножение, деление.
\item Вычислять результат выражения и выводить его на экран.
\end{itemize}
\item Разработка синтаксического анализатора текста и генератора продолжения текста. Задачи:
\begin{enumerate}
\item Считать текст из файла, название которого вводит пользователь, и выполнить его синтаксический анализ:
\begin{itemize}
\item Разбить текст на предложения, используя следующие правила: слова состоят только из букв; предложения состоят из слов и разделяются символами: \texttt{. ! ? ; : ( )}.
\item Удалить из текста все символы пунктуации и цифры.
\end{itemize}
\item Построить модель N-грамм:
\begin{itemize}
\item Использовать биграммы и триграммы.
\item Составить словарь, где ключами являются одно слово или пара слов, а значениями — списки всех уникальных возможных продолжений.
\item Сохранить словарь в текстовый файл (.txt).
\end{itemize}
\item Реализовать пользовательское взаимодействие:
\begin{itemize}
\item При вводе одного или пары слов возвращать случайную строку длиной от 2 до 15 слов, основанную на созданном словаре.
\item Если введенное слово отсутствует в ключах словаря, выводить сообщение об этом.
\end{itemize}
\item Организовать диалог между двумя моделями N-грамм, созданными на основе двух различных текстов:
\begin{itemize}
\item Пользователь задает начальное слово или пару слов и количество сообщений (глубину диалога).
\item Ответ каждой модели основывается на последнем слове (или предпоследнем, если последнее отсутствует в словаре) из предыдущего сообщения оппонента.
\end{itemize}
\end{enumerate}
В качестве текстов для построения моделей использовать произведения Антона Павловича Чехова.
\end{enumerate}
% \newpage
% \section {Математическое описание}
\newpage
\section{Особенности реализации}
Согласно заданию для каждой части работы был создан отдельный проект \texttt{stack}.
\subsection{Часть 1: Синтаксический анализ арифметических выражений}
\subsubsection{Тип Parser}
Тип \texttt{Parser} обеспечивает разбор входной строки по заданным правилам. Он принимает на вход список токенов (например, символов) и пытается разобрать их в соответствии с описанными правилами, возвращая либо результат с оставшейся частью строки, либо \texttt{Nothing}, если разбор не удался.
Код типа \texttt{Parser} представлен в листинге~\ref{lst:parser_type}.
\begin{itemize}
\item Вход: список токенов.
\item Выход: результат разбора в виде \texttt{Maybe ([tok], a)}.
\end{itemize}
Для типа \texttt{Parser} определены представители классов типов для \texttt{Functor}, \texttt{Applicative} и \texttt{Alternative}. Представитель \texttt{Functor} позволяет применять функцию к результату разбора парсера. Представители \texttt{Applicative} и \texttt{Alternative} позволяют последовательно комбинировать разные парсеры и функции и составлять сложные парсеры из простых.
\begin{lstlisting}[caption={Определение типа Parser и его представителей для классов типов Functor, Applicative и Alternative.}, label={lst:parser_type}]
newtype Parser tok a =
Parser { runParser :: [tok] -> Maybe ([tok], a)}
instance Functor (Parser tok) where
fmap g (Parser p) = Parser $ \xs ->
case p xs of
Nothing -> Nothing
Just (cs, c) -> Just (cs, g c)
instance Applicative (Parser tok) where
pure x = Parser $ \toks -> Just (toks, x)
Parser u <*> Parser v = Parser $ \xs ->
case u xs of
Nothing -> Nothing
Just (xs', g) ->
case v xs' of
Nothing -> Nothing
Just (xs'', x) -> Just (xs'', g x)
instance Alternative (Parser tok) where
empty = Parser $ \_ -> Nothing
Parser u <|> Parser v = Parser $ \xs ->
case u xs of
Nothing -> v xs
z -> z
\end{lstlisting}
\subsubsection{Работа с арифметическими операциями}
В листинге~\ref{lst:Operation} представлен код определения класса \texttt{Operation}, а также нескольких вспомогательных функций для работы с ним. Тип используется для хранения одной из четырёх арифметических операций: сложение, вычитание, умножение и деление. Функция \texttt{operationToString} принимает значение типа \texttt{Operation} и возвращает его строковое представление. Функция \texttt{operationToOperator} также принимает значение типа \texttt{Operation}, а возвращает функцию, соответствующую арифметической операции.
\begin{lstlisting}[caption={Определение типа Operation и функций для работы с ним.}, label={lst:Operation}]
data Operation = Add | Sub | Mul | Div deriving Show
operationToString :: Operation -> String
operationToString op = case op of
Add -> "+"
Sub -> "-"
Mul -> "*"
Div -> "/"
operationToOperator :: Operation -> (Int -> Int -> Int)
operationToOperator op = case op of
Add -> (+)
Sub -> (-)
Mul -> (*)
Div -> div
\end{lstlisting}
\subsubsection{Базовые парсеры}
В этом разделе рассматриваются основные парсеры, используемые для разбора арифметических выражений. Эти парсеры являются строительными блоками для более сложных выражений. Их код представлен в листинге~\ref{lst:base_parsers}.
\begin{itemize}
\item \texttt{satisfy} — парсит символ, удовлетворяющий предикату, и возвращает его.
\item \texttt{char} — парсит один заданный символ и возвращает его.
\item \texttt{digit} — парсит одну цифру и возвращает в виде символа.
\item \texttt{skipSpaces} — парсит все пробелы пока не встретить символ, который пробелом не является.
\item \texttt{number} — парсит целое число (последовательность цифр) и возвращает в виде~\texttt{Int}.
\item \texttt{operation} — парсит арифметическую операцию (\texttt{+}, \texttt{-}, \texttt{*}, \texttt{/}) и возвращает как значение типа \texttt{Operation}.
\end{itemize}
\begin{lstlisting}[caption={Базовые парсеры}, label={lst:base_parsers}]
satisfy :: (tok -> Bool) -> Parser tok tok
satisfy pr = Parser $ \case
(c:cs) | pr c -> Just (cs, c)
_ -> Nothing
char :: Char -> Parser Char Char
char c = satisfy (== c)
digit :: Parser Char Char
digit = satisfy isDigit
skipSpaces :: Parser Char String
skipSpaces = many (char ' ')
number :: Parser Char Int
number = skipSpaces *> (strToInt <$> some digit)
where
strToInt = foldl (\acc x -> acc * 10 + digitToInt x) 0
operation :: Parser Char Operation
operation = skipSpaces *> (
char '+' *> pure Add <|>
char '-' *> pure Sub <|>
char '*' *> pure Mul <|>
char '/' *> pure Div
)
\end{lstlisting}
\subsubsection{Парсер expression}
Парсер \texttt{expression}, код которого представлен в листинге~\ref{lst:expression}, парсит выражение вида \texttt{<число> <операция> <число>}. В случае успеха возвращает кортеж вида: \texttt{(Int -- левый операнд, Operation -- операция, Int -- правый операнд)}. Является комбинацей парсеров \texttt{number} и \texttt{operation}. Не чувствителен к пробелам до выражения и внутри него, между операндами и оператором. Поглощает также пробелы после выражения с помощью парсера \texttt{skipSpaces}.
\begin{lstlisting}[caption={Код функции expression}, label={lst:expression}]
expression :: Parser Char (Int, Operation, Int)
expression = (,,) <$> number <*> operation <*> number <* skipSpaces
\end{lstlisting}
\subsubsection{Функция processExpression}
Код функции \texttt{processExpression} представлен в листинге~\ref{lst:processExpression}.
Функция принимает строку, парсит её как выражение, вычисляет результат и возвращает строку с ответом. При ошибке парсинга генерирует ошибку.
Вход: \texttt{String} — строка с выражением.
Выход: \texttt{String} — результат вычисления в формате \texttt{a op b = result}.
Вспомогательная функция \texttt{calculateExpression} используется для вычисления результата. На вход она получает операнды и операцию, а возвращает вычисленное значение. Её код также представлен в листинге~\ref{lst:processExpression}.
\begin{lstlisting}[caption={Код функции processExpression}, label={lst:processExpression}]
processExpression :: String -> String
processExpression s = case runParser expression s of
Nothing -> error $ "Не удалось прочитать выражение: \"" ++ s ++ "\""
Just (cs, (a, op, b)) -> case cs of
[] -> show a ++ " " ++ operationToString op ++ " " ++
show b ++ " = " ++ show (calculateExpression (a, op, b)) ++ "\n"
_ -> error $ "Не удалось прочитать выражение: \"" ++ s ++ "\""
calculateExpression :: (Int, Operation, Int) -> Int
calculateExpression (a, op, b) = (operationToOperator op) a b
\end{lstlisting}
\subsubsection{Функция main}
Код функции \texttt{main} представлен в листинге~\ref{lst:main}.
Функция \texttt{main} считывает имя файла у пользователя, читает файл, построчно обрабатывает каждое выражение с помощью \texttt{processExpression} и выводит результат.
\begin{lstlisting}[caption={Код функции main}, label={lst:main}]
main :: IO ()
main =
putStrLn "Введите имя файла:" >>
getLine >>= \fileName ->
readFile fileName >>= \content ->
let expressions = lines content in
putStrLn $ concatMap processExpression expressions
\end{lstlisting}
\subsection{Часть 2: Синтаксический анализ текста и генерация фраз}
\newpage
\section {Результаты работы программы}
\newpage
\section*{Заключение}
\addcontentsline{toc}{section}{Заключение}
\newpage
\section*{Список литературы}
\addcontentsline{toc}{section}{Список литературы}
\vspace{-1.5cm}
\begin{thebibliography}{0}
\bibitem{JuicyPixels}
Hackage -- unescaping-print: Tiny package providing unescaping versions of show and print, URL: \url{https://hackage.haskell.org/package/unescaping-print}, Дата обращения: 09.12.2024.
\end{thebibliography}
\end{document}