Files

341 lines
19 KiB
TeX
Raw Permalink 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{Отчет по лабораторной работе №4}\\
\large{по дисциплине}\\
\large{<<Функциональное программирование>>}\\
\large{Вариант 12}\\
\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 {Постановка задачи}
Для выполнения лабораторной работы необходимо было сделать следующее. Создать проект в \texttt{stack}. Функции записать в библиотеку \texttt{Lib.hs} и ограничить доступ к вспомогательным функциям. Тесты записать в \texttt{Spec.hs}.
\textbf{Функция 1:} Напишите функцию проверки равенства по модулю \texttt{isCongruent :: Int -> Int -> Int -> Bool}, которая проверяет, равны ли два числа по модулю третьего числа. Используя \texttt{QuickCheck}, проверьте следующие свойства:
\begin{enumerate}
\item Если два числа равны по модулю, то их разность делится на модуль:
\texttt{isCongruent a b m == (modulus (a - b) m == 0)}.
\item Равенство по модулю является симметричным:
\texttt{isCongruent a b m == isCongruent b a m}.
\item Если одно число равно другому, то они равны по любому модулю:
если \texttt{a == b}, то \texttt{isCongruent a b m == True}.
\end{enumerate}
\textbf{Функция 2:} Напишите функцию \texttt{filterByPredicate :: (a -> Bool) -> [a] -> [a]}, которая фильтрует элементы списка по заданному предикату. Используя \texttt{QuickCheck}, проверьте следующие свойства:
\begin{enumerate}
\item Все элементы результата удовлетворяют предикату: для каждого элемента \texttt{x} из результата должно выполняться условие: \texttt{predicate x == True}.
\item Длина результата не превышает длину исходного списка:
\texttt{length (filterByPredicate predicate xs) <= length xs}.
\item Если предикат всегда возвращает \texttt{True}, то результат совпадает с исходным списком:
если \texttt{predicate x == True} для всех \texttt{x}, то \texttt{filterByPredicate predicate xs == xs}.
\end{enumerate}
\newpage
\section {Особенности реализации}
\subsection{Функция isCongruent}
Код функции для проверки числовой конгруэнтности представлен в листинге~\ref{lst:is-congruent}. Функция \texttt{isCongruent} принимает три числа: \texttt{a}, \texttt{b} и \texttt{d}. Она возвращает \texttt{True}, если остатки от деления \texttt{a} и \texttt{b} на \texttt{d} равны, и \texttt{False} в противном случае.
\begin{lstlisting}[caption={Функция для проверки числовой конгруэнтности.}, label={lst:is-congruent}]
isCongruent :: Int -> Int -> Int -> Bool
isCongruent a b d = a `mod` d == b `mod` d
\end{lstlisting}
\subsection{Функция filterByPredicate}
Код функции для фильтрации элементов списка на основе предиката представлен в листинге~\ref{lst:filter-by-predicate}. Функция \texttt{filterByPredicate} принимает предикат (\texttt{predicate}) и список (\texttt{[a]}). Она возвращает новый список, содержащий только те элементы исходного списка, для которых предикат возвращает \texttt{True}.
\begin{lstlisting}[caption={Функция для фильтрации списка по предикату.}, label={lst:filter-by-predicate}]
filterByPredicate :: (a -> Bool) -> [a] -> [a]
filterByPredicate _ [] = []
filterByPredicate predicate (x:xs)
| predicate x = x : filteredTail
| otherwise = filteredTail
where
filteredTail = filterByPredicate predicate xs
\end{lstlisting}
\subsection{Тесты для функции isCongruent}
Для тестирования функции \texttt{isCongruent} использовались свойства, проверяемые с использованием библиотеки QuickCheck. Ниже приведены описания тестов, представленных в листинге~\ref{lst:congruent-tests}.
\begin{itemize}
\item \texttt{propCongruentDifference}: Проверяет, что два числа конгруэнтны по модулю \texttt{m}, если и только если разность этих чисел делится на \texttt{m} без остатка.
\item \texttt{propCongruentSymmetric}: Проверяет симметричность конгруэнтности, то есть, если \texttt{a} конгруэнтно \texttt{b}, то \texttt{b} конгруэнтно \texttt{a}.
\item \texttt{propCongruentEqualNumbers}: Проверяет, что любое число \texttt{a} всегда конгруэнтно самому себе по любому ненулевому модулю.
\end{itemize}
\begin{lstlisting}[caption={Тесты для функции \texttt{isCongruent} с использованием QuickCheck.}, label={lst:congruent-tests}]
propCongruentDifference :: Int -> Int -> Int -> Property
propCongruentDifference a b m =
m /= 0 ==> isCongruent a b m == ((a - b) `mod` m == 0)
propCongruentSymmetric :: Int -> Int -> Int -> Property
propCongruentSymmetric a b m =
m /= 0 ==> isCongruent a b m == isCongruent b a m
propCongruentEqualNumbers :: Int -> Int -> Property
propCongruentEqualNumbers a m =
m /= 0 ==> isCongruent a a m == True
\end{lstlisting}
\subsection{Тесты для функции filterByPredicate}
Для тестирования функции \texttt{filterByPredicate} использовались свойства, проверяемые с использованием библиотеки QuickCheck. Описание тестов приведено в листинге~\ref{lst:filter-tests}.
\begin{itemize}
\item \texttt{propFilterByPredicateSatisfiesPredicate}: Проверяет, что все элементы результирующего списка удовлетворяют переданному предикату.
\item \texttt{propFilterByPredicateLength}: Проверяет, что длина результирующего списка не превышает длину исходного списка.
\item \texttt{propFilterByPredicateAlwaysTrue}: Проверяет, что если предикат всегда возвращает \texttt{True}, результирующий список совпадает с исходным.
\end{itemize}
\begin{lstlisting}[caption={Тесты для функции \texttt{filterByPredicate} с использованием QuickCheck.}, label={lst:filter-tests}]
propFilterByPredicateSatisfiesPredicate :: Fun Int Bool -> [Int] -> Bool
propFilterByPredicateSatisfiesPredicate (Fun _ predicate) xs =
all predicate (filterByPredicate predicate xs)
propFilterByPredicateLength :: Fun Int Bool -> [Int] -> Bool
propFilterByPredicateLength (Fun _ predicate) xs =
length (filterByPredicate predicate xs) <= length xs
propFilterByPredicateAlwaysTrue :: [Int] -> Bool
propFilterByPredicateAlwaysTrue xs =
filterByPredicate (\_ -> True) xs == xs
\end{lstlisting}
В листинге~\ref{lst:broken1} представлена реализация функции \texttt{filterByPredicate}, которая не пройдёт ни один из перечисленных тестов. А в листинге~\ref{lst:broken2} представлена реализация, которая не пройдёт два из трёх тестов, первый и третий.
\begin{lstlisting}[caption={Пример реализации функции filterByPredicate, которая не пройдёт ни один тест.}, label={lst:broken1}]
filterByPredicate :: (a -> Bool) -> [a] -> [a]
filterByPredicate _ [] = []
filterByPredicate predicate (x:xs)
| not $ predicate x = x : x : filteredTail
| otherwise = x : x : filteredTail
where
filteredTail = filterByPredicate predicate xs
\end{lstlisting}
\begin{lstlisting}[caption={Пример реализации функции filterByPredicate, которая не пройдёт первый и третий тесты.}, label={lst:broken2}]
filterByPredicate :: (a -> Bool) -> [a] -> [a]
filterByPredicate _ [] = []
filterByPredicate predicate (x:xs)
| not $ predicate x = x : filteredTail
| otherwise = filteredTail
where
filteredTail = filterByPredicate predicate xs
\end{lstlisting}
\subsection{Запуск тестов}
Для выполнения всех тестов в проекте создан файл \texttt{Spec.hs}, в котором определена функция \texttt{main}. Она последовательно запускает все тесты, используя библиотеку \texttt{QuickCheck}. Код функции \texttt{main} приведён в листинге~\ref{lst:test-main}.
Функция \texttt{quickCheck} используется для автоматического тестирования свойств. Она генерирует случайные входные данные, проверяет выполнение свойства на каждом из них и сообщает о результатах. В случае провала теста \texttt{quickCheck} предоставляет пример данных, на которых свойство не выполняется.
Для сборки проекта и выполнения всех тестов достаточно выполнить команду \texttt{stack test}.
\begin{lstlisting}[caption={Функция \texttt{main} для запуска тестов.}, label={lst:test-main}]
main :: IO ()
main = do
quickCheck propCongruentDifference
quickCheck propCongruentSymmetric
quickCheck propCongruentEqualNumbers
quickCheck propFilterByPredicateSatisfiesPredicate
quickCheck propFilterByPredicateLength
quickCheck propFilterByPredicateAlwaysTrue
\end{lstlisting}
\newpage
\section {Результаты работы программы}
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/main.png}
\caption{Результаты работы программы.}
\label{fig:main}
\end{figure}
Сама программа лишь выводит примеры работы функций \texttt{isCongruent} и \texttt{filterByPredicate}. Результаты её запуска представлены на Рис.~\ref{fig:main}.
\begin{figure}[h!]
\centering
\includegraphics[width=0.6\linewidth]{img/test.png}
\caption{Результаты запуска тестов.}
\label{fig:test}
\end{figure}
Результаты запуска тестов с помощью команды \texttt{stack test} представлены на Рис.~\ref{fig:test}.
\newpage
\section*{Заключение}
\addcontentsline{toc}{section}{Заключение}
В данной работе был создан проект с использованием \texttt{stack}, включающий разработку и тестирование двух функций: проверки равенства по модулю и фильтрации списка по предикату. Для каждой функции были написаны три теста. Тесты запускаются на сгенерированных данных с помощью \texttt{QuickCheck}. Они подтверждают корректность реализации этих функций. В ходе выполнения лабораторной работы были получены базовые знания об автоматическом тестировании программ, написанных на языке Haskell.
\newpage
\section*{Список литературы}
\addcontentsline{toc}{section}{Список литературы}
\vspace{-1.5cm}
\begin{thebibliography}{0}
\bibitem{JuicyPixels}
Hackage -- QuickCheck: Automatic testing of Haskell programs, URL: \url{https://hackage.haskell.org/package/QuickCheck}, Дата обращения: 19.11.2024
\end{thebibliography}
\end{document}