Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| de4bfa4f84 | |||
| 25a5646093 | |||
| 9e3e5cda0c | |||
| a3061e6678 | |||
| f05a39da06 | |||
| 7ccdb8346e | |||
| 1aa359b5c1 | |||
| 69e7f5537a | |||
| 2ad9d5d784 | |||
| 9f7e34f7cd | |||
| ddabccfd2b | |||
| bfa7c918b2 | |||
| b816f9f17c | |||
| d8db6809e4 | |||
| 09b722a8eb | |||
| 66279d0ff4 |
@@ -22,6 +22,8 @@ main = do
|
||||
|
||||
let sourceTextPath = "resources/biography.txt"
|
||||
let sourceImagePath = "resources/david.bmp"
|
||||
let alphabetPath = "tmp/alphabet.txt"
|
||||
let encryptedTextPath = "tmp/biography_encrypted.txt"
|
||||
let encodedImagePath = "tmp/david_" ++ show bitsPerByte ++ "_" ++ show caesarShift ++ ".bmp"
|
||||
let decodedTextPath = "tmp/biography.txt"
|
||||
|
||||
@@ -32,8 +34,12 @@ main = do
|
||||
putStrLn "\nШифрование текста"
|
||||
let alphabet = createAlphabetFromText inputText
|
||||
putStrLn $ "Размер алфавита: " ++ show (length alphabet)
|
||||
writeFile alphabetPath alphabet
|
||||
putStrLn $ "Алфавит сохранён в файл \"" ++ alphabetPath ++ "\""
|
||||
let encryptedText = encryptCaesar alphabet caesarShift inputText
|
||||
putStrLn $ "10 символов шифра: \"" ++ take 10 encryptedText ++ "\""
|
||||
writeFile encryptedTextPath encryptedText
|
||||
putStrLn $ "Зашифрованный текст сохранён в файл \"" ++ encryptedTextPath ++ "\""
|
||||
let encryptedTextBits = textToBits encryptedText
|
||||
putStrLn $ "10 битов шифра: \"" ++ show (take 10 $ VU.toList encryptedTextBits) ++ "\""
|
||||
|
||||
@@ -52,6 +58,8 @@ main = do
|
||||
saveBmpImage encodedImagePath (ImageRGB8 resultImage)
|
||||
putStrLn $ "Изображение сохранено по пути: \"" ++ encodedImagePath ++ "\""
|
||||
|
||||
putStrLn $ "\nЧтение алфавита из файла \"" ++ alphabetPath ++ "\""
|
||||
alphabetFromFile <- readFile alphabetPath
|
||||
|
||||
putStrLn "\nДекодирование текста из изображения"
|
||||
case extractShift encodedImagePath of
|
||||
@@ -67,7 +75,7 @@ main = do
|
||||
putStrLn $ "10 битов шифра: \"" ++ show (take 10 $ VU.toList bits) ++ "\""
|
||||
let encryptedTextFromImage = takeWhile (/= '\NUL') (bitsToText bits)
|
||||
putStrLn $ "10 символов шифра: \"" ++ take 10 encryptedTextFromImage ++ "\""
|
||||
let decryptedText = decryptCaesar alphabet extractedCaesarShift encryptedTextFromImage
|
||||
let decryptedText = decryptCaesar alphabetFromFile extractedCaesarShift encryptedTextFromImage
|
||||
putStrLn $ "10 символов текста: \"" ++ take 10 decryptedText ++ "\""
|
||||
writeFile decodedTextPath decryptedText
|
||||
putStrLn $ "Текст сохранён по пути: \"" ++ decodedTextPath ++ "\""
|
||||
|
||||
BIN
lab3/report/img/david_2_20.jpg
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
lab3/report/img/david_3_20.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
lab3/report/img/david_5_20.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
lab3/report/img/david_6_20.jpg
Normal file
|
After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 38 KiB |
@@ -210,7 +210,7 @@
|
||||
|
||||
\subsection{Кодирование и декодирование текста с помощью шифра Цезаря}
|
||||
|
||||
Код функций для кодирования и декодирования текста с помощью шифра Цезаря представлен в листинге~\ref{lst:encrypt-caesar}. Функция \texttt{encryptCaesar} принимает алфавит в виде списка символов, смещение и сам текст, а возвращает зашифрованный текст. В её коде используется вспомогательная функция \texttt{indexOf}. Функция принимает список и элемент списка, а возвращает индекс этого элемента. Для создания алфавита используется функция \texttt{createAlphabetFromText}. Она принимает текст, а возвращает алфавит, который в нём используется, в виде списка символов. Для декодирования текста используется функция \texttt{decryptCaesar}, которая, по-сути, является лишь обёрткой над функцией \texttt{encryptCaesar}, так как процесс кодирования осуществляется почти так же как и декодирования. Функция \texttt{decryptCaesar} принимает на вход алфавит, смещение и закодированный текст, а возвращает декодированный текст.
|
||||
Код функций для кодирования и декодирования текста с помощью шифра Цезаря представлен в листинге~\ref{lst:encrypt-caesar}. Функция \texttt{encryptCaesar} принимает алфавит в виде списка символов, смещение и сам текст, а возвращает зашифрованный текст. В её коде используется вспомогательная функция \texttt{indexOf}. Функция принимает список и элемент списка, а возвращает индекс этого элемента. Для создания алфавита используется функция \texttt{createAlphabetFromText}. Она принимает текст, а возвращает алфавит, который в нём используется, в виде списка символов. Для декодирования текста используется функция \texttt{decryptCaesar}, которая, по-сути, является лишь обёрткой над функцией \texttt{encryptCaesar}, так как процесс кодирования осуществляется почти так же как и декодирования. Функция \texttt{decryptCaesar} принимает на вход алфавит, смещение и закодированный текст, а возвращает декодированный текст. Алфавит сохраняется в отдельный файл и должен передаваться вместе с зашифрованным текстом, чтобы этот текст можно было дешифровать.
|
||||
|
||||
\begin{lstlisting}[caption={Функции для кодирования и декодирования текста с помощью шифра Цезаря.}, label={lst:encrypt-caesar}]
|
||||
encryptCaesar :: [Char] -> Int -> String -> String
|
||||
@@ -239,6 +239,31 @@ decryptCaesar alphabet shift =
|
||||
alphabetLength = length alphabet
|
||||
\end{lstlisting}
|
||||
|
||||
Пример закодированного с помощью шифра Цезаря текста биографии Дэвида Дойча для смещения 5 представлен ниже.
|
||||
|
||||
\noindent
|
||||
\texttt{
|
||||
uiHF rWtFaga.ruabYgo;r3qkrNuCLS59Grcm.lrDwrvinrDJRBTrFgrirM.FYFg;rs;ngFo\\
|
||||
FgYriYrY;arAlFHa.gFYnrmerCdem. Ur9arFgrirHFgFYFlhrs.meaggm.rFlrY;aruasi.\\
|
||||
YQalYrmerIYmQForil r)iga.r8;ngFogriYrY;ar5alY.arem.r(bilYbQr5mQsbYiYFmlr\\
|
||||
N5(5TrFlrY;ar5ti.al mlr)icm.iYm.nrmerY;arAlFHa.gFYnrmerCdem. Ur9arsFmlaa\\
|
||||
.a rY;areFat rmerpbilYbQromQsbYiYFmlrcnrem.QbtiYFlhrir ago.FsYFmlrem.rir\\
|
||||
pbilYbQrSb.FlhrQio;Flayrigr,attrigrgsaoFenFlhrilrithm.FY;Qr agFhla rYmr.\\
|
||||
blrmlrirpbilYbQromQsbYa.Ur9arFgrirs.msmlalYrmerY;arQiln,m.t grFlYa.s.aYi\\
|
||||
YFmlrmerpbilYbQrQao;ilFogU1uabYgo;r,igrcm.lrYmrirxa,Fg;reiQFtnrFlr9iFeiy\\
|
||||
r-g.iatrmlrDwrvinrDJRByrY;argmlrmerCg2i.ril rSF2HiruabYgo;Ur-lr)ml mlyru\\
|
||||
iHF riYYal a rEalaHir9mbgargo;mmtrFlr5.Fo2ta,mm rN;Fgrsi.alYgrm,la ril r\\
|
||||
.ilrY;arItQir.agYib.ilYrmlr5.Fo2ta,mm rM.mi ,inTyremttm,a rcnrPFttFiQrWt\\
|
||||
tFgrko;mmtrFlr9Fh;hiYarcaem.ar.ai FlhrOiYb.itrkoFaloagriYr5ti.ar5mttahay\\
|
||||
r5iQc.F haril rYi2Flhr8i.Yr---rmerY;arviY;aQiYFoitrS.FsmgUr9ar,alYrmlrYm\\
|
||||
rPmtegmlr5mttahayrCdem. rem.r;Fgr moYm.iYarFlrY;am.aYFoitrs;ngFogyricmbY\\
|
||||
rpbilYbQreFat rY;am.nrFlrob.Ha rgsioaYFQayrgbsa.HFga rcnruallFgrkoFiQiri\\
|
||||
l r8;FtFsr5il atigU19Fgr,m.2rmlrpbilYbQrithm.FY;Qgrcahilr,FY;rirDJwRrsis\\
|
||||
a.yrtiYa.radsil a rFlrDJJzritmlhr,FY;rqFo;i. rxmfgiyrYmrs.m boarY;aruabY\\
|
||||
go;xmfgirithm.FY;QyrmlarmerY;areF.gYradiQstagrmerirpbilYbQrithm.FY;QrY;i\\
|
||||
YrFgradsmlalYFittnreigYa.rY;ilrilnrsmggFctar aYa.QFlFgYForotiggFoitrithm\\
|
||||
.FY;QU}
|
||||
|
||||
|
||||
\subsection{Представление текста в виде последовательности бит}
|
||||
|
||||
@@ -339,7 +364,7 @@ extractShift path =
|
||||
|
||||
\newpage
|
||||
\section {Результаты работы программы}
|
||||
При успешном завершении программа создаёт два файла: файл изображения с закодированных текстом и текстовый файл с декодированным текстом.
|
||||
При успешном завершении программа создаёт четыре файла: файл изображения с закодированных текстом, текстовый файл с закодированным текстом, текстовый файл с алфавитом и текстовый файл с декодированным текстом.
|
||||
|
||||
\begin{figure}[h]
|
||||
\centering
|
||||
@@ -352,32 +377,64 @@ extractShift path =
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=0.3\linewidth]{img/david_1_20.jpg}
|
||||
\includegraphics[width=0.33\linewidth]{img/david_1_20.jpg}
|
||||
\caption{Изображение с зашифрованными данными (1 бит).}
|
||||
\label{fig:david1}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=0.3\linewidth]{img/david_4_20.jpg}
|
||||
\includegraphics[width=0.33\linewidth]{img/david_2_20.jpg}
|
||||
\caption{Изображение с зашифрованными данными (2 бит).}
|
||||
\label{fig:david2}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=0.33\linewidth]{img/david_3_20.jpg}
|
||||
\caption{Изображение с зашифрованными данными (3 бит).}
|
||||
\label{fig:david3}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=0.33\linewidth]{img/david_4_20.jpg}
|
||||
\caption{Изображение с зашифрованными данными (4 бит).}
|
||||
\label{fig:david4}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=0.3\linewidth]{img/david_7_20.jpg}
|
||||
\includegraphics[width=0.33\linewidth]{img/david_5_20.jpg}
|
||||
\caption{Изображение с зашифрованными данными (5 бит).}
|
||||
\label{fig:david5}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=0.33\linewidth]{img/david_6_20.jpg}
|
||||
\caption{Изображение с зашифрованными данными (6 бит).}
|
||||
\label{fig:david6}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=0.33\linewidth]{img/david_7_20.jpg}
|
||||
\caption{Изображение с зашифрованными данными (7 бит).}
|
||||
\label{fig:david7}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[h!]
|
||||
\centering
|
||||
\includegraphics[width=0.3\linewidth]{img/david_8_20.jpg}
|
||||
\includegraphics[width=0.33\linewidth]{img/david_8_20.jpg}
|
||||
\caption{Изображение с зашифрованными данными (8 бит).}
|
||||
\label{fig:david8}
|
||||
\end{figure}
|
||||
|
||||
\newpage
|
||||
\phantom{text}
|
||||
\newpage
|
||||
\phantom{text}
|
||||
\newpage
|
||||
На Рис.~\ref{fig:david1}-\ref{fig:david8} представлены результирующие изображения с разным количеством бит, отведённых под зашифрованные данные.
|
||||
|
||||
|
||||
3
lab4/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.stack-work/
|
||||
*~
|
||||
!task.txt
|
||||
11
lab4/CHANGELOG.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Changelog for `lab4`
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to the
|
||||
[Haskell Package Versioning Policy](https://pvp.haskell.org/).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 0.1.0.0 - YYYY-MM-DD
|
||||
26
lab4/LICENSE
Normal file
@@ -0,0 +1,26 @@
|
||||
Copyright 2024 Author name here
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
1
lab4/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# lab4
|
||||
2
lab4/Setup.hs
Normal file
@@ -0,0 +1,2 @@
|
||||
import Distribution.Simple
|
||||
main = defaultMain
|
||||
14
lab4/app/Main.hs
Normal file
@@ -0,0 +1,14 @@
|
||||
module Main (main) where
|
||||
|
||||
import Lib
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
putStrLn $ "Примеры работы `isCongruent`"
|
||||
putStrLn $ "isCongruent 10 12 2: " ++ show (isCongruent 10 12 2)
|
||||
putStrLn $ "isCongruent 10 11 2: " ++ show (isCongruent 10 11 2)
|
||||
|
||||
putStrLn $ "\nПример работы `filterByPredicate`"
|
||||
let predicate x = x > 5
|
||||
putStrLn $ "filterByPredicate (>5) [1, 6, 3, 7, 2]: "
|
||||
++ show (filterByPredicate predicate [1 :: Int, 6, 3, 7, 2])
|
||||
68
lab4/lab4.cabal
Normal file
@@ -0,0 +1,68 @@
|
||||
cabal-version: 2.2
|
||||
|
||||
-- This file has been generated from package.yaml by hpack version 0.37.0.
|
||||
--
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
name: lab4
|
||||
version: 0.1.0.0
|
||||
description: Please see the README on GitHub at <https://github.com/githubuser/lab4#readme>
|
||||
homepage: https://github.com/githubuser/lab4#readme
|
||||
bug-reports: https://github.com/githubuser/lab4/issues
|
||||
author: Author name here
|
||||
maintainer: example@example.com
|
||||
copyright: 2024 Author name here
|
||||
license: BSD-3-Clause
|
||||
license-file: LICENSE
|
||||
build-type: Simple
|
||||
extra-source-files:
|
||||
README.md
|
||||
CHANGELOG.md
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://github.com/githubuser/lab4
|
||||
|
||||
library
|
||||
exposed-modules:
|
||||
Lib
|
||||
other-modules:
|
||||
Paths_lab4
|
||||
autogen-modules:
|
||||
Paths_lab4
|
||||
hs-source-dirs:
|
||||
src
|
||||
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints
|
||||
build-depends:
|
||||
base >=4.7 && <5
|
||||
default-language: Haskell2010
|
||||
|
||||
executable lab4-exe
|
||||
main-is: Main.hs
|
||||
other-modules:
|
||||
Paths_lab4
|
||||
autogen-modules:
|
||||
Paths_lab4
|
||||
hs-source-dirs:
|
||||
app
|
||||
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends:
|
||||
base >=4.7 && <5
|
||||
, lab4
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite lab4-test
|
||||
type: exitcode-stdio-1.0
|
||||
main-is: Spec.hs
|
||||
other-modules:
|
||||
Paths_lab4
|
||||
autogen-modules:
|
||||
Paths_lab4
|
||||
hs-source-dirs:
|
||||
test
|
||||
ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends:
|
||||
QuickCheck
|
||||
, base >=4.7 && <5
|
||||
, lab4
|
||||
default-language: Haskell2010
|
||||
60
lab4/package.yaml
Normal file
@@ -0,0 +1,60 @@
|
||||
name: lab4
|
||||
version: 0.1.0.0
|
||||
github: "githubuser/lab4"
|
||||
license: BSD-3-Clause
|
||||
author: "Author name here"
|
||||
maintainer: "example@example.com"
|
||||
copyright: "2024 Author name here"
|
||||
|
||||
extra-source-files:
|
||||
- README.md
|
||||
- CHANGELOG.md
|
||||
|
||||
# Metadata used when publishing your package
|
||||
# synopsis: Short description of your package
|
||||
# category: Web
|
||||
|
||||
# To avoid duplicated efforts in documentation and dealing with the
|
||||
# complications of embedding Haddock markup inside cabal files, it is
|
||||
# common to point users to the README.md file.
|
||||
description: Please see the README on GitHub at <https://github.com/githubuser/lab4#readme>
|
||||
|
||||
dependencies:
|
||||
- base >= 4.7 && < 5
|
||||
|
||||
ghc-options:
|
||||
- -Wall
|
||||
- -Wcompat
|
||||
- -Widentities
|
||||
- -Wincomplete-record-updates
|
||||
- -Wincomplete-uni-patterns
|
||||
- -Wmissing-export-lists
|
||||
- -Wmissing-home-modules
|
||||
- -Wpartial-fields
|
||||
- -Wredundant-constraints
|
||||
|
||||
library:
|
||||
source-dirs: src
|
||||
|
||||
executables:
|
||||
lab4-exe:
|
||||
main: Main.hs
|
||||
source-dirs: app
|
||||
ghc-options:
|
||||
- -threaded
|
||||
- -rtsopts
|
||||
- -with-rtsopts=-N
|
||||
dependencies:
|
||||
- lab4
|
||||
|
||||
tests:
|
||||
lab4-test:
|
||||
main: Spec.hs
|
||||
source-dirs: test
|
||||
ghc-options:
|
||||
- -threaded
|
||||
- -rtsopts
|
||||
- -with-rtsopts=-N
|
||||
dependencies:
|
||||
- lab4
|
||||
- QuickCheck
|
||||
5
lab4/report/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
**/*
|
||||
!.gitignore
|
||||
!report.tex
|
||||
!img
|
||||
!img/*
|
||||
BIN
lab4/report/img/main.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
lab4/report/img/test.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
320
lab4/report/report.tex
Normal file
@@ -0,0 +1,320 @@
|
||||
\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{Вариант 20}\\
|
||||
\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}
|
||||
|
||||
|
||||
\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}
|
||||
16
lab4/src/Lib.hs
Normal file
@@ -0,0 +1,16 @@
|
||||
module Lib
|
||||
( isCongruent,
|
||||
filterByPredicate
|
||||
) where
|
||||
|
||||
isCongruent :: Int -> Int -> Int -> Bool
|
||||
isCongruent a b d = a `mod` d + 1 == b `mod` d
|
||||
|
||||
|
||||
filterByPredicate :: (a -> Bool) -> [a] -> [a]
|
||||
filterByPredicate _ [] = []
|
||||
filterByPredicate predicate (x:xs)
|
||||
| predicate x = x : filteredTail
|
||||
| otherwise = filteredTail
|
||||
where
|
||||
filteredTail = filterByPredicate predicate xs
|
||||
67
lab4/stack.yaml
Normal file
@@ -0,0 +1,67 @@
|
||||
# This file was automatically generated by 'stack init'
|
||||
#
|
||||
# Some commonly used options have been documented as comments in this file.
|
||||
# For advanced use and comprehensive documentation of the format, please see:
|
||||
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||
|
||||
# A 'specific' Stackage snapshot or a compiler version.
|
||||
# A snapshot resolver dictates the compiler version and the set of packages
|
||||
# to be used for project dependencies. For example:
|
||||
#
|
||||
# snapshot: lts-22.28
|
||||
# snapshot: nightly-2024-07-05
|
||||
# snapshot: ghc-9.6.6
|
||||
#
|
||||
# The location of a snapshot can be provided as a file or url. Stack assumes
|
||||
# a snapshot provided as a file might change, whereas a url resource does not.
|
||||
#
|
||||
# snapshot: ./custom-snapshot.yaml
|
||||
# snapshot: https://example.com/snapshots/2024-01-01.yaml
|
||||
snapshot:
|
||||
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml
|
||||
|
||||
# User packages to be built.
|
||||
# Various formats can be used as shown in the example below.
|
||||
#
|
||||
# packages:
|
||||
# - some-directory
|
||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
# subdirs:
|
||||
# - auto-update
|
||||
# - wai
|
||||
packages:
|
||||
- .
|
||||
# Dependency packages to be pulled from upstream that are not in the snapshot.
|
||||
# These entries can reference officially published versions as well as
|
||||
# forks / in-progress versions pinned to a git hash. For example:
|
||||
#
|
||||
# extra-deps:
|
||||
# - acme-missiles-0.3
|
||||
# - git: https://github.com/commercialhaskell/stack.git
|
||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
#
|
||||
# extra-deps: []
|
||||
|
||||
# Override default flag values for project packages and extra-deps
|
||||
# flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
# extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
#
|
||||
# Require a specific version of Stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: ">=3.1"
|
||||
#
|
||||
# Override the architecture used by Stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
#
|
||||
# Extra directories used by Stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
||||
#
|
||||
# Allow a newer minor version of GHC than the snapshot specifies
|
||||
# compiler-check: newer-minor
|
||||
13
lab4/stack.yaml.lock
Normal file
@@ -0,0 +1,13 @@
|
||||
# This file was autogenerated by Stack.
|
||||
# You should not edit this file by hand.
|
||||
# For more information, please see the documentation at:
|
||||
# https://docs.haskellstack.org/en/stable/lock_files
|
||||
|
||||
packages: []
|
||||
snapshots:
|
||||
- completed:
|
||||
sha256: 08bd13ce621b41a8f5e51456b38d5b46d7783ce114a50ab604d6bbab0d002146
|
||||
size: 720271
|
||||
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml
|
||||
original:
|
||||
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml
|
||||
BIN
lab4/task.jpg
Normal file
|
After Width: | Height: | Size: 162 KiB |
19
lab4/task.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
Практическое задание 4. Тестирование в Haskell
|
||||
№ 12
|
||||
|
||||
Создать проект в stack. Функции записать в библиотеку Lib.hs и ограничить доступ к вспомогательным функциям. Тесты записать в Spec.hs.
|
||||
|
||||
Функция 1: Напишите функцию проверки равенства по модулю isCongruent :: Int -> Int -> Int -> Bool, которая проверяет, равны ли два числа по модулю третьего числа. Используя QuickCheck, проверьте следующие свойства:
|
||||
|
||||
1. Если два числа равны по модулю, то их разность делится на модуль:
|
||||
isCongruent a b m == (modulus (a - b) m == 0).
|
||||
2. Равенство по модулю является симметричным:
|
||||
isCongruent a b m == isCongruent b a m.
|
||||
3. Если одно число равно другому, то они равны по любому модулю:
|
||||
если a == b, то isCongruent a b m == True.
|
||||
|
||||
Функция 2: Напишите функцию filterByPredicate :: (a -> Bool) -> [a] -> [a], которая фильтрует элементы списка по заданному предикату. Используя QuickCheck, проверьте следующие свойства:
|
||||
|
||||
1. Все элементы результата удовлетворяют предикату: для каждого элемента x из результата должно выполняться условие: predicate x == True.
|
||||
2. Длина результата не превышает длину исходного списка: length (filterByPredicate predicate xs) <= length xs.
|
||||
3. Если предикат всегда возвращает True, то результат совпадает с исходным списком: если predicate x == True для всех x, то filterByPredicate predicate xs == xs.
|
||||
37
lab4/test/Spec.hs
Normal file
@@ -0,0 +1,37 @@
|
||||
import Test.QuickCheck
|
||||
import Lib
|
||||
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
quickCheck propCongruentDifference
|
||||
quickCheck propCongruentSymmetric
|
||||
quickCheck propCongruentEqualNumbers
|
||||
|
||||
quickCheck propFilterByPredicateSatisfiesPredicate
|
||||
quickCheck propFilterByPredicateLength
|
||||
quickCheck propFilterByPredicateAlwaysTrue
|
||||