Compare commits
8 Commits
a497908ed0
...
14238f7082
| Author | SHA1 | Date | |
|---|---|---|---|
| 14238f7082 | |||
| ae430df936 | |||
| 0de9d4ace1 | |||
| 8216523a6e | |||
| 7711f47dad | |||
| 4b3baff74f | |||
| 56b2555e15 | |||
| ca62ba2dc3 |
BIN
coursework/report/img/bad_result1.png
Normal file
BIN
coursework/report/img/bad_result1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
coursework/report/img/bad_result2.png
Normal file
BIN
coursework/report/img/bad_result2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
BIN
coursework/report/img/result1.png
Normal file
BIN
coursework/report/img/result1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
BIN
coursework/report/img/result2.png
Normal file
BIN
coursework/report/img/result2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
@@ -217,7 +217,7 @@
|
||||
|
||||
\newpage
|
||||
\section{Особенности реализации}
|
||||
Согласно заданию для каждой части работы был создан отдельный проект \texttt{stack}.
|
||||
Согласно заданию для каждой части работы был создан отдельный проект \texttt{stack}. Также все монадические вычисления были записаны без использования do-нотации, а лишь с помощью операторов \texttt{>\>>=} и \texttt{>\>>}. Все чистые функции были записаны в библиотеку \texttt{Lib.hs}, а доступ к вспомогательным функциям был ограничен.
|
||||
|
||||
\subsection{Часть 1: Синтаксический анализ арифметических выражений}
|
||||
|
||||
@@ -415,6 +415,14 @@ buildDictionary sentences =
|
||||
in Map.map nub combined
|
||||
\end{lstlisting}
|
||||
|
||||
\subsubsection{Функция saveDictionary}
|
||||
Функция \texttt{saveDictionary}, код которой представлен в листинге~\ref{lst:saveDictionary}, сохраняет словарь с N-граммами в текстовый файл. Она принимает на вход путь до файла и сам словарь, явно ничего не возвращает, но перезаписывает содержимое файла. Для получения текстового представления списков вместо стандартной функции \texttt{show}, используется \texttt{ushow} из библиотеки \texttt{unescaping-print}~\cite{unescaping-print}. \texttt{ushow} отображает кириллицу напрямую, без экранирования, в отличии от стандартной функции \texttt{show}.
|
||||
|
||||
\begin{lstlisting}[caption={Функция saveDictionary для сохранения словаря N-грамм в файл.}, label={lst:saveDictionary}]
|
||||
saveDictionary :: FilePath -> Map String [String] -> IO ()
|
||||
saveDictionary filePath dict = withFile filePath WriteMode $ \h ->
|
||||
mapM_ (\(k,v) -> hPutStrLn h $ ushow k ++ ": " ++ ushow v) (Map.toList dict)
|
||||
\end{lstlisting}
|
||||
|
||||
\subsubsection{Функция generatePhrase}
|
||||
|
||||
@@ -439,7 +447,9 @@ generatePhrase dict start initGenState =
|
||||
in gp next (next:acc) (n - length (words next)) newGenState
|
||||
\end{lstlisting}
|
||||
|
||||
Функция \texttt{processInput} (листинг~\ref{lst:processInput}) проверяет, существует ли введённое пользователем слово(или пара слов) в словаре, и если да — генерирует фразу.
|
||||
|
||||
\subsubsection{Функция processInput}
|
||||
Функция \texttt{processInput}, код которой представлен в листинге~\ref{lst:processInput}, проверяет, существует ли введённое пользователем слово (или пара слов) в словаре, и генерирует фразу, используя функцию \texttt{generatePhrase}. Функция принимает на вход словарь и строку с пользовательским вводом. Явно ничего не возвращает, но выводит результаты в консоль.
|
||||
|
||||
\begin{lstlisting}[caption={Функция processInput для обработки пользовательского ввода}, label={lst:processInput}]
|
||||
processInput :: Map String [String] -> String -> IO ()
|
||||
@@ -453,7 +463,14 @@ processInput dict input =
|
||||
|
||||
\subsubsection{Функция twoModelsDialog}
|
||||
|
||||
Реализован режим, в котором две модели N-грамм, построенные на разных текстах, обмениваются сообщениями. Начальное слово или пару слов задаёт пользователь, затем модели по очереди генерируют ответы, основываясь на словах, из которых состоит последнее сообщение их собеседника. Код, реализующий диалог, представлен в листинге~\ref{lst:twoModelsDialog}.
|
||||
Функция \texttt{twoModelsDialog}, код которой представлен в листинге~\ref{lst:twoModelsDialog}, симулирует диалог между двумя моделями N-грамм. Начальное слово или пару слов задаёт пользователь, затем модели по очереди генерируют ответы, основываясь на словах, из которых состоит последнее сообщение их собеседника. Функция \texttt{twoModelsDialog} принимает на вход два словаря N-грамм, строку с пользовательским вводом, в котором содержится стартовая N-грамма, и число -- наибольшее количество сообщений от каждой модели.
|
||||
|
||||
Внутри \texttt{twoModelsDialog} используются две вспомогательные функции:
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{findKeyForResponse} -- ищет в ответе собеседника слово, на которое модель способна дать ответ. Принимает на вход словарь N-грамм и список строк -- предложение с ответом собеседника. Возвращает строку с подходящим словом, если его удалось найти. Поиск слов идёт с конца предложения собеседника.
|
||||
\item \texttt{dialogStep} -- генерирует ответ с помощью функции \texttt{generatePhrase} на основе слова из предложения собеседника, найденного с помощью \texttt{findKeyForResponse}. Принимает на вход словарь N-грамм и список N-грамм -- предложение собеседника. Если удалось сгенерировать ответ, то возвращает его в виде списка N-грамм.
|
||||
\end{itemize}
|
||||
|
||||
\begin{lstlisting}[caption={Функция twoModelsDialog для организации диалога между двумя моделями}, label={lst:twoModelsDialog}]
|
||||
twoModelsDialog :: Map String [String] -> Map String [String] -> String -> Int -> IO ()
|
||||
@@ -473,22 +490,141 @@ twoModelsDialog dict1 dict2 start m =
|
||||
dialogStep d1 resp >>= \resp2 ->
|
||||
if null resp2 then return () else
|
||||
loop d1 d2 resp2 (i-1)
|
||||
|
||||
findKeyForResponse :: Map String [String] -> [String] -> Maybe String
|
||||
findKeyForResponse dict ws =
|
||||
case dropWhile (\w -> Map.notMember w dict) (reverse ws) of
|
||||
[] -> Nothing
|
||||
(x:_) -> Just x
|
||||
|
||||
dialogStep :: Map String [String] -> [String] -> IO [String]
|
||||
dialogStep dict prevPhrase =
|
||||
case findKeyForResponse dict (words $ unwords prevPhrase) of
|
||||
Nothing -> putStrLn "Нет в словаре" >> return []
|
||||
Just key ->
|
||||
newStdGen >>= \gen ->
|
||||
let p = generatePhrase dict key gen
|
||||
in putStrLn ("(" ++ key ++ ") " ++ unwords p) >> return p
|
||||
\end{lstlisting}
|
||||
|
||||
Данный подход позволяет динамически генерировать фразы и организовывать имитацию диалога между двумя текстовыми моделями, что служит демонстрацией возможностей построенной системы N-грамм.
|
||||
\subsubsection{Функция Main}
|
||||
Код функции \texttt{main} представлен в листинге~\ref{lst:main2}.
|
||||
Функция \texttt{main} обрабатывает пользовательский ввод и с помощью функций \texttt{splitText} и \texttt{buildDictionary} строит две модели N-грамм на файлах указанных пользователем. Предлагает пользователю ввести слово или пару слов, на которые потом генерируется ответ с помощью функции \texttt{processInput}. Также запускает диалог между созданными моделями N-грамм с помощью функции \texttt{twoModelsDialog}. Словари с N-граммами моделей сохраняются в файлы \texttt{dict.txt} и \texttt{dict2.txt} с помощью функции \texttt{saveDictionary}.
|
||||
|
||||
\begin{lstlisting}[caption={Код функции main}, label={lst:main2}]
|
||||
main :: IO ()
|
||||
main =
|
||||
putStrLn "Введите имя файла:" >>
|
||||
getLine >>= \fileName ->
|
||||
readFile fileName >>= \content ->
|
||||
let sentences = splitText content in
|
||||
let dict = buildDictionary sentences in
|
||||
saveDictionary "dict.txt" dict >>
|
||||
putStrLn "Введите слово или пару слов для генерации фразы:" >>
|
||||
getLine >>= \input ->
|
||||
processInput dict input >>
|
||||
|
||||
putStrLn "Введите имя второго файла:" >>
|
||||
getLine >>= \fileName2 ->
|
||||
readFile fileName2 >>= \content2 ->
|
||||
let dict2 = buildDictionary (splitText content2) in
|
||||
saveDictionary "dict2.txt" dict2 >>
|
||||
putStrLn "Введите начальное слово или пару слов для старта диалога:" >>
|
||||
getLine >>= \input2 ->
|
||||
putStrLn "Введите количество сообщений от каждой модели:" >>
|
||||
getLine >>= \ms ->
|
||||
let m = read ms :: Int in
|
||||
twoModelsDialog dict dict2 input2 m
|
||||
\end{lstlisting}
|
||||
|
||||
|
||||
|
||||
\newpage
|
||||
\section {Результаты работы программы}
|
||||
\subsection{Часть 1: Синтаксический анализ арифметических выражений}
|
||||
Результаты работы программы представлены на Рис.~\ref{fig:result1}. Программа предлагает пользователю ввести название файла, а затем выводит в консоль результаты разбора.
|
||||
|
||||
|
||||
Если какую-то строку разобрать невозможно, то программа выведет ошибку, последующие строки анализироваться не будут. Пример такого сценария показан на Рис.~\ref{fig:bad_result1}. Программа также выводит в консоль строку, которую не удалось разобрать.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=0.25\linewidth]{img/result1.png}
|
||||
\caption{Результат успешного разбора арифметических выражений.}
|
||||
\label{fig:result1}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=1\linewidth]{img/bad_result1.png}
|
||||
\caption{Результат неудачного разбора арифметических выражений.}
|
||||
\label{fig:bad_result1}
|
||||
\end{figure}
|
||||
|
||||
Пример содержимого файла \texttt{expressions.txt} представлен ниже:
|
||||
\begin{verbatim}
|
||||
100 * 100
|
||||
40 + 30
|
||||
50 / 2
|
||||
5 / 2
|
||||
62 - 32
|
||||
78 - 500
|
||||
\end{verbatim}
|
||||
|
||||
\subsection{Часть 2: Синтаксический анализ текста и генерация фраз}
|
||||
Результаты работы программы представлены на Рис.~\ref{fig:result2}. Программа предлагает пользователю ввести имя файла с текстом, а потом слово или пару слов, на основе которой генерируется и выводится ответ. Затем пользователю предлагается ввести имя ещё одного файла с текстом, задать начальное слово и размер диалога. После чего выводится диалог между полученными моделями, в скобках указано слово, с которого модель начала генерацию предложения.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=1\linewidth]{img/result2.png}
|
||||
\caption{Результаты работы программы для синтаксического анализа текста и генерации фраз.}
|
||||
\label{fig:result2}
|
||||
\end{figure}
|
||||
|
||||
Если заданного слова нет в словаре, то программа выводит сообщение об этом. По этой же причине диалог между моделями может прерваться преждевременно, о чём также будет сообщено пользователю. Пример такого сценария показан на Рис.~\ref{fig:bad_result2}.
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=1\linewidth]{img/bad_result2.png}
|
||||
\caption{Пример ситуации, в которой модель не может сгенерировать продолжение текста.}
|
||||
\label{fig:bad_result2}
|
||||
\end{figure}
|
||||
|
||||
Файлы \texttt{text1.txt} и \texttt{text2.txt} содержат произведения Антона Павловича Чехова -- <<Человек в футляре>> и <<Каштанка>>. В первом тексте содержится 4146 слов, а во втором -- 5963. Первый абзац текста из файла \texttt{text1.txt} представлен ниже:
|
||||
\begin{verbatim}
|
||||
На самом краю села Мироносицкого, в сарае старосты Прокофия расположились
|
||||
на ночлег запоздавшие охотники. Их было только двое: ветеринарный врач
|
||||
Иван Иваныч и учитель гимназии Буркин. У Ивана Иваныча была довольно
|
||||
странная, двойная фамилия - Чимша-Гималайский, которая совсем не шла ему,
|
||||
и его во всей губернии звали просто по имени и отчеству; он жил около
|
||||
города на конском заводе и приехал теперь на охоту, чтобы подышать чистым
|
||||
воздухом. Учитель же гимназии Буркин каждое лето гостил у графов П. и в
|
||||
этой местности давно уже был своим человеком.
|
||||
\end{verbatim}
|
||||
|
||||
Программа сохраняет словари N-грамм в файлы \texttt{dict1.txt} и \texttt{dict2.txt}. В результате запуска программы на текстах, описанных выше, файл \texttt{dict1.txt} содержит 4511 строк, а файл \texttt{dict2.txt} -- 6250. Каждая строка файла представляет собой ключ и значение из словаря. Ключ это одна из N-грамм, а значение это список N-грамм, которые являются возможными продолжениями текста. Первые десять строк содержимого файла \texttt{dict1.txt} представлены ниже:
|
||||
\begin{verbatim}
|
||||
"а в": ["последние"]
|
||||
"а варенька": ["поет"]
|
||||
"а возле": ["бродит"]
|
||||
"а вот": ["подчинились"]
|
||||
"а вы": ["оставайтесь"]
|
||||
"а главное": ["это"]
|
||||
"а держал": ["повара"]
|
||||
"а дома": ["как"]
|
||||
"а на": ["педагогических","хуторе"]
|
||||
"а он": ["зеленый","только"]
|
||||
\end{verbatim}
|
||||
|
||||
\newpage
|
||||
\section*{Заключение}
|
||||
\addcontentsline{toc}{section}{Заключение}
|
||||
|
||||
В рамках курсовой работы были разработаны и реализованы два \texttt{stack} проекта на языке Haskell, соответствующих поставленным задачам.
|
||||
|
||||
Первый проект представляет собой синтаксический анализатор для обработки строк, содержащих целые числа и бинарные операции. Реализация включала чтение данных из файла, синтаксический разбор выражений и вычисление их результатов. Код проекта состоит из 115 строк.
|
||||
|
||||
Второй проект — синтаксический анализатор текста и генератор продолжения текста, основанный на модели N-грамм. Проект, содержащий 139 строк кода, включает функционал по синтаксическому разбору текста, удалению пунктуации и цифр, построению словаря биграмм и триграмм, генерации текста, а также ведению диалога между моделями, созданными на основе двух разных текстов. Для демонстрации работы программы были взяты два произведения А. П. Чехова: «Человек в футляре» (4146 слов) и «Каштанка» (5963 слова).
|
||||
|
||||
В ходе работы были выполнены все поставленные задачи, а полученные знания могут быть использованы в других проектах на языке Haskell.
|
||||
|
||||
|
||||
\newpage
|
||||
@@ -497,7 +633,7 @@ twoModelsDialog dict1 dict2 start m =
|
||||
|
||||
\vspace{-1.5cm}
|
||||
\begin{thebibliography}{0}
|
||||
\bibitem{JuicyPixels}
|
||||
\bibitem{unescaping-print}
|
||||
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}
|
||||
Reference in New Issue
Block a user