├── Lecture1 ├── Slides.pdf └── Slides.tex ├── Lecture2 ├── Pics │ ├── Compr.png │ ├── Doge.png │ ├── HeadTail.png │ ├── Imm.png │ ├── InfixPrefix.png │ ├── ListFunctions.png │ ├── TypesScreen.png │ └── WhatToDo.jpeg ├── Slides.pdf └── Slides.tex ├── Lecture3 ├── Slides.pdf └── Slides.tex ├── Lecture4 ├── Slides.pdf ├── Slides.tex └── mlem.jpeg ├── Lecture5 ├── Slides.pdf ├── Slides.tex └── retriever.jpeg ├── Lecture6 ├── Slides.pdf ├── Slides.tex └── monads.png ├── Lecture7 ├── Seminar7.hs ├── Slides.pdf ├── Slides.tex └── puppies.png ├── Lecture8 ├── Slides.pdf └── Slides.tex ├── ParserSeminar ├── Slides.pdf └── Slides.tex ├── README.md ├── Theory ├── slides01.pdf ├── slides02.pdf ├── slides03.pdf ├── slides04.pdf ├── slides05.pdf ├── slides06.pdf ├── slides07.pdf └── src │ ├── CardinalMale2007.jpg │ ├── Common-Kestrel-3.jpg │ ├── Kestrel.jpg │ ├── Mountain_Bluebird.jpg │ ├── ezhik.jpg │ ├── slides01.tex │ ├── slides02.tex │ ├── slides03.tex │ ├── slides04.tex │ ├── slides05.tex │ ├── slides06.tex │ └── slides07.tex ├── final_exam_2021_autumn.pdf └── quiz2021_autumn.pdf /Lecture1/Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture1/Slides.pdf -------------------------------------------------------------------------------- /Lecture1/Slides.tex: -------------------------------------------------------------------------------- 1 | \documentclass[10pt]{beamer} 2 | \usepackage[outputdir=build]{minted} 3 | \usepackage[utf8x]{inputenc} 4 | \usepackage{hyperref} 5 | \usepackage{fontawesome} 6 | \usepackage{graphicx} 7 | \usepackage[english,ngerman]{babel} 8 | \usepackage{bussproofs} 9 | 10 | % ------------------------------------------------------------------------------ 11 | % Use the beautiful metropolis beamer template 12 | % ------------------------------------------------------------------------------ 13 | \usepackage[T1]{fontenc} 14 | \usepackage{fontawesome} 15 | \usepackage{FiraSans} 16 | \newtheorem{defin}{Definition} 17 | \newtheorem{theor}{Theorem} 18 | \newtheorem{prop}{Proposition} 19 | \mode 20 | { 21 | \usetheme[progressbar=foot,numbering=fraction,background=light]{metropolis} 22 | \usecolortheme{default} % or try albatross, beaver, crane, ... 23 | \usefonttheme{default} % or try serif, structurebold, ... 24 | \setbeamertemplate{navigation symbols}{} 25 | \setbeamertemplate{caption}[numbered] 26 | %\setbeamertemplate{frame footer}{My custom footer} 27 | } 28 | 29 | % ------------------------------------------------------------------------------ 30 | % beamer doesn't have texttt defined, but I usually want it anyway 31 | % ------------------------------------------------------------------------------ 32 | \let\textttorig\texttt 33 | \renewcommand<>{\texttt}[1]{% 34 | \only#2{\textttorig{#1}}% 35 | } 36 | 37 | % ------------------------------------------------------------------------------ 38 | % minted 39 | % ------------------------------------------------------------------------------ 40 | 41 | 42 | % ------------------------------------------------------------------------------ 43 | % tcolorbox / tcblisting 44 | % ------------------------------------------------------------------------------ 45 | \usepackage{xcolor} 46 | \definecolor{codecolor}{HTML}{FFC300} 47 | 48 | \usepackage{tcolorbox} 49 | \tcbuselibrary{most,listingsutf8,minted} 50 | 51 | \tcbset{tcbox width=auto,left=1mm,top=1mm,bottom=1mm, 52 | right=1mm,boxsep=1mm,middle=1pt} 53 | 54 | \newtcblisting{myr}[1]{colback=codecolor!5,colframe=codecolor!80!black,listing only, 55 | minted options={numbers=left, style=tcblatex,fontsize=\tiny,breaklines,autogobble,linenos,numbersep=3mm}, 56 | left=5mm,enhanced, 57 | title=#1, fonttitle=\bfseries, 58 | listing engine=minted,minted language=r} 59 | 60 | 61 | % ------------------------------------------------------------------------------ 62 | % Listings 63 | % ------------------------------------------------------------------------------ 64 | \definecolor{mygreen}{HTML}{37980D} 65 | \definecolor{myblue}{HTML}{0D089F} 66 | \definecolor{myred}{HTML}{98290D} 67 | 68 | \usepackage{listings} 69 | 70 | % the following is optional to configure custom highlighting 71 | \lstdefinelanguage{XML} 72 | { 73 | morestring=[b]", 74 | morecomment=[s]{}, 75 | morestring=[s]{>}{<}, 76 | morekeywords={ref,xmlns,version,type,canonicalRef,metr,real,target}% list your attributes here 77 | } 78 | 79 | \lstdefinestyle{myxml}{ 80 | language=XML, 81 | showspaces=false, 82 | showtabs=false, 83 | basicstyle=\ttfamily, 84 | columns=fullflexible, 85 | breaklines=true, 86 | showstringspaces=false, 87 | breakatwhitespace=true, 88 | escapeinside={(*@}{@*)}, 89 | basicstyle=\color{mygreen}\ttfamily,%\footnotesize, 90 | stringstyle=\color{myred}, 91 | commentstyle=\color{myblue}\upshape, 92 | keywordstyle=\color{myblue}\bfseries, 93 | } 94 | 95 | 96 | % ------------------------------------------------------------------------------ 97 | % The Document 98 | % ------------------------------------------------------------------------------ 99 | \title{Functional programming, Seminar No. 1} 100 | \author{Daniel Rogozin \\ Institute for Information Transmission Problems, RAS \\ Serokell O\"{U}} 101 | 102 | \vspace{\baselineskip} 103 | 104 | \date{Higher School of Economics \\ The Department of Computer Science} 105 | 106 | \begin{document} 107 | \maketitle 108 | 109 | \begin{frame} 110 | \frametitle{Basic intro} 111 | \begin{center} 112 | \includegraphics[scale=0.3]{Pics/samoyed.png} 113 | \end{center} 114 | \end{frame} 115 | 116 | \section{General words on Haskell and History} 117 | 118 | \begin{frame} 119 | \frametitle{Intro} 120 | 121 | \begin{itemize} 122 | \item The language is named after Haskell Curry, an American logician 123 | \item The first implementation: 1990 124 | \item The language standard: Haskell2010 125 | \item Default compiler: Glasgow Haskell compiler 126 | \item Haskell is a strongly-typed, polymorphic, and purely functional programming language 127 | \end{itemize} 128 | \end{frame} 129 | 130 | \begin{frame} 131 | \frametitle{Lambda calculus and type theory. Incomplete and Utter History of Functional Programming} 132 | 133 | \onslide<1->{ 134 | \begin{itemize} 135 | \item At the end of the 1920-s, Alonzo Church proposed an alternative approach to the foundations of mathematics where the notion of a function is a primitive one. Informally, lambda-calculus is a formal system that describes abstract functions. 136 | } 137 | \onslide<2->{ 138 | \item Moreover, Church used the lambda calculus to show that Peano arithmetic is undecidable. 139 | } 140 | \onslide<3->{ 141 | \item Kleene and Rosser showed that the initial version of the lambda calculus is inconsistent. Initially (due to Bertand Russell), the idea of typing was the instrument that would allow us to avoid paradoxes. 142 | } 143 | \onslide<4->{ 144 | \item The first system of typed the lambda calculus is a hybrid from the lambda calculus and type theory developed by Bertrand Russell and Alfred North Whitehead in Principia Mathematica (1910-s). 145 | } 146 | \end{itemize} 147 | \end{frame} 148 | 149 | \begin{frame} 150 | \frametitle{Lambda calculus and type theory. Historical notes} 151 | 152 | \onslide<1->{ 153 | \begin{itemize} 154 | \item After Church’s works, type theory as the branch of $\lambda$ calculus and combinatory logic was developed by Haskell Curry and William Howard within the context of proof theory (1950-1960-s) 155 | } 156 | \onslide<2->{ 157 | \item Polymorphic lambda calculus (John Reynolds and Jean-Yves Girard (1970-s)) 158 | } 159 | \onslide<3->{ 160 | \item Polymorphic type inference (Roger Hindley, Robin Milner and Luis Damas (1970-1980-s)) 161 | } 162 | \onslide<4->{ 163 | \item ML: the very first language with polymorphic inferred type system (Robin Milner, 1973) 164 | } 165 | \onslide<5->{ 166 | \item The language Haskell appeared at the beginning of 1990-s. Haskell desinged by Simon Peyton Jones, Philip Wadler, and others 167 | } 168 | \end{itemize} 169 | \end{frame} 170 | 171 | \begin{frame} 172 | \frametitle{Functional programming and its foundations} 173 | \onslide<1->{ 174 | The lambda calculus establishes the foundations for functional programming in the same manner as the von Neumann principles for imperative programming. 175 | } \onslide<2->{ 176 | \begin{itemize} 177 | \item We have no assignment in imperative languages. Variables are nullary constant functions rather than boxes. 178 | \item We have no states (in a usual sense) 179 | \item We use recursion instead of loops 180 | \item Pattern-matching 181 | \item ... 182 | \end{itemize} 183 | } 184 | \end{frame} 185 | 186 | \begin{frame} 187 | \frametitle{What are types needed for?} 188 | 189 | \metroset{block=fill} 190 | \begin{exampleblock}{According to Benjamin Pierce} 191 | A type system is a tractable syntactic method for proving the absence of certain program behaviours by classifying phrases according to the kinds of values they compute. 192 | \end{exampleblock} 193 | 194 | \onslide<2->{ 195 | Types in programming languages are about 196 | \begin{itemize} 197 | \item A partial specification 198 | \item Type preserving 199 | \item Type checking allows one to catch simple errors 200 | \item Type inference 201 | \item Etc 202 | \end{itemize} 203 | } 204 | \end{frame} 205 | 206 | \begin{frame} 207 | \frametitle{A landscape of typing from a bird's eye view} 208 | We may classify possible ways of typing as follows 209 | 210 | \begin{itemize} 211 | \item Static and dynamic typing 212 | \begin{itemize} 213 | \item C, C++, Java, Haskell, etc 214 | \item JavaScript, Ruby, PHP, etc 215 | \end{itemize} 216 | \item Implicit and explicit typing 217 | \begin{itemize} 218 | \item JavaScript, Ruby, PHP, etc 219 | \item C++, Java, etc 220 | \end{itemize} 221 | \item Inferred typing 222 | \begin{itemize} 223 | \item Haskell, Standard ML, Ocaml, Idris, etc 224 | \end{itemize} 225 | \end{itemize} 226 | 227 | \end{frame} 228 | 229 | \section{Ecosystem} 230 | 231 | \begin{frame} 232 | \frametitle{The Haskell Platform installation} 233 | 234 | There are several ways to install the Haskell platform on Mac (if you have M1, don't cry): 235 | 236 | \onslide<1->{ 237 | \begin{itemize} 238 | \item Download the \verb".pkg" file and install the corresponding package} 239 | \onslide<2->{\item Run the script 240 | \begin{center} 241 | \verb"curl -sSL https://get.haskellstack.org/ | sh" 242 | \end{center} 243 | } 244 | \onslide<3->{\item Install ghc, stack, and cabal using Homebrew 245 | \end{itemize} 246 | } 247 | 248 | \onslide<4->{ 249 | Choose any way you prefer. All these ways are equivalent to each other. 250 | } 251 | \vspace{\baselineskip} 252 | \end{frame} 253 | 254 | \begin{frame} 255 | \frametitle{GHC} 256 | 257 | \onslide<1->{ 258 | \begin{itemize} 259 | \item GHC is a default Haskell compiler. 260 | \item GHC is an open-source project. Don't hesitate to contribute! 261 | \item GHC is mostly implemented on Haskell. 262 | } 263 | \item GHC is developed under the GHC Steering committee control. 264 | \onslide<2->{ 265 | \item Very roughly, compiling pipeline has the following form: 266 | \begin{center} 267 | parsing $\Rightarrow$ compile-time (type-checking mostly) 268 | $\Rightarrow$ runtime (program execution) 269 | \end{center} 270 | } 271 | \end{itemize} 272 | \end{frame} 273 | 274 | \begin{frame} 275 | \frametitle{GHCi} 276 | 277 | \begin{itemize} 278 | \item GHCi is a Haskell interpreter based on GHC. 279 | \item One may run GHCi with the command \verb"ghci". 280 | \item You may play with GHCi as a calculator, arithmetic operators are usual 281 | \item You may also have a look at the GHCi chapter in the GHC User's Guide to get familiar with GHCi closer. 282 | \end{itemize} 283 | 284 | \begin{center} 285 | \includegraphics[scale=0.23]{Pics/GHCi.png} 286 | \end{center} 287 | \end{frame} 288 | 289 | \begin{frame} 290 | \frametitle{Cabal} 291 | 292 | \onslide<1->{ 293 | \begin{itemize} 294 | \item Cabal is a system of library and dependency management 295 | \item A \verb".cabal" file describes the version of a package and its dependencies 296 | \item Cabal is also a packaging tool 297 | \item Cabal used to cause dependency hell, and it still does. 298 | \end{itemize}} 299 | \end{frame} 300 | 301 | \begin{frame} 302 | \frametitle{Stack} 303 | 304 | \onslide<1->{ 305 | \begin{itemize} 306 | \item Stack is a \emph{mainstream} cross-platform build tool for Haskell projects 307 | \item Stack is about 308 | } 309 | \onslide<2->{ 310 | \begin{itemize} 311 | \item installation of required packages and the latest GHC (and their more concrete versions), 312 | \item building, execution, and testing 313 | \item creating an isolated location. 314 | \item Builds are reproducible 315 | \end{itemize} 316 | \end{itemize} 317 | } 318 | \end{frame} 319 | 320 | \begin{frame} 321 | \frametitle{Snapshots} 322 | 323 | \begin{itemize} 324 | \onslide<1->{ 325 | \item A \emph{snapshot} is a curated package set used by Stack 326 | } 327 | \onslide<2->{ 328 | \item Stackage is a stable repository that stores snapshots} 329 | \onslide<3->{\item A \emph{resolver} is a reference to a required snapshot 330 | } 331 | \onslide<4->{ 332 | \item A screenshot from Stackage: 333 | 334 | \begin{center} 335 | \includegraphics[scale=0.33]{Pics/Snapshots.png} 336 | \end{center} 337 | } 338 | \end{itemize} 339 | \end{frame} 340 | 341 | \begin{frame} 342 | \frametitle{Ecosystem encapsulation} 343 | 344 | The Haskell ecosystem encapsulation can be described as the sequence of the following inclusions: 345 | 346 | \begin{center} 347 | \includegraphics[scale=0.25]{Pics/Eco.png} 348 | \end{center} 349 | \end{frame} 350 | 351 | \begin{frame} 352 | \frametitle{Creating a Haskell project using Stack} 353 | \onslide<1->{ 354 | \begin{itemize} 355 | \item Name your project somehow and run the script \verb"stack new " 356 | \item You will see the following story after the command \verb"tree ." in the project directory: 357 | } 358 | \onslide<2->{ 359 | 360 | \begin{center} 361 | \includegraphics[scale=0.34]{Pics/Tree.png} 362 | \end{center} 363 | \end{itemize} 364 | } 365 | \end{frame} 366 | 367 | \begin{frame} 368 | \frametitle{\verb"stack.yaml"} 369 | 370 | \onslide<1->{ 371 | Let us discuss on how dependency files look like. First of all, we have a look the \verb"stack.yaml" file: 372 | } 373 | 374 | \onslide<2->{ 375 | \begin{center} 376 | \includegraphics[scale=0.35]{Pics/StackYaml.png} 377 | \end{center} 378 | } 379 | \end{frame} 380 | 381 | \begin{frame} 382 | \frametitle{Cabal file} 383 | 384 | \onslide<1->{ 385 | The \verb".cabal" file describes the relevant version of a project and its dependencies: 386 | } 387 | \onslide<2->{ 388 | \begin{center} 389 | \includegraphics[scale=0.35]{Pics/CabalFile.png} 390 | \end{center} 391 | } 392 | \end{frame} 393 | 394 | \begin{frame} 395 | \frametitle{\verb"package.yaml"} 396 | 397 | \onslide<1->{ 398 | The \verb"package.yaml" is used to generate the \verb".cabal" file automatically: 399 | } 400 | \onslide<2->{ 401 | \begin{center} 402 | \includegraphics[scale=0.35]{Pics/PackageYaml.png} 403 | \end{center} 404 | } 405 | \end{frame} 406 | 407 | \begin{frame} 408 | \frametitle{Building and running a project} 409 | 410 | The basic commands: 411 | \begin{itemize} 412 | \item \verb"stack build" 413 | \item \verb"stack run" 414 | \item \verb"stack exec" 415 | \item \verb"stack ghci" 416 | \item \verb"stack clean" 417 | \item \verb"stack test" 418 | \end{itemize} 419 | \onslide<2->{ 420 | The roles of all these commands follow from their quite self-explanatory names. 421 | } 422 | \end{frame} 423 | 424 | \begin{frame} 425 | \frametitle{Hackage} 426 | According to its description, 'Hackage is the Haskell community's central package archive of open source software`. 427 | 428 | \onslide<2->{ 429 | \begin{itemize} 430 | \item Webpage: \verb"https://hackage.haskell.org" 431 | } 432 | \onslide<3->{ 433 | \item Browsing packages, simplified package search, current uploads. 434 | \end{itemize} 435 | } 436 | \onslide<4->{ 437 | \begin{center} 438 | \includegraphics[scale=0.22]{Pics/HackageExample.png} 439 | \end{center} 440 | } 441 | \end{frame} 442 | 443 | \begin{frame} 444 | \frametitle{Hoogle} 445 | 446 | \onslide<1->{ 447 | Hoogle is a sort of Haskell search engine. Webpage: \verb"https://hoogle.haskell.org". 448 | } 449 | 450 | \onslide<2->{ 451 | \begin{center} 452 | \includegraphics[scale=0.24]{Pics/Hoogle.png} 453 | \end{center} 454 | } 455 | \end{frame} 456 | 457 | \begin{frame} 458 | \frametitle{Hackage Search} 459 | 460 | Hackage Search is a searching tool for Hackage based on regular expressions. This tool is by Vladislav Zavialov, my GHC teammate from Serokell. 461 | 462 | \verb"https://hackage-search.serokell.io". 463 | 464 | \onslide<2->{ 465 | \begin{center} 466 | \includegraphics[scale=0.25]{Pics/HackageSearch1.png} 467 | \end{center} 468 | } 469 | \end{frame} 470 | 471 | \begin{frame} 472 | \frametitle{Hackage Search} 473 | 474 | \onslide<1->{ 475 | Hackage Search is a searching tool for Hackage based on regular expressions. This tool is by Vlad Zavialov, my GHC teammate from Serokell. 476 | 477 | \verb"https://hackage-search.serokell.io". 478 | } 479 | \begin{center} 480 | \includegraphics[scale=0.38]{Pics/HackageSearch2.png} 481 | \end{center} 482 | \end{frame} 483 | 484 | \begin{frame} 485 | \frametitle{Summary} 486 | We had a look at such topics as 487 | 488 | \begin{enumerate} 489 | \item General aspects of GHC and GHCi 490 | \item The Haskell Platform installation 491 | \item Dependency management using Stack and Cabal 492 | \item In other words, the Haskell ecosystem in a nutshell 493 | \end{enumerate} 494 | 495 | \vspace{\baselineskip} 496 | 497 | \onslide<2->{ 498 | On the next seminar, we will discuss: 499 | 500 | \begin{enumerate} 501 | \item The basic Haskell syntax 502 | \item The underlying aspects of the Haskell type system 503 | \item Functions and lambdas 504 | \item Immutability and laziness 505 | \end{enumerate} 506 | } 507 | \end{frame} 508 | 509 | \end{document} 510 | -------------------------------------------------------------------------------- /Lecture2/Pics/Compr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture2/Pics/Compr.png -------------------------------------------------------------------------------- /Lecture2/Pics/Doge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture2/Pics/Doge.png -------------------------------------------------------------------------------- /Lecture2/Pics/HeadTail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture2/Pics/HeadTail.png -------------------------------------------------------------------------------- /Lecture2/Pics/Imm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture2/Pics/Imm.png -------------------------------------------------------------------------------- /Lecture2/Pics/InfixPrefix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture2/Pics/InfixPrefix.png -------------------------------------------------------------------------------- /Lecture2/Pics/ListFunctions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture2/Pics/ListFunctions.png -------------------------------------------------------------------------------- /Lecture2/Pics/TypesScreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture2/Pics/TypesScreen.png -------------------------------------------------------------------------------- /Lecture2/Pics/WhatToDo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture2/Pics/WhatToDo.jpeg -------------------------------------------------------------------------------- /Lecture2/Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture2/Slides.pdf -------------------------------------------------------------------------------- /Lecture2/Slides.tex: -------------------------------------------------------------------------------- 1 | \documentclass[10pt]{beamer} 2 | \usepackage[cache=false]{minted} 3 | \usepackage[utf8x]{inputenc} 4 | \usepackage{hyperref} 5 | \usepackage{fontawesome} 6 | \usepackage{graphicx} 7 | \usepackage[english,ngerman]{babel} 8 | \usepackage{bussproofs} 9 | 10 | % ------------------------------------------------------------------------------ 11 | % Use the beautiful metropolis beamer template 12 | % ------------------------------------------------------------------------------ 13 | \usepackage[T1]{fontenc} 14 | \usepackage{fontawesome} 15 | \usepackage{FiraSans} 16 | \newtheorem{defin}{Definition} 17 | \newtheorem{theor}{Theorem} 18 | \newtheorem{prop}{Proposition} 19 | \mode 20 | { 21 | \usetheme[progressbar=foot,numbering=fraction,background=light]{metropolis} 22 | \usecolortheme{default} % or try albatross, beaver, crane, ... 23 | \usefonttheme{default} % or try serif, structurebold, ... 24 | \setbeamertemplate{navigation symbols}{} 25 | \setbeamertemplate{caption}[numbered] 26 | %\setbeamertemplate{frame footer}{My custom footer} 27 | } 28 | 29 | % ------------------------------------------------------------------------------ 30 | % beamer doesn't have texttt defined, but I usually want it anyway 31 | % ------------------------------------------------------------------------------ 32 | \let\textttorig\texttt 33 | \renewcommand<>{\texttt}[1]{% 34 | \only#2{\textttorig{#1}}% 35 | } 36 | 37 | % ------------------------------------------------------------------------------ 38 | % minted 39 | % ------------------------------------------------------------------------------ 40 | 41 | 42 | % ------------------------------------------------------------------------------ 43 | % tcolorbox / tcblisting 44 | % ------------------------------------------------------------------------------ 45 | \usepackage{xcolor} 46 | \definecolor{codecolor}{HTML}{FFC300} 47 | 48 | \usepackage{tcolorbox} 49 | \tcbuselibrary{most,listingsutf8,minted} 50 | 51 | \tcbset{tcbox width=auto,left=1mm,top=1mm,bottom=1mm, 52 | right=1mm,boxsep=1mm,middle=1pt} 53 | 54 | \newtcblisting{myr}[1]{colback=codecolor!5,colframe=codecolor!80!black,listing only, 55 | minted options={numbers=left, style=tcblatex,fontsize=\tiny,breaklines,autogobble,linenos,numbersep=3mm}, 56 | left=5mm,enhanced, 57 | title=#1, fonttitle=\bfseries, 58 | listing engine=minted,minted language=r} 59 | 60 | 61 | % ------------------------------------------------------------------------------ 62 | % Listings 63 | % ------------------------------------------------------------------------------ 64 | \definecolor{mygreen}{HTML}{37980D} 65 | \definecolor{myblue}{HTML}{0D089F} 66 | \definecolor{myred}{HTML}{98290D} 67 | 68 | \usepackage{listings} 69 | 70 | % the following is optional to configure custom highlighting 71 | \lstdefinelanguage{XML} 72 | { 73 | morestring=[b]", 74 | morecomment=[s]{}, 75 | morestring=[s]{>}{<}, 76 | morekeywords={ref,xmlns,version,type,canonicalRef,metr,real,target}% list your attributes here 77 | } 78 | 79 | \lstdefinestyle{myxml}{ 80 | language=XML, 81 | showspaces=false, 82 | showtabs=false, 83 | basicstyle=\ttfamily, 84 | columns=fullflexible, 85 | breaklines=true, 86 | showstringspaces=false, 87 | breakatwhitespace=true, 88 | escapeinside={(*@}{@*)}, 89 | basicstyle=\color{mygreen}\ttfamily,%\footnotesize, 90 | stringstyle=\color{myred}, 91 | commentstyle=\color{myblue}\upshape, 92 | keywordstyle=\color{myblue}\bfseries, 93 | } 94 | 95 | \title{Functional programming, Seminar No. 2} 96 | \author{Daniel Rogozin \\ Institute for Information Transmission Problems, RAS \\ Serokell O\"{U}} 97 | \date{Higher School of Economics \\ The Faculty of Computer Science} 98 | \begin{document} 99 | 100 | \maketitle 101 | 102 | \begin{frame} 103 | \frametitle{Intro} 104 | 105 | On the previous seminar, we: 106 | 107 | \onslide<1->{ 108 | \begin{itemize} 109 | \item discussed the general aspects of Haskell 110 | \item took a look at the Haskell ecosystem 111 | \end{itemize} 112 | } 113 | 114 | \vspace{\baselineskip} 115 | 116 | \onslide<2->{ 117 | Today, we: 118 | 119 | \begin{itemize} 120 | \item study the basic Haskell syntax 121 | \item study the list data type as one of the Haskell data structures 122 | \item realise why Haskell is a lazy language 123 | \end{itemize} 124 | } 125 | \end{frame} 126 | 127 | \begin{frame}[fragile] 128 | \frametitle{Bindings} 129 | 130 | The equality sign in Haskell denotes binding: 131 | 132 | \metroset{block=fill} 133 | \begin{exampleblock}{Example} 134 | \begin{minted}{haskell} 135 | fortyTwo = 42 136 | coolString = "coolString" 137 | \end{minted} 138 | \end{exampleblock} 139 | 140 | Local binding with the \verb"let"-keyword: 141 | \metroset{block=fill} 142 | \begin{exampleblock}{Example} 143 | \begin{minted}{haskell} 144 | fortyTwo = let number = 43 in number - 1 145 | \end{minted} 146 | \end{exampleblock} 147 | \end{frame} 148 | 149 | \begin{frame}[fragile] 150 | \frametitle{Function definitions} 151 | 152 | The following functions are also defined as bindings: 153 | 154 | \metroset{block=fill} 155 | \begin{exampleblock}{Example} 156 | \begin{minted}{haskell} 157 | add x y = x + y 158 | userName name = "Username: " ++ name 159 | id x = x 160 | \end{minted} 161 | \end{exampleblock} 162 | 163 | \vspace{\baselineskip} 164 | 165 | The same functions defined with lambda: 166 | \metroset{block=fill} 167 | \begin{exampleblock}{Example} 168 | \begin{minted}{haskell} 169 | add = \x y -> x + y 170 | userName = \name -> "Username: " ++ name 171 | id = \x -> x 172 | \end{minted} 173 | \end{exampleblock} 174 | \end{frame} 175 | 176 | \begin{frame}[fragile] 177 | \frametitle{Function application} 178 | 179 | As in the lambda calculus, function application is left associative by default 180 | 181 | \metroset{block=fill} 182 | \begin{exampleblock}{Example} 183 | \begin{minted}{haskell} 184 | {- 185 | foo x y z = f x y z = ((f x) y) z 186 | -} 187 | \end{minted} 188 | \end{exampleblock} 189 | 190 | \vspace{\baselineskip} 191 | 192 | One may use the dollar infix operator to reduce the overuse of brackets. 193 | For example, the functions \verb"function" and \verb"function1" are equivalent: 194 | \metroset{block=fill} 195 | \begin{exampleblock}{Example} 196 | \begin{minted}{haskell} 197 | function f x y z = f ((x y) z) 198 | function1 f x y z = f $ x y $ z 199 | \end{minted} 200 | \end{exampleblock} 201 | \end{frame} 202 | 203 | \begin{frame}[fragile] 204 | \frametitle{Prefix and infix notation} 205 | Every operator or function is prefix and infix in the following sense: 206 | 207 | \metroset{block=fill} 208 | \begin{exampleblock}{Example} 209 | \begin{minted}{haskell} 210 | > map (\x -> x * pi * 100) [1..3] 211 | [314.1592653589793,628.3185307179587,942.4777960769379] 212 | > (\x -> x * pi * 100) `map` [1..3] 213 | [314.1592653589793,628.3185307179587,942.4777960769379] 214 | \end{minted} 215 | \end{exampleblock} 216 | One can declare an operator defining its priority and associativity explicitly. Here is an example: 217 | \metroset{block=fill} 218 | \begin{exampleblock}{Example} 219 | \begin{minted}{haskell} 220 | (^) :: (Num a, Integral b) => a -> b -> a 221 | infixr 8 ^ 222 | \end{minted} 223 | \end{exampleblock} 224 | \end{frame} 225 | 226 | \begin{frame}[fragile] 227 | \frametitle{Currying and partial application} 228 | 229 | Recall the function \verb"add" once more. Here is an example of partial application: 230 | 231 | \metroset{block=fill} 232 | \begin{exampleblock}{Example} 233 | \begin{minted}{haskell} 234 | add x y = x + y 235 | addFive = add 5 236 | twentyEight = addFive 23 237 | -- 28 238 | \end{minted} 239 | \end{exampleblock} 240 | 241 | Partial application is well-defined since all many-argument functions in Haskell are curried by default. 242 | 243 | \end{frame} 244 | 245 | \begin{frame}[fragile] 246 | \frametitle{Immutability and laziness} 247 | 248 | In Haskell, values are immutable. A small example: 249 | 250 | \metroset{block=fill} 251 | \begin{exampleblock}{Example} 252 | \begin{minted}{haskell} 253 | > list = [1,2,3,4] 254 | > reverse list 255 | [4,3,2,1] 256 | > list 257 | [1,2,3,4] 258 | > 10 : list 259 | [10,1,2,3,4] 260 | > list 261 | [1,2,3,4] 262 | \end{minted} 263 | \end{exampleblock} 264 | \end{frame} 265 | 266 | \begin{frame}[fragile] 267 | \frametitle{Recursion} 268 | 269 | The straighforward factorial and the tail-recursive one: 270 | \metroset{block=fill} 271 | \begin{exampleblock}{Example} 272 | \begin{minted}{haskell} 273 | factorial n 274 | = if n == 0 then 1 else n * factorial (n - 1) 275 | 276 | tailFactorial n = helper 1 n 277 | where 278 | helper acc x = 279 | if x > 1 280 | then helper (acc * x) (x - 1) 281 | else acc 282 | \end{minted} 283 | \end{exampleblock} 284 | \end{frame} 285 | 286 | \begin{frame}[fragile] 287 | \frametitle{Guards} 288 | 289 | Let us take a look at the factorial implementation with guards: 290 | \metroset{block=fill} 291 | \begin{exampleblock}{Example} 292 | \begin{minted}{haskell} 293 | tailFactorial n = helper 1 n 294 | where 295 | helper acc x | x > 1 = helper (acc * x) (x - 1) 296 | | otherwise acc 297 | \end{minted} 298 | \end{exampleblock} 299 | \end{frame} 300 | 301 | \begin{frame}[fragile] 302 | \frametitle{Basic types} 303 | The basic types are: 304 | \begin{itemize} 305 | \item \verb"Bool" 306 | \item \verb"Int" 307 | \item \verb"Integer" 308 | \item \verb"Char" 309 | \item \verb"()" 310 | \item If \verb"a" and \verb"b" are types, then \verb"a -> b" is a type 311 | \item If \verb"a" and \verb"b" are types, then \verb"(a,b)" is a type 312 | \item If \verb"a" is a type, then \verb"[a]" is a type 313 | \end{itemize} 314 | 315 | A type declaration has the following form: 316 | 317 | \begin{minted}{haskell} 318 | term :: type 319 | \end{minted} 320 | \end{frame} 321 | 322 | \begin{frame}[fragile] 323 | \frametitle{Datatypes and constructors} 324 | We take the list of basic data types and associate constructors with these types. A constructor is a term that allows one to obtain a value of a given type. 325 | \begin{center} 326 | \begin{tabular}{ |c|c| } 327 | \hline 328 | \verb"Bool" & \verb"True" and \verb"False" \\ 329 | \verb"Int" & Integers from $-2^{29}$ to $2^{29} - 1$ \\ 330 | \verb"Integer" & The set of integers \\ 331 | \verb"Char" & Characters \verb"'0'", ..., \verb"'9'", \verb"'a'", ..., \verb"'z'", etc \\ 332 | \verb"()" & \verb"()" only \\ 333 | \verb"a -> b" & $\lambda x \rightarrow m$ \\ 334 | \verb"(a,b)" & if \verb"x :: a" and \verb"y :: b", then \verb"(x, y) :: (a,b)" \\ 335 | \verb"[a]" & the empty list \verb"[]" \\ 336 | \verb"[a]" & if \verb"x :: a" and \verb"xs :: [a]", then \verb"x : xs :: [a]" \\ 337 | \hline 338 | \end{tabular} 339 | \end{center} 340 | \end{frame} 341 | 342 | \begin{frame}[fragile] 343 | \frametitle{Types in GHCi} 344 | 345 | Use the GHCi command \verb":t" to get a type of an expression: 346 | 347 | \metroset{block=fill} 348 | \begin{exampleblock}{Example} 349 | \begin{minted}{haskell} 350 | > :t 5 351 | 5 :: Num p => p 352 | > :t not 353 | not :: Bool -> Bool 354 | > :t [0.5, 0.6, 0.7] 355 | [0.5, 0.6, 0.7] :: Fractional a => [a] 356 | > :t (\x -> "dratuti, " ++ x) 357 | (\x -> "dratuti, " ++ x) :: [Char] -> [Char] 358 | > :t 'x' 359 | 'x' :: Char 360 | \end{minted} 361 | \end{exampleblock} 362 | 363 | \end{frame} 364 | 365 | \begin{frame}[fragile] 366 | \frametitle{Function declaration with datatypes} 367 | 368 | Let us recall the examples: 369 | \metroset{block=fill} 370 | \begin{exampleblock}{Example} 371 | \begin{minted}{haskell} 372 | add x y = x + y 373 | userName name = "Username: " ++ name 374 | \end{minted} 375 | \end{exampleblock} 376 | 377 | \vspace{\baselineskip} 378 | 379 | One may annotate these functions with type signatures as follows: 380 | \metroset{block=fill} 381 | \begin{exampleblock}{Example} 382 | \begin{minted}{haskell} 383 | add :: Int -> Int -> Int 384 | add x y = x + y 385 | 386 | userName :: String -> String 387 | userName name = "Username: " ++ name 388 | \end{minted} 389 | \end{exampleblock} 390 | \end{frame} 391 | 392 | \begin{frame}[fragile] 393 | \frametitle{Lists} 394 | 395 | In Haskell, a list is a homogeneous collection of elements. 396 | \metroset{block=fill} 397 | \begin{exampleblock}{Example} 398 | \begin{minted}{haskell} 399 | empty :: [Int] 400 | empty = [] 401 | 402 | ten :: [Int] 403 | ten = [10] 404 | 405 | tenEleven :: [Int] 406 | tenEleven = 11 : ten 407 | 408 | tenElevenTwelve :: [Int] 409 | tenElevenTwelve = 12 : tenEleven 410 | -- 12 : (11 : []) 411 | \end{minted} 412 | \end{exampleblock} 413 | 414 | \end{frame} 415 | 416 | \begin{frame}[fragile] 417 | \frametitle{Lists. Ranges} 418 | \metroset{block=fill} 419 | \begin{exampleblock}{Example} 420 | \begin{minted}{haskell} 421 | oneToFive :: [Int] 422 | oneToFive = [1..5] 423 | 424 | oneToSevenOdd :: [Int] 425 | oneToSevenOdd = [1,3..7] 426 | 427 | nat :: [Int] 428 | nat = [0,1..] 429 | 430 | evens :: [Int] 431 | evens = [0,2,4..] 432 | \end{minted} 433 | \end{exampleblock} 434 | \end{frame} 435 | 436 | \begin{frame}[fragile] 437 | \frametitle{Lists. Heads and Tails} 438 | \metroset{block=fill} 439 | \begin{exampleblock}{Example} 440 | \begin{minted}{haskell} 441 | > tail [1..3] 442 | [2,3] 443 | > head [1..3] 444 | 1 445 | > head [] 446 | *** Exception: Prelude.head: empty list 447 | > tail [] 448 | *** Exception: Prelude.tail: empty list 449 | \end{minted} 450 | \end{exampleblock} 451 | \onslide<2->{ 452 | \begin{center} 453 | \includegraphics[scale=0.2]{Pics/Doge.png} 454 | \end{center}} 455 | 456 | \end{frame} 457 | 458 | \begin{frame}[fragile] 459 | \frametitle{Other helpful list functions} 460 | 461 | \metroset{block=fill} 462 | \begin{exampleblock}{Example} 463 | \begin{minted}{haskell} 464 | Prelude> drop 3 [1..7] 465 | [4,5,6,7] 466 | Prelude> take 4 ['a'..'h'] 467 | "abcd" 468 | Prelude> replicate 3 "d" 469 | ["d","d","d"] 470 | Prelude> replicate 3 'd' 471 | "ddd" 472 | Prelude> zip [1,2,3] "this is a word" 473 | [(1,'t'),(2,'h'),(3,'i')] 474 | Prelude> unzip [(1,'t'),(2,'h'),(3,'i')] 475 | ([1,2,3],"thi") 476 | Prelude> ['a'..'h'] !! 3 477 | 'd' 478 | \end{minted} 479 | \end{exampleblock} 480 | \end{frame} 481 | 482 | \begin{frame}[fragile] 483 | \frametitle{List compeherension} 484 | \metroset{block=fill} 485 | \begin{exampleblock}{Example} 486 | \begin{minted}{haskell} 487 | > take 4 [(i, j) | i <- [1..10], j <- [1..10], i == j*j] 488 | [(1,1),(4,2),(9,3),(16,4)] 489 | > [ i | i <- "a cool sentence", i < 'h'] 490 | "a c eece" 491 | > [ i | i <- "a cool sentence", fromEnum i < 100 ] 492 | "a c c" 493 | \end{minted} 494 | \end{exampleblock} 495 | \end{frame} 496 | 497 | \begin{frame}[fragile] 498 | \frametitle{Higher order functions} 499 | 500 | A function is a first-class object and one may pass any function as an argument: 501 | \metroset{block=fill} 502 | \begin{exampleblock}{Example} 503 | \begin{minted}{haskell} 504 | inc :: Int -> Int 505 | inc x = x + 1 506 | 507 | changeTwiceBy :: (Int -> Int) -> Int -> Int 508 | changeTwiceBy operation value 509 | = operation (operation value) 510 | 511 | seven :: Int 512 | seven = changeTwiceBy inc 5 513 | \end{minted} 514 | \end{exampleblock} 515 | \end{frame} 516 | 517 | \begin{frame}[fragile] 518 | \frametitle{\verb"Case"-expressions} 519 | 520 | \verb"Case"-expressions allows one to perform case analysis within a function body. 521 | 522 | \metroset{block=fill} 523 | \begin{exampleblock}{Example} 524 | \begin{minted}{haskell} 525 | getFont :: Int -> String 526 | getFont n = 527 | case n of 528 | 0 -> "PLAIN" 529 | 1 -> "BOLD" 530 | 2 -> "ITALIC" 531 | _ -> "UNKNOWN" 532 | \end{minted} 533 | \end{exampleblock} 534 | \end{frame} 535 | 536 | \begin{frame} 537 | \frametitle{Reduction strategies} 538 | 539 | \onslide<1->{ 540 | We recall a couple of definitions related to lambda calculus: 541 | } 542 | \onslide<2->{ 543 | \begin{enumerate} 544 | \item A term $M$ is called \emph{weakly normalisable} (WN), if there exists some halting reduction path that starts from $M$} 545 | \onslide<3->{\item A term $M$ is called \emph{strongly normalisable} (SN), if any reduction path that starts from $M$ terminates} 546 | \end{enumerate} 547 | 548 | \onslide<4->{ 549 | It is clear, that SN implies WN, not vice versa. In other words, there exists a term with an infinite reduction path, but it has a finite one at the same time. 550 | } 551 | \end{frame} 552 | 553 | \begin{frame} 554 | \frametitle{Reduction strategies} 555 | 556 | \onslide<1->{ 557 | Let us consider the example of the following ridiculous term: $(\lambda x y. x) (\lambda z. z) ((\lambda x. x x) (\lambda x. x x))$. One may reduce this term in two ways: 558 | } 559 | 560 | \vspace{\baselineskip} 561 | \onslide<2->{ 562 | From the one hand: 563 | 564 | $\begin{array}{lll} 565 | &(\lambda x y. x) (\lambda z. z) ((\lambda x. x x) (\lambda x. x x)) \rightarrow_{\beta} & \\ 566 | &(\lambda y. [x := (\lambda z. z)]) ((\lambda x. x x) (\lambda x. x x)) \rightarrow_{\beta} & \\ 567 | &(\lambda y. \lambda z. z) ((\lambda x. x x) (\lambda x. x x)) \rightarrow_{\beta}& \\ 568 | &(\lambda z. z) [y := (\lambda x. x x) (\lambda x. x x)] \rightarrow_{\beta}& \\ 569 | &\lambda z. z& 570 | \end{array}$ 571 | } 572 | \vspace{\baselineskip} 573 | 574 | \onslide<3->{ 575 | From the other hand: 576 | 577 | $\begin{array}{lll} 578 | & (\lambda x y. x) (\lambda z. z) ((\lambda x. x x) (\lambda x. x x)) \rightarrow_{\beta} & \\ 579 | & (\lambda x y. x) (\lambda z. z) (x x)(x := [\lambda x. x x]) \rightarrow_{\beta}& \\ 580 | & (\lambda x y. x) (\lambda z. z) ((\lambda x. x x) (\lambda x. x x)) \rightarrow_{\beta} \dots & \\ 581 | \end{array}$ 582 | } 583 | \end{frame} 584 | 585 | \begin{frame} 586 | \frametitle{Reduction strategies} 587 | \onslide<1->{ 588 | Let us consider the aforementioned example in some other aspects. 589 | } \onslide<2->{ 590 | \begin{itemize} 591 | \item In the first case, we have got a sensible result by several reduction steps. On the other hand, we have a loop in the second case. 592 | } \onslide<3->{ 593 | \item Also, in the first case, we start our reduction from the leftmost innermost redex. But when we were trying to reduce the term $(\lambda x. x x) (\lambda x. x x)$, we have seen that something went wrong. 594 | } \onslide<4->{ 595 | \item The moral is that the order of reduction matters. 596 | } 597 | \end{itemize} 598 | 599 | \onslide<5->{ 600 | In fact, we need to distinguish possible ways of application reduction, so far as we have no other options in the remaining cases: 601 | 602 | \begin{enumerate} 603 | \item If $x$ is a variable, then $x$ is already in normal form 604 | \item If a term has the form $\lambda x. M$, then we reduce $M$ 605 | \end{enumerate} 606 | } 607 | \end{frame} 608 | 609 | \begin{frame} 610 | \frametitle{Reduction strategies} 611 | 612 | \onslide<1->{ 613 | Thus, one needs to analyse the possible ways of application reduction. We have the following alternatives: 614 | } \onslide<2->{ 615 | \begin{enumerate} 616 | \item $(\lambda x_1 \dots x_n. M) N_1 \dots N_n$: we firtsly reduce $(N_i)_{i \in \{ 1, \dots, n \}}$ 617 | \item $(\lambda x_1 \dots x_n. M) N_1 \dots N_n$: reduce $(\lambda x. M) N_1$ and go further from left to right 618 | \end{enumerate} 619 | } \onslide<3->{ 620 | 621 | The first way is called \emph{applicative order reduction}, the second one is normal order reduction. In the following sense, the second is better: 622 | } \onslide<4->{ 623 | \begin{theorem} 624 | Let $M$ be a term such that $M$ has a normal form $M'$, then $M$ can be reduced to $M'$ using normal order reduction. 625 | \end{theorem} 626 | } 627 | \end{frame} 628 | 629 | \begin{frame} 630 | \frametitle{Theoretical Flashback. Call-by-value and call-by-name} 631 | 632 | \begin{itemize} 633 | \onslide<1->{\item The applicative (normal) order is often called call-by-value (call-by-name)} 634 | \onslide<2->{\item The most mainstream programming languages you know (Java, Python, Kotlin, etc) have the call-by-value semantics} 635 | \onslide<3->{\item The Haskell reduction has a call-by-need strategy which is quite close to call-by-name. Informally, such a stragety is called \emph{lazy}. Laziness denotes that Haskell does not compute a value if it is not needed at the moment} 636 | \onslide<4->{\item Call-by-name reduction reduces reducible terms to the bitter end, but it is not always optimal, unfortunately} 637 | \end{itemize} 638 | \end{frame} 639 | 640 | \begin{frame}[fragile] 641 | \frametitle{Haskell reduction} 642 | 643 | Suppose we have the following trivial function: 644 | \metroset{block=fill} 645 | \begin{exampleblock}{Example} 646 | \begin{minted}{haskell} 647 | square :: Int -> Int 648 | square x = x * x 649 | \end{minted} 650 | \end{exampleblock} 651 | 652 | \onslide<2->{ 653 | If we call this function on $(1 + 2)$, then we would have the following story: 654 | 655 | $\operatorname{square} \: (1 + 2) = (1 + 2) * (1 + 2) = 3 * (1 + 2) = 3 * 3 = 9$ 656 | } 657 | \onslide<3->{ 658 | We evalutate $(1 + 2)$ twice, even if we know that $1 + 2 = 3$ a priori.} \onslide<4->{The question of performance is still relevant. 659 | \begin{center} 660 | \includegraphics[scale=0.25]{Pics/WhatToDo.jpeg} 661 | \end{center} 662 | } 663 | \end{frame} 664 | 665 | \begin{frame}[fragile] 666 | \frametitle{The notion of a weak head normal form} 667 | 668 | In Haskell, reduction evalutates a term to its weak head normal form, where the outermost must be either constructor or lambda. Here are examples: WHNFs from the left and non-WHNFs from the right 669 | 670 | \begin{minipage}{0.5\textwidth} 671 | \begin{flushleft} 672 | \begin{minted}{haskell} 673 | 78 674 | 675 | 2 : [1,2] 676 | 677 | 'p' : ("ri" ++ "vet") 678 | 679 | [1, 1 + 2, 1 + 3] 680 | 681 | ("hel" ++ "lo", "world") 682 | 683 | \x -> (x + 2) + 2 684 | \end{minted} 685 | \end{flushleft} 686 | \end{minipage}\hfill 687 | \begin{minipage}{0.5\textwidth} 688 | \begin{flushright} 689 | \begin{minted}{haskell} 690 | 1 + 665 691 | 692 | (\x -> x ++ "ab") "cd" 693 | 694 | length [1..145] 695 | 696 | (\f g x -> f (g x)) id 697 | \end{minted} 698 | \end{flushright} 699 | \end{minipage} 700 | \end{frame} 701 | 702 | \section{Pure functions and side-effects} 703 | 704 | \begin{frame} 705 | \frametitle{Pure functions and side-effects} 706 | 707 | \begin{itemize} 708 | \onslide<1->{\item A function is called \emph{pure} if it has no side effects} 709 | \onslide<2->{\item It means that such a function behaves 'in the same way' at every point. This principle is also called \emph{referential transparency} 710 | } 711 | \onslide<3->{\item A side-effect function is a function that may yield different values for the same arguments. Mathematically, such a function is not function at all. This is rather a procedure. 712 | } \onslide<4->{ 713 | \item Haskell functions are (mostly) pure ones, but Haskell is not confluent as a version of the lambda calculus 714 | } 715 | \end{itemize} 716 | \end{frame} 717 | 718 | \begin{frame}[fragile] 719 | \frametitle{The failure of the Church-Rosser property} 720 | 721 | Let us consider the following quite simple example. In Haskell one has a function called \verb"seq". According to Hackage, ``The value of \verb"seq a b" is bottom if a is bottom, and otherwise equal to b.'' This function is a sort of instrument to introduce the restricted strictness to Haskell. The listing below demostrates the failure of the CRP: 722 | 723 | \begin{minted}{haskell} 724 | seq :: a -> b -> b 725 | seq _|_ _ = _|_ 726 | seq _ b = b 727 | 728 | bottom = undefined 729 | 730 | seq bottom 14 == bottom 731 | seq (bottom . id) 14 == 14 732 | \end{minted} 733 | 734 | \end{frame} 735 | 736 | \begin{frame} 737 | \frametitle{Finally} 738 | 739 | \onslide<1->{ 740 | On this seminar, we 741 | \begin{itemize} 742 | \item got acquinted with the basic Haskell syntax and basic data types 743 | \item discussed pure functions and the example of the confluence failure 744 | \end{itemize} 745 | } 746 | 747 | \onslide<2->{ 748 | On the next seminar, we will 749 | \begin{itemize} 750 | \item start to learn polymorphism and its advantages 751 | \item introduce typeclasses 752 | \item study the very first examples of typeclasses 753 | \end{itemize} 754 | } 755 | \end{frame} 756 | 757 | \begin{frame} 758 | \frametitle{Thank you!} 759 | \end{frame} 760 | 761 | \end{document} 762 | -------------------------------------------------------------------------------- /Lecture3/Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture3/Slides.pdf -------------------------------------------------------------------------------- /Lecture3/Slides.tex: -------------------------------------------------------------------------------- 1 | \documentclass[10pt]{beamer} 2 | \usepackage[cache=false]{minted} 3 | \usepackage[utf8x]{inputenc} 4 | \usepackage{hyperref} 5 | \usepackage{fontawesome} 6 | \usepackage{graphicx} 7 | \usepackage[english,ngerman]{babel} 8 | \usepackage{bussproofs} 9 | 10 | % ------------------------------------------------------------------------------ 11 | % Use the beautiful metropolis beamer template 12 | % ------------------------------------------------------------------------------ 13 | \usepackage[T1]{fontenc} 14 | \usepackage{fontawesome} 15 | \usepackage{FiraSans} 16 | \newtheorem{defin}{Definition} 17 | \newtheorem{theor}{Theorem} 18 | \newtheorem{prop}{Proposition} 19 | \mode 20 | { 21 | \usetheme[progressbar=foot,numbering=fraction,background=light]{metropolis} 22 | \usecolortheme{default} % or try albatross, beaver, crane, ... 23 | \usefonttheme{default} % or try serif, structurebold, ... 24 | \setbeamertemplate{navigation symbols}{} 25 | \setbeamertemplate{caption}[numbered] 26 | %\setbeamertemplate{frame footer}{My custom footer} 27 | } 28 | 29 | % ------------------------------------------------------------------------------ 30 | % beamer doesn't have texttt defined, but I usually want it anyway 31 | % ------------------------------------------------------------------------------ 32 | \let\textttorig\texttt 33 | \renewcommand<>{\texttt}[1]{% 34 | \only#2{\textttorig{#1}}% 35 | } 36 | 37 | % ------------------------------------------------------------------------------ 38 | % minted 39 | % ------------------------------------------------------------------------------ 40 | 41 | 42 | % ------------------------------------------------------------------------------ 43 | % tcolorbox / tcblisting 44 | % ------------------------------------------------------------------------------ 45 | \usepackage{xcolor} 46 | \definecolor{codecolor}{HTML}{FFC300} 47 | 48 | \usepackage{tcolorbox} 49 | \tcbuselibrary{most,listingsutf8,minted} 50 | 51 | \tcbset{tcbox width=auto,left=1mm,top=1mm,bottom=1mm, 52 | right=1mm,boxsep=1mm,middle=1pt} 53 | 54 | \newtcblisting{myr}[1]{colback=codecolor!5,colframe=codecolor!80!black,listing only, 55 | minted options={numbers=left, style=tcblatex,fontsize=\tiny,breaklines,autogobble,linenos,numbersep=3mm}, 56 | left=5mm,enhanced, 57 | title=#1, fonttitle=\bfseries, 58 | listing engine=minted,minted language=r} 59 | 60 | 61 | % ------------------------------------------------------------------------------ 62 | % Listings 63 | % ------------------------------------------------------------------------------ 64 | \definecolor{mygreen}{HTML}{37980D} 65 | \definecolor{myblue}{HTML}{0D089F} 66 | \definecolor{myred}{HTML}{98290D} 67 | 68 | \usepackage{listings} 69 | 70 | % the following is optional to configure custom highlighting 71 | \lstdefinelanguage{XML} 72 | { 73 | morestring=[b]", 74 | morecomment=[s]{}, 75 | morestring=[s]{>}{<}, 76 | morekeywords={ref,xmlns,version,type,canonicalRef,metr,real,target}% list your attributes here 77 | } 78 | 79 | \lstdefinestyle{myxml}{ 80 | language=XML, 81 | showspaces=false, 82 | showtabs=false, 83 | basicstyle=\ttfamily, 84 | columns=fullflexible, 85 | breaklines=true, 86 | showstringspaces=false, 87 | breakatwhitespace=true, 88 | escapeinside={(*@}{@*)}, 89 | basicstyle=\color{mygreen}\ttfamily,%\footnotesize, 90 | stringstyle=\color{myred}, 91 | commentstyle=\color{myblue}\upshape, 92 | keywordstyle=\color{myblue}\bfseries, 93 | } 94 | 95 | \title{Functional programming, Seminar No. 3} 96 | \author{Daniel Rogozin \\ Institute for Information Transmission Problems, RAS \\ Serokell O\"{U}} 97 | \date{Higher School of Economics \\ The Faculty of Computer Science} 98 | \begin{document} 99 | 100 | \maketitle 101 | 102 | \begin{frame} 103 | \frametitle{Today} 104 | 105 | We will study 106 | \begin{center} 107 | \includegraphics[scale=0.3]{Pics/doge.png} 108 | \end{center} 109 | \end{frame} 110 | 111 | \begin{frame}[fragile] 112 | \frametitle{Motivation} 113 | Let us recall the example of a higher order function from the previous seminar: 114 | 115 | \begin{minted}{haskell} 116 | changeTwiceBy :: (Int -> Int) -> Int -> Int 117 | changeTwiceBy operation value = operation (operation value) 118 | \end{minted} 119 | 120 | Here are the `same' functions for Booleans and strings: 121 | 122 | \begin{minted}{haskell} 123 | changeTwiceBy :: (Bool -> Bool) -> Bool -> Bool 124 | changeTwiceByBool operation value = 125 | operation (operation value) 126 | 127 | changeTwiceBy :: (String -> String) -> String -> String 128 | changeTwiceBy operation value = 129 | operation (operation value) 130 | \end{minted} 131 | 132 | \onslide<2->{ 133 | Too much boilerplate. 134 | } 135 | \end{frame} 136 | 137 | \begin{frame}[fragile] 138 | \frametitle{Parametric polymorphism} 139 | 140 | The key idea of parametric polymorphism that the same function can be called on distinct data types. Here are the first polymorphic examples: 141 | \begin{minted}{haskell} 142 | id :: a -> a 143 | id x = x 144 | 145 | const :: a -> b -> a 146 | const a b = a 147 | 148 | fst :: (a, b) -> a 149 | fst (a, b) = a 150 | 151 | swap :: (a, b) -> (b, a) 152 | swap (a, b) = (b, a) 153 | \end{minted} 154 | \end{frame} 155 | 156 | \begin{frame}[fragile] 157 | \frametitle{Example} 158 | \metroset{block=fill} 159 | \begin{exampleblock}{GHCi session} 160 | \begin{minted}{haskell} 161 | > id 6 162 | 6 163 | > id 6.0 164 | 6.0 165 | > const True 6 166 | True 167 | > const 6 True 168 | 6 169 | > fst ('5', 5) 170 | '5' 171 | > fst (5, '5') 172 | 5 173 | \end{minted} 174 | \end{exampleblock} 175 | \end{frame} 176 | 177 | \begin{frame}[fragile] 178 | \frametitle{A brief clarification} 179 | 180 | \begin{itemize} 181 | \item In such signatures as $a \to b \to a$, $a, b$ are type variables that range over arbitrary data types. In fact, $a$, $b$ are bounded by universal quantifier hidden under the carpet. 182 | \item In fact, the functions from the previous slide have the following signatures: 183 | \begin{minted}{haskell} 184 | id :: forall a. a -> a 185 | id x = x 186 | 187 | const :: forall a b. a -> b -> a 188 | const a b = a 189 | 190 | fst :: forall a b. (a, b) -> a 191 | fst (a, b) = a 192 | 193 | swap :: forall a b. (a, b) -> (b, a) 194 | swap (a, b) = (b, a) 195 | \end{minted} 196 | \end{itemize} 197 | \end{frame} 198 | 199 | \begin{frame}[fragile] 200 | \frametitle{Higher order functions and parametric polymorpism} 201 | \metroset{block=fill} 202 | \begin{exampleblock}{More examples} 203 | \begin{minted}{haskell} 204 | infixr 9 . 205 | (.) :: (b -> c) -> (a -> b) -> a -> c 206 | f . g = \x -> f (g x) 207 | 208 | flip :: (a -> b -> c) -> b -> a -> c 209 | flip f b a = f a b 210 | 211 | fix :: (a -> a) -> a 212 | fix f = f (fix f) 213 | 214 | curry :: ((a, b) -> c) -> a -> b -> c 215 | curry f x y = f (x, y) 216 | 217 | uncurry :: (a -> b -> c) -> ((a, b) -> c) 218 | uncurry f p = f (fst p) (snd p) 219 | \end{minted} 220 | \end{exampleblock} 221 | \end{frame} 222 | 223 | \begin{frame}[fragile] 224 | \frametitle{Examples with composition} 225 | \metroset{block=fill} 226 | \begin{exampleblock}{More examples} 227 | \begin{minted}{haskell} 228 | incNegate :: Int -> Int 229 | incNegate x = negate (x + 1) 230 | incNegate x = negate $ x + 1 231 | incNegate x = (negate . (+1)) x 232 | incNegate x = negate . (+1) $ x 233 | incNegate = negate . (+1) 234 | \end{minted} 235 | \end{exampleblock} 236 | \end{frame} 237 | 238 | \begin{frame}[fragile] 239 | \frametitle{\verb"curry" and \verb"uncurry"} 240 | 241 | \metroset{block=fill} 242 | \begin{exampleblock}{More examples} 243 | \begin{minted}{haskell} 244 | > uncurry (*) (3,4) 245 | 12 246 | > curry fst 3 4 247 | 3 248 | > curry id 3 4 249 | (3,4) 250 | > uncurry const (3,4) 251 | 3 252 | > uncurry (flip const) (3,4) 253 | 4 254 | \end{minted} 255 | \end{exampleblock} 256 | \end{frame} 257 | 258 | \begin{frame}[fragile] 259 | \frametitle{Examples with \verb"flip"} 260 | \metroset{block=fill} 261 | \begin{exampleblock}{More examples} 262 | \begin{minted}{haskell} 263 | show2 :: Int -> Int -> String 264 | show2 x y = show x ++ " and " ++ show y 265 | 266 | showSnd, showFst, showFst' :: Int -> String 267 | showSnd = show2 1 268 | showFst = flip show2 2 269 | showFst' = (`show2` 2) 270 | \end{minted} 271 | \end{exampleblock} 272 | 273 | \metroset{block=fill} 274 | \begin{exampleblock}{GHCi session} 275 | \begin{minted}{haskell} 276 | > showSnd 10 277 | "1 and 10" 278 | > showFst 10 279 | "10 and 2" 280 | > showFst' 42 281 | "42 and 2" 282 | \end{minted} 283 | \end{exampleblock} 284 | \end{frame} 285 | 286 | \begin{frame}[fragile] 287 | \frametitle{We no longer have boilerplate} 288 | 289 | All those functions such as the following one 290 | \metroset{block=fill} 291 | \begin{exampleblock}{\verb"changeTwiceBy" with \verb"Int"} 292 | \begin{minted}{haskell} 293 | changeTwiceBy :: (Int -> Int) -> Int -> Int 294 | changeTwiceBy operation value = 295 | operation (operation value) 296 | \end{minted} 297 | \end{exampleblock} 298 | can be generalised as follows: 299 | \metroset{block=fill} 300 | \begin{exampleblock}{\verb"applyTwice"} 301 | \begin{minted}{haskell} 302 | applyTwice :: (a -> a) -> a -> a 303 | applyTwice f a = f (f a) 304 | applyTwice f a = f . f $ a 305 | applyTwice f = f . f 306 | \end{minted} 307 | \end{exampleblock} 308 | \end{frame} 309 | 310 | \begin{frame}[fragile] 311 | \frametitle{HOF, polymorpism, and lists} 312 | \metroset{block=fill} 313 | \begin{exampleblock}{Examples} 314 | \begin{minted}{haskell} 315 | map :: (a -> b) -> [a] -> [b] 316 | 317 | filter :: (a -> Bool) -> [a] -> [a] 318 | 319 | zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] 320 | 321 | length :: [a] -> Int 322 | \end{minted} 323 | \end{exampleblock} 324 | 325 | \vspace{\baselineskip} 326 | 327 | We discuss their implementations closely on the next seminar. Here we just discuss them briefly. 328 | \end{frame} 329 | 330 | \begin{frame}[fragile] 331 | \frametitle{The composition examples + list functions} 332 | \metroset{block=fill} 333 | \begin{exampleblock}{More examples} 334 | \begin{minted}{haskell} 335 | foo, bar :: [Int] -> Int 336 | foo patak = 337 | length $ filter odd $ 338 | map (div 2) $ filter even $ map (div 7) patak 339 | bar = 340 | length . filter odd . 341 | map (div 2) . filter even . map (div 7) 342 | 343 | zip :: [a] -> [b] -> [(a, b)] 344 | zip = zipWith (,) 345 | \end{minted} 346 | \end{exampleblock} 347 | \end{frame} 348 | 349 | \begin{frame}[fragile] 350 | \frametitle{The composition examples + list functions} 351 | \metroset{block=fill} 352 | \begin{exampleblock}{More examples} 353 | \begin{minted}{haskell} 354 | stringsTransform :: [String] -> [String] 355 | stringsTransform l = 356 | map (\s -> map toUpper s) 357 | (filter (\s -> length s == 5) l) 358 | 359 | stringsTransform l = 360 | map (\s -> map toUpper s) $ 361 | filter (\s -> length s == 5) l 362 | 363 | stringsTransform l = 364 | map (map toUpper) $ filter ((== 5) . length) l 365 | 366 | stringsTransform = 367 | map (map toUpper) . filter ((== 5) . length) 368 | \end{minted} 369 | \end{exampleblock} 370 | \end{frame} 371 | 372 | \section{Bounded polymorphism and type classes} 373 | 374 | \begin{frame}[fragile] 375 | \frametitle{Bounded polymorphism and type classes} 376 | The idea of bounded (ad hoc) polymorphism is that one has a general interface with instances for each concrete data type. 377 | \metroset{block=fill} 378 | \begin{exampleblock}{More examples} 379 | \begin{minted}{haskell} 380 | > :t 9 381 | 9 :: Num p => p 382 | > 9 :: Int 383 | 9 384 | > 9 :: Double 385 | 9.0 386 | > 9 :: Rational 387 | 9 % 1 388 | > 9 :: Char 389 | :6:1: error: 390 | * No instance for (Num Char) arising from the literal '9' 391 | \end{minted} 392 | \end{exampleblock} 393 | \end{frame} 394 | 395 | \begin{frame}[fragile] 396 | \frametitle{Type classes. Motivation} 397 | 398 | \begin{itemize} 399 | \item Let us take a look a the following function 400 | 401 | \begin{minted}{haskell} 402 | elem' :: a -> [a] -> Bool 403 | elem' _ [] = False 404 | elem' x (y:ys) = x == y || elem' x ys 405 | \end{minted} 406 | 407 | \item \verb"a" is an arbitrary type for which equality is defined as usual. 408 | \end{itemize} 409 | \end{frame} 410 | 411 | \begin{frame}[fragile] 412 | \frametitle{Type classes. Motivation} 413 | Type variables in polymorphic function are bounded with universal quantifier. In ad hoc polymorphism, type variables are also bounded with $\forall$ but with the additional condition. This kind of quantification is called \emph{bounded}. 414 | 415 | \begin{minted}{haskell} 416 | elem :: forall a. Eq a => a -> [a] -> Bool 417 | elem _ [] = False 418 | elem x (y:ys) = x == y || elem x ys 419 | \end{minted} 420 | \end{frame} 421 | 422 | \begin{frame}[fragile] 423 | \frametitle{Type classes} 424 | 425 | \begin{itemize} 426 | \item \emph{A type class} is a collection of functions with type signatures with a common type parameter. An example given: 427 | \begin{minted}{haskell} 428 | class Eq a where 429 | (==) :: a -> a -> Bool 430 | (/=) :: a -> a -> Bool 431 | x /= y = neg (x == y) 432 | \end{minted} 433 | \item A type class name introduce a constraint called \emph{context}: 434 | \begin{minted}{haskell} 435 | elem :: Eq a => a -> [a] -> Bool 436 | \end{minted} 437 | \item The definition above without a context is not well-defined: 438 | \begin{minted}{haskell} 439 | :4:19: error: 440 | * No instance for (Eq a) arising from a use of '==' 441 | Possible fix: add (Eq a) to the context of 442 | the type signature for: elem' :: forall a. a -> [a] -> Bool 443 | \end{minted} 444 | \end{itemize} 445 | \end{frame} 446 | 447 | \begin{frame}[fragile] 448 | \frametitle{Instance declarations} 449 | 450 | A given data type \verb"a" has the \emph{instance} of a type class if every function of that class is implemented for \verb"a". An example: 451 | \metroset{block=fill} 452 | \begin{exampleblock}{Example} 453 | \begin{minted}{haskell} 454 | instance Eq Bool where 455 | True == True = True 456 | False == False = True 457 | _ == _ = False 458 | \end{minted} 459 | \end{exampleblock} 460 | \end{frame} 461 | 462 | \begin{frame}[fragile] 463 | \frametitle{Polymorphism + instance declarations} 464 | 465 | \begin{itemize} 466 | \item A type parameter in an instance declaration might be polymorphic as well: 467 | 468 | \metroset{block=fill} 469 | \begin{exampleblock}{Example} 470 | \begin{minted}{haskell} 471 | instance Eq a => Eq [a] where 472 | [] == [] = True 473 | (x : xs) == (y : ys) = x == y && xs == ys 474 | _ == _ = False 475 | \end{minted} 476 | \end{exampleblock} 477 | \item Without the context \verb"Eq a =>", this definition yields type error. 478 | \end{itemize} 479 | \end{frame} 480 | 481 | \begin{frame}[fragile] 482 | \frametitle{Some the \verb"Eq" instances} 483 | 484 | \begin{itemize} 485 | \item The \verb"Eq" type class has the following instances (some of them) 486 | \metroset{block=fill} 487 | \begin{exampleblock}{\verb"Eq" instances} 488 | \begin{minted}{haskell} 489 | instance Eq a => Eq [a] 490 | instance Eq Ordering 491 | instance Eq Int 492 | instance Eq Float 493 | instance Eq Double 494 | instance Eq Char 495 | instance Eq Bool 496 | \end{minted} 497 | \end{exampleblock} 498 | \item See the standard library source code to have a look at the implementation. 499 | \end{itemize} 500 | \end{frame} 501 | 502 | \begin{frame}[fragile] 503 | \frametitle{The \verb"Show" type class} 504 | 505 | \begin{itemize} 506 | \item The \verb"Show" type class allows one to represent a value as a string: 507 | \metroset{block=fill} 508 | \begin{exampleblock}{Some \verb"Eq" instances} 509 | \begin{minted}{haskell} 510 | class Show a where 511 | show :: a -> String 512 | \end{minted} 513 | \end{exampleblock} 514 | \item One needs to have a \verb"Show" instance to show a value of a given type. 515 | \end{itemize} 516 | \end{frame} 517 | 518 | \begin{frame}[fragile] 519 | \frametitle{Some of the \verb"Show" instances} 520 | 521 | Here are some of the \verb"Show" instances: 522 | \metroset{block=fill} 523 | \begin{exampleblock}{Some \verb"Show" instances} 524 | \begin{minted}{haskell} 525 | instance Show Integer 526 | instance Show Int 527 | instance Show Char 528 | instance Show Bool 529 | instance (Show a, Show b) => Show (a, b) 530 | \end{minted} 531 | \end{exampleblock} 532 | \end{frame} 533 | 534 | \begin{frame}[fragile] 535 | \frametitle{Ordering. Motivation} 536 | \begin{itemize} 537 | \item Let us take a look at the \verb"quicksort" function: 538 | 539 | \metroset{block=fill} 540 | \begin{exampleblock}{Some \verb"quicksort" instances} 541 | \begin{minted}{haskell} 542 | quicksort :: [a] -> [a] 543 | quicksort [] = [] 544 | quicksort (x:xs) = 545 | quicksort small ++ (x : quicksort large) 546 | where 547 | small = [y | y <- xs, y <= x] 548 | large = [y | y <- xs, y > x] 549 | \end{minted} 550 | \end{exampleblock} 551 | \onslide<2->{ 552 | \item Here we have the same situation. The definition of \verb"quicksort" as above is wrong. There exist types elements of which are incomparable, complex numbers, e.g. 553 | } 554 | \end{itemize} 555 | \end{frame} 556 | 557 | \begin{frame}[fragile] 558 | \frametitle{The \verb"Ord" type class} 559 | 560 | The full definition of \verb"Ord" is the following one: 561 | 562 | \metroset{block=fill} 563 | \begin{exampleblock}{\verb"Ord"} 564 | \begin{minted}{haskell} 565 | data Ordering = LT | EQ | GT 566 | class Eq a => Ord a where 567 | compare :: a -> a -> Ordering 568 | (<), (<=), (>), (>=) :: a -> a -> Bool 569 | max, min :: a -> a -> a 570 | compare x y = if x == y then EQ 571 | else if x <= y then LT 572 | else GT 573 | x <= y = 574 | case compare x y of 575 | GT -> False 576 | _ -> True 577 | {-# MINIMAL compare | (<=) #-} 578 | \end{minted} 579 | \end{exampleblock} 580 | \end{frame} 581 | 582 | \begin{frame}[fragile] 583 | \frametitle{\verb"Ord" instances} 584 | 585 | \metroset{block=fill} 586 | \begin{exampleblock}{\verb"Ord" instances} 587 | \begin{minted}{haskell} 588 | instance Ord Int 589 | instance Ord Float 590 | instance Ord Double 591 | instance Ord Char 592 | instance Ord Bool 593 | \end{minted} 594 | \end{exampleblock} 595 | \end{frame} 596 | 597 | \begin{frame}[fragile] 598 | \frametitle{The \verb"Num" type class} 599 | 600 | \verb"Num" is a type class with the general interface of usual arithmetic operations. 601 | \metroset{block=fill} 602 | \begin{exampleblock}{\verb"Num"} 603 | \begin{minted}{haskell} 604 | class Num a where 605 | (+), (-), (*) :: a -> a -> a 606 | negate, abs, signum :: a -> a 607 | fromInteger :: Integer -> a 608 | {-# MINIMAL (+), (*), abs, signum, 609 | fromInteger, (negate | (-)) #-} 610 | \end{minted} 611 | \end{exampleblock} 612 | \end{frame} 613 | 614 | \begin{frame}[fragile] 615 | \frametitle{\verb"Num" instances} 616 | 617 | \metroset{block=fill} 618 | \begin{exampleblock}{Some \verb"Num" instances} 619 | \begin{minted}{haskell} 620 | instance Num Integer 621 | instance Num Int 622 | instance Num Float 623 | instance Num Double 624 | \end{minted} 625 | \end{exampleblock} 626 | \end{frame} 627 | 628 | \begin{frame}[fragile] 629 | \frametitle{The \verb"Enum" type class} 630 | 631 | \verb"Enum" is a type class for sequentially ordered types. 632 | \metroset{block=fill} 633 | \begin{exampleblock}{Some \verb"Enum" instances} 634 | \begin{minted}{haskell} 635 | class Enum a where 636 | succ, pred :: a -> a 637 | toEnum :: Int -> a 638 | fromEnum :: a -> Int 639 | 640 | enumFrom :: a -> [a] -- [n..] 641 | enumFromThen :: a -> a -> [a] -- [n,m..] 642 | enumFromTo :: a -> a -> [a] -- [n..m] 643 | enumFromThenTo :: a -> a -> a -> [a] -- [n,m..p] 644 | {-# MINIMAL toEnum, fromEnum #-} 645 | \end{minted} 646 | \end{exampleblock} 647 | \end{frame} 648 | 649 | \begin{frame}[fragile] 650 | \frametitle{\verb"Enum" instances} 651 | 652 | \metroset{block=fill} 653 | \begin{exampleblock}{Some \verb"Num" instances} 654 | \begin{minted}{haskell} 655 | instance Enum Integer 656 | instance Enum Int 657 | instance Enum Char 658 | instance Enum Bool 659 | instance Enum Float 660 | instance Enum Double 661 | \end{minted} 662 | \end{exampleblock} 663 | \end{frame} 664 | 665 | \begin{frame}[fragile] 666 | \frametitle{The \verb"Fractional" type class} 667 | 668 | \begin{itemize} 669 | \item The \verb"Fractional" type class is a general interface for numeric division 670 | \metroset{block=fill} 671 | \begin{exampleblock}{Some \verb"Num" instances} 672 | \begin{minted}{haskell} 673 | class Num a => Fractional a where 674 | (/) :: a -> a -> a 675 | recip :: a -> a 676 | fromRational :: Rational -> a 677 | {-# MINIMAL fromRational, (recip | (/)) #-} 678 | \end{minted} 679 | \end{exampleblock} 680 | \item We require the \verb"Num a" restriction. 681 | \item The \verb"Fractional" instances are \verb"Float" and \verb"Double". 682 | \end{itemize} 683 | \end{frame} 684 | 685 | \begin{frame} 686 | \frametitle{Summary} 687 | 688 | \onslide<1->{ 689 | On this seminar, we 690 | \begin{itemize} 691 | \item had a look at parametric polymorphism to see how to avoid boilerplate, 692 | \item discussed type classes and ad hoc polymorphism, 693 | \item studied such basic type classes as \verb"Eq", \verb"Show", etc. 694 | \end{itemize} 695 | } 696 | 697 | \onslide<2->{ 698 | On the next seminar, we will study 699 | \begin{itemize} 700 | \item the variety of Haskell data types: algebraic data types, newtypes, 701 | type synonyms, etc, 702 | \item the power of pattern matching, 703 | \item folds 704 | \item evaluation enforcement. 705 | \end{itemize} 706 | } 707 | \end{frame} 708 | 709 | 710 | \end{document} 711 | -------------------------------------------------------------------------------- /Lecture4/Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture4/Slides.pdf -------------------------------------------------------------------------------- /Lecture4/Slides.tex: -------------------------------------------------------------------------------- 1 | \documentclass[10pt]{beamer} 2 | \usepackage[cache=false]{minted} 3 | \usepackage[utf8x]{inputenc} 4 | \usepackage{hyperref} 5 | \usepackage{fontawesome} 6 | \usepackage{graphicx} 7 | \usepackage[all, 2cell]{xy} 8 | \usepackage[all]{xy} 9 | \usepackage[english,ngerman]{babel} 10 | \usepackage{bussproofs} 11 | 12 | % ------------------------------------------------------------------------------ 13 | % Use the beautiful metropolis beamer template 14 | % ------------------------------------------------------------------------------ 15 | \usepackage[T1]{fontenc} 16 | \usepackage{fontawesome} 17 | \usepackage{FiraSans} 18 | \newtheorem{defin}{Definition} 19 | \newtheorem{theor}{Theorem} 20 | \newtheorem{prop}{Proposition} 21 | \mode 22 | { 23 | \usetheme[progressbar=foot,numbering=fraction,background=light]{metropolis} 24 | \usecolortheme{default} % or try albatross, beaver, crane, ... 25 | \usefonttheme{default} % or try serif, structurebold, ... 26 | \setbeamertemplate{navigation symbols}{} 27 | \setbeamertemplate{caption}[numbered] 28 | %\setbeamertemplate{frame footer}{My custom footer} 29 | } 30 | 31 | % ------------------------------------------------------------------------------ 32 | % beamer doesn't have texttt defined, but I usually want it anyway 33 | % ------------------------------------------------------------------------------ 34 | \let\textttorig\texttt 35 | \renewcommand<>{\texttt}[1]{% 36 | \only#2{\textttorig{#1}}% 37 | } 38 | 39 | % ------------------------------------------------------------------------------ 40 | % minted 41 | % ------------------------------------------------------------------------------ 42 | 43 | 44 | % ------------------------------------------------------------------------------ 45 | % tcolorbox / tcblisting 46 | % ------------------------------------------------------------------------------ 47 | \usepackage{xcolor} 48 | \definecolor{codecolor}{HTML}{FFC300} 49 | 50 | \usepackage{tcolorbox} 51 | \tcbuselibrary{most,listingsutf8,minted} 52 | 53 | \tcbset{tcbox width=auto,left=1mm,top=1mm,bottom=1mm, 54 | right=1mm,boxsep=1mm,middle=1pt} 55 | 56 | \newtcblisting{myr}[1]{colback=codecolor!5,colframe=codecolor!80!black,listing only, 57 | minted options={numbers=left, style=tcblatex,fontsize=\tiny,breaklines,autogobble,linenos,numbersep=3mm}, 58 | left=5mm,enhanced, 59 | title=#1, fonttitle=\bfseries, 60 | listing engine=minted,minted language=r} 61 | 62 | 63 | % ------------------------------------------------------------------------------ 64 | % Listings 65 | % ------------------------------------------------------------------------------ 66 | \definecolor{mygreen}{HTML}{37980D} 67 | \definecolor{myblue}{HTML}{0D089F} 68 | \definecolor{myred}{HTML}{98290D} 69 | 70 | \usepackage{listings} 71 | 72 | % the following is optional to configure custom highlighting 73 | \lstdefinelanguage{XML} 74 | { 75 | morestring=[b]", 76 | morecomment=[s]{}, 77 | morestring=[s]{>}{<}, 78 | morekeywords={ref,xmlns,version,type,canonicalRef,metr,real,target}% list your attributes here 79 | } 80 | 81 | \lstdefinestyle{myxml}{ 82 | language=XML, 83 | showspaces=false, 84 | showtabs=false, 85 | basicstyle=\ttfamily, 86 | columns=fullflexible, 87 | breaklines=true, 88 | showstringspaces=false, 89 | breakatwhitespace=true, 90 | escapeinside={(*@}{@*)}, 91 | basicstyle=\color{mygreen}\ttfamily,%\footnotesize, 92 | stringstyle=\color{myred}, 93 | commentstyle=\color{myblue}\upshape, 94 | keywordstyle=\color{myblue}\bfseries, 95 | } 96 | 97 | \title{Functional programming, Seminar No. 4} 98 | \author{Daniel Rogozin \\ Institute for Information Transmission Problems, RAS \\ Serokell O\"{U}} 99 | \date{Higher School of Economics \\ The Faculty of Computer Science} 100 | \begin{document} 101 | 102 | \maketitle 103 | 104 | \begin{frame} 105 | \frametitle{Today} 106 | 107 | We will study 108 | \begin{center} 109 | \includegraphics[scale=0.12]{mlem.jpeg} 110 | \end{center} 111 | \end{frame} 112 | 113 | \section{Algebraic data types and pattern matching} 114 | 115 | \begin{frame}[fragile] 116 | \frametitle{Pattern matching} 117 | Let us take a look at the following functions: 118 | \begin{minted}{haskell} 119 | swap :: (a, b) -> (b, a) 120 | swap (a, b) = (b, a) 121 | 122 | length :: [a] -> Int 123 | length [] = 0 124 | lenght (x : xs) = 1 + length xs 125 | \end{minted} 126 | 127 | \onslide<2->{ 128 | \begin{itemize} 129 | \item Such expressions as \verb"(a,b)", \verb"[]", and \verb"(x : xs)" are called \emph{patterns} 130 | \item One needs to check whether the constructors \verb"(,)" and \verb"( : )" are relevant. 131 | \item Consider \verb"swap (45, True)". Variables \verb"a" and \verb"b" are bound with the values \verb"45" and \verb"True". 132 | \item Consider \verb"lenght [1,2,3]". Variables \verb"x" and \verb"xs" are bound with the values \verb"1" and \verb"[2,3]" 133 | \end{itemize} 134 | } 135 | \end{frame} 136 | 137 | \begin{frame}[fragile] 138 | \frametitle{Algebraic data types. Sums} 139 | 140 | The simplest example of an algebraic data type is a data type defined with an enumeration of constructors that stores no values. 141 | \begin{minted}{haskell} 142 | data Colour = Red | Blue | Green | Purple | Yellow 143 | deriving (Show, Eq) 144 | 145 | isRGB :: Colour -> Bool 146 | isRGB Red = True 147 | isRGB Blue = True 148 | isRGB Green = True 149 | isRGB _ = False -- Wild-card 150 | \end{minted} 151 | \end{frame} 152 | 153 | \begin{frame}[fragile] 154 | \frametitle{Algebraic data types. Products} 155 | 156 | \begin{itemize} 157 | \item An example of a product data type: 158 | \begin{minted}{haskell} 159 | data Point = Point Double Double 160 | deriving Show 161 | 162 | > :type Point 163 | Point :: Double -> Double -> Point 164 | \end{minted} 165 | \item An example of a function 166 | \begin{minted}{haskell} 167 | taxiCab :: Point -> Point -> Double 168 | taxiCab (Point x1 y1) (Point x2 y2) = 169 | abs (x1 - x2) + abs (y1 - y2) 170 | \end{minted} 171 | \end{itemize} 172 | \end{frame} 173 | 174 | \begin{frame}[fragile] 175 | \frametitle{Polymorphic data types} 176 | 177 | \begin{itemize} 178 | \item That point data type might be parametrised with a type parameter: 179 | \begin{minted}{haskell} 180 | data Point a = Point a a 181 | deriving Show 182 | \end{minted} 183 | 184 | \item The \verb"Point" data constructor has the following type. The \verb"Point" from the left (see the definition above) is a type function that has its type (kind). 185 | \begin{minted}{haskell} 186 | > :type Point 187 | Point :: a -> a -> Point a 188 | > :kind Point 189 | Point :: * -> * 190 | \end{minted} 191 | \end{itemize} 192 | \end{frame} 193 | 194 | \begin{frame}[fragile] 195 | \frametitle{Polymorphic data types and type classes} 196 | 197 | \begin{itemize} 198 | \item Suppose we have a function: 199 | \begin{minted}{haskell} 200 | midPoint 201 | :: Fractional a => Point a -> Point a -> Point a 202 | midPoint (Pt x1 y1) (Pt x2 y2) = 203 | Pt ((x1 + x2) / 2) ((y1 + y2) / 2) 204 | \end{minted} 205 | \item Playing with GHCi: 206 | \begin{minted}{haskell} 207 | > :t midPoint (Pt 3 5) (Pt 6 4) 208 | midPoint (Pt 3 5) (Pt 6 4) :: Fractional a => Point a 209 | > midPoint (Pt 3 5) (Pt 6 4) 210 | Pt 4.5 4.5 211 | > :t it 212 | it :: Fractional a => Point a 213 | \end{minted} 214 | \end{itemize} 215 | \end{frame} 216 | 217 | \begin{frame}[fragile] 218 | \frametitle{Inductive data types} 219 | 220 | \begin{itemize} 221 | \item The list is the first example of an inductive data type 222 | \begin{minted}{haskell} 223 | data List a = Nil | Cons a (List a) 224 | deriving Show 225 | \end{minted} 226 | \item The data constructors are \verb"Nil :: List a" and \verb"Cons :: a -> List a -> List a" 227 | \item Pattern matching and recursion 228 | \begin{minted}{haskell} 229 | concat :: List a -> List a -> List a 230 | concat Nil ys = ys 231 | concat (Cons x xs) ys = Cons x (xs `concat` ys) 232 | \end{minted} 233 | \end{itemize} 234 | \end{frame} 235 | 236 | \begin{frame}[fragile] 237 | \frametitle{Standard lists} 238 | 239 | \begin{itemize} 240 | \item The list data type is already in the standard library, but its approximate definition is the following one: 241 | \begin{minted}{haskell} 242 | infixr 5 : 243 | data [] a = [] | a : ([] a) 244 | deriving Show 245 | \end{minted} 246 | \item Syntax sugar: 247 | \begin{minted}{haskell} 248 | [1,2,3,4] == 1 : 2 : 3 : 4 : [] 249 | \end{minted} 250 | \item The example of a definition with built-in lists: 251 | \begin{minted}{haskell} 252 | infixr 5 ++ 253 | (++) :: [a] -> [a] -> [a] 254 | (++) [] ys = ys 255 | (++) (x:xs) ys = x : xs ++ ys 256 | \end{minted} 257 | \end{itemize} 258 | \end{frame} 259 | 260 | \begin{frame}[fragile] 261 | \frametitle{\verb"case ... of ..." expressions} 262 | \begin{itemize} 263 | \item \verb"case ... of ..." expressions allows one to patternmatch everywhere 264 | \begin{minted}{haskell} 265 | filter :: (a -> Bool) -> [a] -> [a] 266 | filter p [] = [] 267 | filter p (x : xs) = 268 | case p x of 269 | True -> x : filter p xs 270 | False -> filter p xs 271 | \end{minted} 272 | \item The pattern matching from the previous slide is a syntax sugar for the corresponding \verb"case ... of ..." expression 273 | \end{itemize} 274 | \end{frame} 275 | 276 | \begin{frame}[fragile] 277 | \frametitle{Semantic aspects of pattern matching} 278 | \begin{itemize} 279 | \item Pattern matching is performed from up to down and from left to right after that. 280 | \item A pattern match is either 281 | \begin{itemize} 282 | \item succeed 283 | \item or failed 284 | \item or diverged 285 | \end{itemize} 286 | \item Here is an example: 287 | \begin{minted}{haskell} 288 | foo (1,4) = 7 289 | foo (0,_) = 8 290 | \end{minted} 291 | \item \verb"(0, undefined)" fails in the first case and it succeeds in the second one 292 | \item \verb"(undefined, 0)" diverges during a match 293 | \item What about \verb"(1,7-3)"? 294 | \end{itemize} 295 | \end{frame} 296 | 297 | \begin{frame}[fragile] 298 | \frametitle{As-patterns} 299 | \begin{itemize} 300 | \item Suppose we have the following function (a quite bad one) 301 | \begin{minted}{haskell} 302 | dupHead :: [a] -> [a] 303 | dupHead (x : xs) = x : x : xs 304 | \end{minted} 305 | \item One may rewrite this function as follows: 306 | \begin{minted}{haskell} 307 | dupHead :: [a] -> [a] 308 | dupHead s@(x : xs) = x : s 309 | \end{minted} 310 | \item Here, the name \verb"s" is assigned to the whole pattern \verb"x : xs" 311 | \end{itemize} 312 | \end{frame} 313 | 314 | \begin{frame}[fragile] 315 | \frametitle{Irrefutable patterns} 316 | \begin{itemize} 317 | \item Irrefutable patterns are wild-cards, variables, and lazy patterns 318 | \item An example of a lazy pattern: 319 | \begin{minted}{haskell} 320 | > f *** g (a,b) = (f a, g b) 321 | > (const 2) *** (const 1) $ undefined 322 | *** Exception: Prelude.undefined 323 | > f *** g ~(a,b) = (f a, g b) 324 | > (const 2) *** (const 1) $ undefined 325 | (2,1) 326 | \end{minted} 327 | \end{itemize} 328 | \end{frame} 329 | 330 | \begin{frame}[fragile] 331 | \frametitle{\verb"newtype" and \verb"type" declarations} 332 | 333 | \begin{itemize} 334 | \item The keyword \verb"type" introduces type synonyms. 335 | \begin{minted}{haskell} 336 | type String = [Char] 337 | \end{minted} 338 | \item In Haskell, the string data type type is merely a type synonym for the list of characters 339 | \item The keyword \verb"newtype" defines a new type with the single constructor that packs a value of a given type 340 | \begin{minted}{haskell} 341 | newtype Age = Age Int 342 | \end{minted} 343 | 344 | \item The same type \verb"Age" defined with the accessor \verb"runAge" 345 | \begin{minted}{haskell} 346 | newtype Age = Age { runAge :: Int } 347 | -- where runAge :: Age -> Int 348 | \end{minted} 349 | \end{itemize} 350 | \end{frame} 351 | 352 | \begin{frame}[fragile] 353 | \frametitle{Field labels} 354 | \begin{itemize} 355 | \item Sometimes product data types are rather cumbersome: 356 | \begin{minted}{haskell} 357 | data Person = Person String String Int Float String 358 | \end{minted} 359 | \item As an alternative, one may define a data type with field labels 360 | \begin{minted}{haskell} 361 | data Person = 362 | Person { firstName :: String 363 | , lastName :: String 364 | , age :: Int 365 | , height :: Float 366 | , phoneNumber :: String 367 | } 368 | \end{minted} 369 | \item Such a data type is a record with accessors such as 370 | \verb"firstName :: Person -> String" 371 | \end{itemize} 372 | \end{frame} 373 | 374 | \begin{frame}[fragile] 375 | \frametitle{Field labels and type classes} 376 | \begin{itemize} 377 | \item Let us recall the \verb"Eq" type class once more 378 | \begin{minted}{haskell} 379 | class Eq a where 380 | (==) :: a -> a -> Bool 381 | (/=) :: a -> a -> Bool 382 | 383 | instance Eq Int where 384 | x == y = x `eqInt` y 385 | 386 | eqFunction :: Eq a => a -> a -> Int 387 | eqFunction x y = 388 | case x == y of 389 | True -> 42 390 | False -> 0 391 | \end{minted} 392 | \item In fact, type classes are sugar for data types with field labels 393 | \item The constraint \verb"Eq a" is an additional argument 394 | \end{itemize} 395 | \end{frame} 396 | 397 | \begin{frame}[fragile] 398 | \frametitle{Field labels and type classes} 399 | 400 | \begin{itemize} 401 | \item The previous listing, an unsugared version (but very roughly): 402 | \begin{minted}{haskell} 403 | data Eq a = 404 | Eq { eq :: a -> a -> Bool 405 | , neq :: a -> a -> Bool 406 | } 407 | 408 | intInstance :: Eq Int 409 | intInstance = Eq eqInt (\x y -> not $ x `eqInt` y) 410 | 411 | eqFunction :: Eq a -> a -> a -> Int 412 | eqFunction eqInst x y = 413 | case ((eq eqInst) x y) of 414 | True -> 42 415 | False -> 0 416 | \end{minted} 417 | \end{itemize} 418 | \end{frame} 419 | 420 | \begin{frame}[fragile] 421 | \frametitle{Some standard algebraic data types} 422 | \begin{itemize} 423 | \item The \verb"Maybe a" data type is a type of optional values: 424 | \begin{minted}{haskell} 425 | data Maybe a = Nothing | Just a 426 | 427 | maybe :: b -> (a -> b) -> Maybe a -> b 428 | maybe b _ Nothing = b 429 | maybe b f (Just x) = f x 430 | \end{minted} 431 | \item A simple example 432 | \begin{minted}{haskell} 433 | safeHead :: [a] -> Maybe a 434 | safeHead [] = Nothing 435 | safeHead (x : _) = Just x 436 | \end{minted} 437 | \end{itemize} 438 | \end{frame} 439 | 440 | \begin{frame}[fragile] 441 | \frametitle{Some standard algebraic data types} 442 | \begin{itemize} 443 | \item The \verb"Either" data type describes one or the other value 444 | \begin{minted}{haskell} 445 | data Either e a = Left e | Right a 446 | 447 | either :: (a -> c) -> (b -> c) -> Either a b -> c 448 | either f _ (Left x) = f x 449 | either _ g (Right x) = g x 450 | \end{minted} 451 | \item An example: 452 | \begin{minted}{haskell} 453 | safeTail :: [a] -> Either String [a] 454 | safeTail [] = Left "I have no tail, mate" 455 | safeTail (_ : xs) = Right xs 456 | \end{minted} 457 | \end{itemize} 458 | \end{frame} 459 | 460 | \section{Folds} 461 | 462 | \begin{frame}[fragile] 463 | \frametitle{Folds and lists. Motivation} 464 | 465 | Take a look at these functions 466 | \begin{minted}{haskell} 467 | sum :: Num a => [a] -> a 468 | sum [] = 0 469 | sum (x : xs) = x + sum xs 470 | 471 | product :: Num a => [a] -> a 472 | product [] = 1 473 | product (x : xs) = x * product xs 474 | 475 | concat :: [[a]] -> [a] 476 | concat [] = [] 477 | concat (x : xs) = x ++ concat xs 478 | \end{minted} 479 | \end{frame} 480 | 481 | \begin{frame}[fragile] 482 | \frametitle{The definition of a right fold} 483 | \begin{itemize} 484 | \item The definition of a right fold is the: 485 | \begin{minted}{haskell} 486 | foldr :: (a -> b -> b) -> b -> [a] -> b 487 | foldr _ ini [] = ini 488 | foldr f ini (x : xs) = f x (foldr f ini xs) 489 | \end{minted} 490 | \item An informal explanation: 491 | \begin{minted}{haskell} 492 | foldr f z [x1, x2, ..., xn] == 493 | x1 `f` (x2 `f` ... (xn `f` z)...) 494 | \end{minted} 495 | \end{itemize} 496 | \end{frame} 497 | 498 | \begin{frame} 499 | \frametitle{The definition of a right fold} 500 | One may visualise that for some list \verb"[a,b,c]". The list from the left and its right fold from the right 501 | \begin{small} 502 | \xymatrix{ 503 | & \verb":" \ar[dl] \ar[dr] &&&&& \verb"f" \ar[dl] \ar[dr] \\ 504 | \verb"a" && \verb":" \ar[dl] \ar[dr] &&& \verb"a" && \verb"f" \ar[dl] \ar[dr] \\ 505 | & \verb"b" && \verb":" \ar[dl] \ar[dr] &&& \verb"b" && \verb"f" \ar[dl] \ar[dr] \\ 506 | && \verb"c" && \verb"[]" &&& \verb"c" && \verb"ini" 507 | } 508 | \end{small} 509 | \end{frame} 510 | 511 | \begin{frame}[fragile] 512 | \frametitle{Functions \verb"sum", \verb"product", and \verb"concat" with \verb"foldr"} 513 | \begin{minted}{haskell} 514 | sum :: Num a => [a] -> a 515 | sum = foldr (+) 0 516 | 517 | product :: Num a => [a] -> a 518 | product = foldr (*) 1 519 | 520 | concat :: [[a]] -> [a] 521 | concat = foldr (++) [] 522 | \end{minted} 523 | \end{frame} 524 | 525 | \begin{frame}[fragile] 526 | \frametitle{The universal property of a right fold} 527 | \begin{block}{The universal property} 528 | Let \verb"g" be a function defined by the following equations: 529 | \begin{minted}{haskell} 530 | g [] = v 531 | g (x : xs) = f x (g xs) 532 | \end{minted} 533 | 534 | then one has $\forall \: \verb"xs :: [a]" \:\: (\verb"g xs" \equiv \verb"foldr f v xs")$ 535 | \end{block} 536 | \begin{itemize} 537 | \item The universal property is proved inductively 538 | \item This property implies \verb"foldr f v" and \verb"g" are equivalent in this case 539 | \end{itemize} 540 | \end{frame} 541 | 542 | \begin{frame}[fragile] 543 | \frametitle{The definition of a left fold} 544 | \begin{itemize} 545 | \item In addition to the right fold, one also has the left one 546 | \begin{minted}{haskell} 547 | foldl :: (b -> a -> b) -> b -> [a] -> b 548 | foldl _ ini [] = ini 549 | foldl f ini (x : xs) = foldl f (f ini x) xs 550 | \end{minted} 551 | \item Informally: 552 | \begin{minted}{haskell} 553 | foldl f ini [x1, x2, ..., xn] 554 | == (...((ini `f` x1) `f` x2) `f`...) `f` xn 555 | \end{minted} 556 | \onslide<2->{ 557 | \item We can optimise the implementation of \verb"foldl". 558 | \item \verb"foldl" is the most optimal function, but we are not capable of processing infinite lists using the left fold function. 559 | } 560 | \end{itemize} 561 | \end{frame} 562 | 563 | \begin{frame}[fragile] 564 | \frametitle{Are \verb"foldr" and \verb"foldl" equivalent?} 565 | 566 | \begin{itemize} 567 | \item Note that \verb"foldr" and \verb"foldl" are not equivalent generally 568 | \begin{minted}{haskell} 569 | > foldl (/) 64 [4,2,4] 570 | 2.0 571 | > foldr (/) 64 [4,2,4] 572 | 0.125 573 | > foldl (\x y -> 2*x + y) 4 [1,2,3] 574 | 43 575 | > foldr (\x y -> 2*x + y) 4 [1,2,3] 576 | 16 577 | \end{minted} 578 | \item \verb"foldr" and \verb"foldl" are equivalent if the folding operation is associative and commutative 579 | \end{itemize} 580 | \end{frame} 581 | 582 | \begin{frame}[fragile] 583 | \frametitle{The right scan} 584 | \begin{itemize} 585 | \item The right scan is the foldr that yields a list that contains all intermediate values 586 | \begin{minted}{haskell} 587 | scanr :: (a -> b -> b) -> b -> [a] -> [b] 588 | scanr _ ini [] = [ini] 589 | scanr f ini (x:xs) = f x q : qs 590 | where qs@(q:_) = scanr f ini xs 591 | \end{minted} 592 | \item \verb"foldr" and \verb"scanr" are connected with each other as follows 593 | \begin{center} 594 | $\verb"head (scanr f z xs)" \equiv \verb"foldr f z xs"$ 595 | \end{center} 596 | \item The examples are 597 | \begin{minted}{haskell} 598 | > scanr (:) [] [1,2,3] 599 | [[1,2,3],[2,3],[3],[]] 600 | > scanr (+) 0 [1..10] 601 | [55,54,52,49,45,40,34,27,19,10,0] 602 | > scanr (*) 1 [1..5] 603 | [120,120,60,20,5,1] 604 | \end{minted} 605 | \end{itemize} 606 | \end{frame} 607 | 608 | \begin{frame}[fragile] 609 | \frametitle{The left scan} 610 | \begin{itemize} 611 | \item One also has a scan function for the \verb"foldl" function: 612 | \begin{minted}{haskell} 613 | scanl :: (b -> a -> b) -> b -> [a] -> [b] 614 | scanl f q ls = q : (case ls of 615 | [] -> [] 616 | x:xs -> scanl f (f q x) xs) 617 | \end{minted} 618 | \item \verb"foldl" and \verb"scanl" are connected with each other as follows: 619 | \begin{center} 620 | $\verb"last (scanl f z xs)" \equiv \verb"foldl f z xs"$ 621 | \end{center} 622 | \item The examples: 623 | \begin{minted}{haskell} 624 | > scanl (++) "!" ["a","b","c"] 625 | ["!","!a","!ab","!abc"] 626 | > scanl (*) 1 [1..] !! 5 627 | 120 628 | \end{minted} 629 | \item In contrast to \verb"foldl", \verb"scanl" works with infinite lists. 630 | \end{itemize} 631 | \end{frame} 632 | 633 | \section{Strictness in Haskell} 634 | 635 | \begin{frame}[fragile] 636 | \frametitle{Bottom} 637 | 638 | \begin{itemize} 639 | \item Any well-formed expression in Haskell has a type 640 | \item Prima facie, the \verb"Bool" data type has two values: \verb"False" and \verb"True" according to its definition: 641 | \begin{minted}{haskell} 642 | data Bool = False | True 643 | \end{minted} 644 | \item One may define an expession \verb"dno :: Bool" which is defined recursively as \verb"dno = not dno" 645 | \item \verb"dno" is neither \verb"False" nor \verb"True", but it's a Boolean value! 646 | \item This value is a bottom ($\bot$). In Haskell, $\bot$ is a value that has a type \verb"forall a. a". 647 | Such errors as \verb"undefined" have this type. 648 | \end{itemize} 649 | \end{frame} 650 | 651 | \begin{frame} 652 | \frametitle{Strict functions} 653 | \begin{itemize} 654 | \item Haskell is lazy. That's why \verb"const 42 undefined == 42" 655 | \item Lazy functions are non-strict ones 656 | \onslide<2->{ 657 | \item In constrast to lazy functions, strict functions satisfy this equation 658 | \begin{center} 659 | $\verb"f" \: x_1 \: x_2 \: \dots \: \bot \: \dots \: x_n = \bot$ 660 | \end{center} 661 | \item For this reason \verb"constStrict 42 undefined = undefined" 662 | } 663 | \end{itemize} 664 | \end{frame} 665 | 666 | \begin{frame}[fragile] 667 | \frametitle{Strictness in Haskell. The \verb"seq" function} 668 | \begin{itemize} 669 | \item We've already had a look at the \verb"seq" function. 670 | \item \verb"seq" is a combinator that enforces computation. It evaluates the first argument to its WHNF. 671 | \item This combinator has a type $a \to b \to b$. 672 | \item It's quite close to something like $\lambda x y. y$, but \verb"seq" satisfies the following equations: 673 | \begin{center} 674 | $\verb"seq" \: \bot \: x = \bot$ 675 | 676 | $\verb"seq" \: v \: x = x, v \neq \bot $ 677 | \end{center} 678 | \item This function ``breaks'' our laziness! But this enforcing with \verb"seq" is not so far-reaching. 679 | Data constructors and lambdas put a barrier for the $\bot$ expansion: 680 | \begin{minted}{haskell} 681 | > seq (4,undefined) 5 682 | 5 683 | > seq (\x -> undefined) 5 684 | 5 685 | > seq (id . undefined) 5 686 | 5 687 | \end{minted} 688 | \item The library \verb"deepseq" contains the same titled combinator that evaluates the first argument completely. 689 | \end{itemize} 690 | \end{frame} 691 | 692 | \begin{frame}[fragile] 693 | \frametitle{Strictness in Haskell. The strict application} 694 | \begin{itemize} 695 | \item One may implement the strict appication using \verb"seq" 696 | \begin{minted}{haskell} 697 | infixr 0 $! 698 | ($!) :: (a -> b) -> a -> b 699 | f $! x = x `seq` f x 700 | \end{minted} 701 | \item That is, this application behaves as usual unless the second argument is the bottom. 702 | \end{itemize} 703 | \end{frame} 704 | 705 | \begin{frame}[fragile] 706 | \frametitle{Strictness in Haskell. The strict application} 707 | \begin{itemize} 708 | \item Let us recall the tail-recursive factorial. The second version is strict: 709 | \begin{minted}{haskell} 710 | tailFactorial :: Integer -> Integer 711 | tailFactorial n = helper 1 n 712 | where 713 | helper acc x = 714 | if x > 1 715 | then helper (acc * x) (x - 1) 716 | else acc 717 | 718 | tailFactorialStrict :: Integer -> Integer 719 | tailFactorialStrict n = helper 1 n 720 | where 721 | helper acc x = 722 | if x > 1 723 | then (helper $! (acc * x)) (x - 1) 724 | else acc 725 | \end{minted} 726 | \end{itemize} 727 | \end{frame} 728 | 729 | \begin{frame}[fragile] 730 | \frametitle{The strict \verb"foldl"} 731 | 732 | \begin{itemize} 733 | \item The strict version of \verb"foldl" 734 | \begin{minted}{haskell} 735 | foldl' :: (a -> b -> a) -> a -> [b] -> a 736 | foldl' f ini [] = ini 737 | foldl' f ini (x:xs) = foldl' f arg xs 738 | where arg = (f ini) $! x 739 | \end{minted} 740 | \end{itemize} 741 | \end{frame} 742 | 743 | \begin{frame}[fragile] 744 | \frametitle{Strictness in Haskell. Bang patterns} 745 | \begin{itemize} 746 | \item A data type might contain strict values with the strictness flag \verb"!", e.g. 747 | \begin{minted}{haskell} 748 | data Complex a = !a :+ !a 749 | deriving Show 750 | infix 6 :+ 751 | 752 | im :: Complex a -> a 753 | im (x :+ y) = y 754 | \end{minted} 755 | > im (undefined :+ 5) 756 | *** Exception: Prelude.undefined 757 | \begin{lstlisting}[language=Haskell] 758 | \end{lstlisting} 759 | 760 | \item The \verb"BangPatterns" extension allows one to make pattern a strict one 761 | \begin{minted}{haskell} 762 | > :set -XBangPatterns 763 | > foo !x = True 764 | > foo undefined 765 | *** Exception: Prelude.undefined 766 | \end{minted} 767 | \end{itemize} 768 | \end{frame} 769 | 770 | \begin{frame} 771 | \frametitle{Summary} 772 | 773 | Today we 774 | \begin{itemize} 775 | \item discussed the data type landscape and together with pattern matching 776 | \item studied folds 777 | \item realised how one can enforce lazy evaluation 778 | \end{itemize} 779 | 780 | \onslide<2->{ 781 | On the next seminar, we will 782 | \begin{itemize} 783 | \item study such type classes as \verb"Functor", \verb"Foldable", and \verb"Monoid" 784 | \end{itemize} 785 | } 786 | \end{frame} 787 | 788 | \end{document} 789 | -------------------------------------------------------------------------------- /Lecture4/mlem.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture4/mlem.jpeg -------------------------------------------------------------------------------- /Lecture5/Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture5/Slides.pdf -------------------------------------------------------------------------------- /Lecture5/Slides.tex: -------------------------------------------------------------------------------- 1 | \documentclass[10pt]{beamer} 2 | \usepackage[cache=false]{minted} 3 | \usepackage[utf8x]{inputenc} 4 | \usepackage{hyperref} 5 | \usepackage{fontawesome} 6 | \usepackage{graphicx} 7 | \usepackage[english,ngerman]{babel} 8 | \usepackage{bussproofs} 9 | 10 | % ------------------------------------------------------------------------------ 11 | % Use the beautiful metropolis beamer template 12 | % ------------------------------------------------------------------------------ 13 | \usepackage[T1]{fontenc} 14 | \usepackage{fontawesome} 15 | \usepackage{FiraSans} 16 | \newtheorem{defin}{Definition} 17 | \newtheorem{theor}{Theorem} 18 | \newtheorem{prop}{Proposition} 19 | \mode 20 | { 21 | \usetheme[progressbar=foot,numbering=fraction,background=light]{metropolis} 22 | \usecolortheme{default} % or try albatross, beaver, crane, ... 23 | \usefonttheme{default} % or try serif, structurebold, ... 24 | \setbeamertemplate{navigation symbols}{} 25 | \setbeamertemplate{caption}[numbered] 26 | %\setbeamertemplate{frame footer}{My custom footer} 27 | } 28 | 29 | % ------------------------------------------------------------------------------ 30 | % beamer doesn't have texttt defined, but I usually want it anyway 31 | % ------------------------------------------------------------------------------ 32 | \let\textttorig\texttt 33 | \renewcommand<>{\texttt}[1]{% 34 | \only#2{\textttorig{#1}}% 35 | } 36 | 37 | % ------------------------------------------------------------------------------ 38 | % minted 39 | % ------------------------------------------------------------------------------ 40 | 41 | 42 | % ------------------------------------------------------------------------------ 43 | % tcolorbox / tcblisting 44 | % ------------------------------------------------------------------------------ 45 | \usepackage{xcolor} 46 | \definecolor{codecolor}{HTML}{FFC300} 47 | 48 | \usepackage{tcolorbox} 49 | \tcbuselibrary{most,listingsutf8,minted} 50 | 51 | \tcbset{tcbox width=auto,left=1mm,top=1mm,bottom=1mm, 52 | right=1mm,boxsep=1mm,middle=1pt} 53 | 54 | \newtcblisting{myr}[1]{colback=codecolor!5,colframe=codecolor!80!black,listing only, 55 | minted options={numbers=left, style=tcblatex,fontsize=\tiny,breaklines,autogobble,linenos,numbersep=3mm}, 56 | left=5mm,enhanced, 57 | title=#1, fonttitle=\bfseries, 58 | listing engine=minted,minted language=r} 59 | 60 | 61 | % ------------------------------------------------------------------------------ 62 | % Listings 63 | % ------------------------------------------------------------------------------ 64 | \definecolor{mygreen}{HTML}{37980D} 65 | \definecolor{myblue}{HTML}{0D089F} 66 | \definecolor{myred}{HTML}{98290D} 67 | 68 | \usepackage{listings} 69 | 70 | % the following is optional to configure custom highlighting 71 | \lstdefinelanguage{XML} 72 | { 73 | morestring=[b]", 74 | morecomment=[s]{}, 75 | morestring=[s]{>}{<}, 76 | morekeywords={ref,xmlns,version,type,canonicalRef,metr,real,target}% list your attributes here 77 | } 78 | 79 | \lstdefinestyle{myxml}{ 80 | language=XML, 81 | showspaces=false, 82 | showtabs=false, 83 | basicstyle=\ttfamily, 84 | columns=fullflexible, 85 | breaklines=true, 86 | showstringspaces=false, 87 | breakatwhitespace=true, 88 | escapeinside={(*@}{@*)}, 89 | basicstyle=\color{mygreen}\ttfamily,%\footnotesize, 90 | stringstyle=\color{myred}, 91 | commentstyle=\color{myblue}\upshape, 92 | keywordstyle=\color{myblue}\bfseries, 93 | } 94 | 95 | 96 | % ------------------------------------------------------------------------------ 97 | % The Document 98 | % ------------------------------------------------------------------------------ 99 | \title{Functional programming, Seminar No. 5} 100 | \author{Daniel Rogozin \\ Institute for Information Transmission Problems, RAS \\ Serokell O\"{U}} 101 | \date{Higher School of Economics \\ The Faculty of Computer Science} 102 | 103 | \begin{document} 104 | 105 | \maketitle 106 | 107 | \begin{frame} 108 | \frametitle{Today} 109 | We will study 110 | \begin{center} 111 | \includegraphics[scale=0.12]{retriever.jpeg} 112 | \end{center} 113 | \end{frame} 114 | 115 | 116 | \section{Foldable} 117 | 118 | \begin{frame}[fragile] 119 | \frametitle{\verb"Semigroup" and \verb"Monoid": the definition} 120 | 121 | In this subsection, we study the generalisation of folds with the type class called \verb"Foldable". 122 | For that, we have a look at the classes called \verb"Semigroup" and \verb"Monoid". 123 | 124 | \begin{minted}{haskell} 125 | class Semigroup a where 126 | (<>) :: a -> a -> a 127 | 128 | class Semigroup a => Monoid a where 129 | mempty :: a 130 | mappend :: a -> a -> a 131 | mappend = (<>) 132 | mconcat :: [a] -> a 133 | mconcat = foldr mappend mempty 134 | \end{minted} 135 | \end{frame} 136 | 137 | \begin{frame}[fragile] 138 | \frametitle{\verb"Semigroup" and \verb"Monoid": the laws} 139 | 140 | The operation in a semigroup should associative and \verb"mempty" is the neutral element: 141 | \begin{minted}{haskell} 142 | a <> (b <> c) == (a <> b) <> c 143 | a <> mempty == a = mempty <> a 144 | \end{minted} 145 | \begin{itemize} 146 | \item NOTE BENE: every \verb"Semigroup"/\verb"Monoid" instance should obey these laws. 147 | \item The compiler is not capable of proving such properties (note that tests $\neq$ proofs), so programmers have to ensure that required laws are valid for such instances themselves. 148 | \item The moral is that declaring a \verb"Semigroup" instance where the operations happens to be non-associative is \emph{mauvais go\^{u}t}. 149 | \end{itemize} 150 | \end{frame} 151 | 152 | \begin{frame}[fragile] 153 | \frametitle{The \verb"Monoid" instances} 154 | \begin{minted}{haskell} 155 | instance Semigroup [a] where 156 | (<>) = (++) 157 | 158 | instance Monoid [a] where 159 | mempty = [] 160 | \end{minted} 161 | 162 | \verb"(++)" is associative operation and \verb"[]" is neutral. A semiformal proof: 163 | \begin{minted}{haskell} 164 | [] ++ (ys ++ zs) = ys ++ zs = ([] ++ ys) ++ zs 165 | 166 | (x : xs) ++ (ys ++ zs) = 167 | x : (xs ++ (ys ++ zs)) = -- IH 168 | x : ((xs ++ ys) ++ zs) = 169 | (x : (xs ++ ys)) ++ zs = 170 | ((x : xs) ++ ys) ++ zs 171 | \end{minted} 172 | \end{frame} 173 | 174 | \begin{frame}[fragile] 175 | \frametitle{Numbers and Booleans as monoids} 176 | 177 | \begin{minted}{haskell} 178 | newtype Sum a = Sum { getSum :: a } 179 | deriving (Show, Eq, Ord) 180 | 181 | instance Num a => Semigroup (Sum a) where 182 | Sum a <> Sum b = Sum (a + b) 183 | 184 | instance Num a => Monoid (Sum a) where 185 | mempty = Sum 0 186 | \end{minted} 187 | 188 | \vspace{\baselineskip} 189 | 190 | One has the \verb"Monoid" instance for any numerical type with the product as a binary operation. 191 | For that one needs to introduce the following new type because the same type cannot have two different instances. 192 | 193 | \begin{minted}{haskell} 194 | newtype Sum a = Sum { getSum :: a } 195 | deriving (Show, Eq, Ord) 196 | \end{minted} 197 | \end{frame} 198 | 199 | \begin{frame}[fragile] 200 | \frametitle{Numbers and Booleans as monoids} 201 | 202 | \begin{minted}{haskell} 203 | newtype All = All { getAll :: Bool } 204 | deriving (Show, Eq, Show) 205 | 206 | instance Semigroup All where 207 | All a <> All b = All (a && b) 208 | 209 | instance Monoid All where 210 | mempty = All True 211 | \end{minted} 212 | 213 | \vspace{\baselineskip} 214 | 215 | The similar for disjunction by putting \verb"a <> b = a || b" and \verb"mempty = False". 216 | \end{frame} 217 | 218 | \begin{frame}[fragile] 219 | \frametitle{Foldable: Motivation} 220 | 221 | \begin{itemize} 222 | \item Before we took a look at such fold functions as \verb"foldr" 223 | \begin{minted}{haskell} 224 | foldr :: (a -> b -> b) -> b -> [a] -> b 225 | foldr _ ini [] = [] 226 | foldr f ini (x : xs) = f x (foldr f ini xs) 227 | \end{minted} 228 | \item One may generalise the idea of folding to consider a broader class of foldable data structures 229 | \end{itemize} 230 | 231 | \end{frame} 232 | 233 | \begin{frame}[fragile] 234 | \frametitle{The \verb"Foldable" type class} 235 | \begin{minted}{haskell} 236 | class Foldable t where 237 | {-# MINIMAL foldMap | foldr #-} 238 | foldMap :: Monoid m => (a -> m) -> t a -> m 239 | foldMap f = foldr (mappend . f) mempty 240 | 241 | foldr :: (a -> b -> b) -> b -> t a -> b 242 | foldr f z t = appEndo (foldMap (Endo . f) t) z 243 | \end{minted} 244 | where 245 | \begin{minted}{haskell} 246 | newtype Endo a = Endo { appEndo :: a -> a } 247 | \end{minted} 248 | \end{frame} 249 | 250 | \begin{frame}[fragile] 251 | \frametitle{Useful functions for foldable data types} 252 | Here we provide type signatures only: 253 | \begin{minted}{haskell} 254 | toList :: Foldable t => t a -> [a] 255 | 256 | null :: Foldable => t a -> Bool 257 | 258 | length :: Foldable t => t a -> Int 259 | 260 | elem :: (Eq a, Foldable t) => a -> t a -> Bool 261 | 262 | maximum :: (Ord a, Foldable t) => t a -> a 263 | 264 | sum, product :: (Num a, Foldable t) => t a -> a 265 | \end{minted} 266 | \end{frame} 267 | 268 | \begin{frame}[fragile] 269 | \frametitle{Foldable instances} 270 | 271 | \begin{minted}{haskell} 272 | instance Foldable [] where 273 | elem = List.elem 274 | foldl = List.foldl 275 | foldr = List.foldr 276 | length = List.length 277 | maximum = List.maximum 278 | product = List.product 279 | \end{minted} 280 | \end{frame} 281 | 282 | \begin{frame}[fragile] 283 | \frametitle{Foldable instances. Other examples} 284 | 285 | \begin{minted}{haskell} 286 | instance Foldable (Either a) where 287 | foldMap _ (Left _) = mempty 288 | foldMap f (Right y) = f y 289 | 290 | foldr _ z (Left _) = z 291 | foldr f z (Right y) = f y z 292 | 293 | length (Left _) = 0 294 | length (Right _) = 1 295 | 296 | null = isLeft 297 | 298 | instance Foldable ((,) a) where 299 | foldMap f (_, y) = f y 300 | foldr f z (_, y) = f y z 301 | \end{minted} 302 | \end{frame} 303 | 304 | \begin{frame}[fragile] 305 | \frametitle{Foldable instances. Other examples} 306 | 307 | \begin{minted}{haskell} 308 | instance Foldable NonEmpty 309 | instance Foldable Set 310 | instance Foldable (Map k) 311 | instance Foldable (Array i) 312 | instance Foldable Vector 313 | \end{minted} 314 | \end{frame} 315 | 316 | \section{Functor} 317 | 318 | \begin{frame}[fragile] 319 | \frametitle{Motivation} 320 | 321 | \begin{itemize} 322 | \item Let us have a look at the following functions: 323 | \begin{minted}{haskell} 324 | map :: (a -> b) -> [a] -> [b] 325 | map _ [] = [] 326 | map f (x : xs) = f x : map f xs 327 | 328 | mapMaybe :: (a -> b) -> Maybe a -> Maybe b 329 | mapMaybe _ Nothing = Nothing 330 | mapMaybe f (Just x) = Just (f x) 331 | \end{minted} 332 | \item These function are similar. Here we have an unary function that we carry through a element of a parametrised type. 333 | \item We generalise that with the type class \verb"Functor". 334 | \end{itemize} 335 | \end{frame} 336 | 337 | \begin{frame}[fragile] 338 | \frametitle{Functor: the definition and instances} 339 | \begin{minted}{haskell} 340 | class Functor (f :: * -> *) where 341 | fmap :: (a -> b) -> (f a -> f b) 342 | 343 | instance Functor Maybe where 344 | fmap _ Nothing = Nothing 345 | fmap f (Just x) = Just (f x) 346 | 347 | instance Functor [] where 348 | fmap _ [] = [] 349 | fmap f (x : xs) = f x : map f xs 350 | \end{minted} 351 | \end{frame} 352 | 353 | \begin{frame}[fragile] 354 | \frametitle{The full definition of \verb"Functor"} 355 | 356 | \begin{minted}{haskell} 357 | class Functor (f :: * -> *) where 358 | fmap :: (a -> b) -> f a -> f b 359 | (<$) :: a -> f b -> f a 360 | (<$) = fmap . const 361 | 362 | infixl 4 <$>, <$ 363 | 364 | (<$>) :: Functor f => (a -> b) -> f a -> f b 365 | (<$>) = fmap 366 | 367 | void :: Functor f => f a -> f () 368 | void x = () <$ x 369 | \end{minted} 370 | \end{frame} 371 | 372 | \begin{frame}[fragile] 373 | \frametitle{Another example of a \verb"Functor" instance} 374 | 375 | \begin{minted}{haskell} 376 | import Data.Functor 377 | 378 | data Tree a = Leaf a | Node (Tree a) a (Tree a) 379 | deriving Show 380 | 381 | instance Functor Tree where 382 | fmap f (Leaf a) = Leaf (f a) 383 | fmap f (Node ls a rs) = Node (fmap f ls) (f a) (fmap f rs) 384 | 385 | left = Node (Leaf 2) 3 (Leaf 5) 386 | right = Node (Leaf 5) 7 (Leaf 11) 387 | tree = Node left 13 right 388 | 389 | treeWord = (\x -> show x ++ show x) <$> tree 390 | voidTree = void tree 391 | constTree = "Anna" <$ treeWord 392 | \end{minted} 393 | 394 | \end{frame} 395 | 396 | \begin{frame}[fragile] 397 | \frametitle{The \verb"DeriveFunctor" extension} 398 | 399 | One may derive the \verb"Functor" instance automatically for some data types. 400 | 401 | \begin{minted}{haskell} 402 | {-# LANGUAGE DeriveFunctor #-} 403 | 404 | import Data.Functor 405 | 406 | data Tree a = Leaf a | Node (Tree a) a (Tree a) 407 | deriving (Show, Functor) 408 | \end{minted} 409 | 410 | \vspace{\baselineskip} 411 | 412 | The derived instance in this example is equivalent to our version above. 413 | \end{frame} 414 | 415 | \begin{frame}[fragile] 416 | \frametitle{\verb"Functor" instances for two-parametric data types} 417 | 418 | Let us take a look at the \verb"Functor" for type constructors that have 419 | kind \verb"* -> * -> *". 420 | 421 | \begin{minted}{haskell} 422 | instance Functor ((,) a) where 423 | fmap f (x,y) = (x, f y) 424 | 425 | instance Functor ((->) r) where 426 | fmap = (.) 427 | 428 | instance Functor (Either a) where 429 | fmap _ (Left x) = Left x 430 | fmap f (Right y) = Right (f y) 431 | \end{minted} 432 | \end{frame} 433 | 434 | \begin{frame}[fragile] 435 | \frametitle{The \verb"Functor" laws} 436 | 437 | Any \verb"Functor" instance has to satisfy the following axioms: 438 | 439 | \begin{minted}{haskell} 440 | 441 | fmap id fx = fx 442 | 443 | fmap (f . g) fx = (fmap f . fmap g) fx 444 | \end{minted} 445 | \end{frame} 446 | 447 | \begin{frame}[fragile] 448 | \frametitle{The \verb"Functor" laws. Example} 449 | Let us check that the list data type is really a functor by induction. 450 | 451 | \begin{minted}{haskell} 452 | 453 | fmap id [] = map id [] = [] 454 | fmap id (x : xs) = 455 | id x : fmap id xs = 456 | x : fmap id xs = -- IH 457 | x : xs 458 | 459 | fmap (f . g) [] = [] 460 | fmap (f . g) (x : xs) = 461 | (f . g) x : fmap (f . g) xs = -- IH 462 | (f . g) x : (fmap f . fmap g) xs = 463 | f (g x) : fmap f (fmap g xs) 464 | \end{minted} 465 | \end{frame} 466 | 467 | \section{Applicative Functors} 468 | 469 | \begin{frame}[fragile] 470 | \frametitle{Motivation} 471 | 472 | It is clear that we would like to have something like \verb"fmap" for functions of an arbitrary arity: 473 | \begin{minted}{haskell} 474 | fmap2 475 | :: (a -> b -> c) 476 | -> f a -> f b -> f c 477 | fmap3 478 | :: (a -> b -> c -> d) 479 | -> f a -> f b -> f c -> f d 480 | fmap4 481 | :: (a -> b -> c -> d -> e) 482 | -> f a -> f b -> f c -> f d -> e 483 | ... 484 | \end{minted} 485 | We cannot do that using only \verb"fmap" for unary functions. 486 | \end{frame} 487 | 488 | \begin{frame}[fragile] 489 | \frametitle{The \verb"Applicative" class} 490 | 491 | \begin{minted}{haskell} 492 | class Functor f => Applicative f where 493 | {-# MINIMAL pure, ((<*>) | liftA2) #-} 494 | pure :: a -> f a 495 | 496 | (<*>) :: f (a -> b) -> f a -> f b 497 | (<*>) = liftA2 ($) 498 | 499 | liftA2 :: (a -> b -> c) -> f a -> f b -> f c 500 | liftA2 f x = (<*>) (fmap f x) 501 | \end{minted} 502 | \end{frame} 503 | 504 | \begin{frame}[fragile] 505 | \frametitle{The \verb"Applicative" class. A couple of examples} 506 | \begin{minted}{haskell} 507 | instance Applicative Maybe where 508 | pure = Just 509 | Nothing <*> _ = Nothing 510 | _ <*> Nothing = Nothing 511 | Just f <*> Just x = Just (f x) 512 | 513 | instance Applicative [] where 514 | pure x = [x] 515 | fs <*> fx = [ f x | f <- fs, x <- xs] 516 | \end{minted} 517 | \end{frame} 518 | 519 | \begin{frame}[fragile] 520 | \frametitle{The \verb"Applicative" laws} 521 | \begin{minted}{haskell} 522 | fmap f x = pure f <*> x 523 | 524 | pure id <*> v = v -- identity 525 | 526 | pure (.) <*> u <*> v <*> w = u <*> (v <*> w) -- composition 527 | 528 | pure f <*> pure x = pure (f x) -- homomorphism 529 | 530 | u <*> pure y = pure (\f -> f y) <*> u -- interchange 531 | \end{minted} 532 | \end{frame} 533 | 534 | \begin{frame}[fragile] 535 | \frametitle{The \verb"Applicative" class. Another \verb"Applicative" instance for lists} 536 | \begin{itemize} 537 | \item The list data type might have an alternative \verb"Applicative" instance 538 | \item Recall the function \verb"zipWith": 539 | \begin{minted}{haskell} 540 | zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] 541 | zipWith _ [] _ = [] 542 | zipWith _ _ [] = [] 543 | zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys 544 | \end{minted} 545 | \item The signature of \verb"zipWith" corresponds to the signature of \verb"liftA2" 546 | \item On the other hand, as we've already said, we cannot have two instances for the same data type 547 | \end{itemize} 548 | \end{frame} 549 | 550 | \begin{frame}[fragile] 551 | \frametitle{The \verb"Applicative" class. Another \verb"Applicative" instance for lists} 552 | \begin{minted}{haskell} 553 | newtype ZipList a = ZipList { getZipList :: [a] } 554 | 555 | instance Functor ZipList where 556 | fmap f = ZipList . getZipList . fmap f 557 | 558 | instance Applicative ZipList where 559 | liftA2 f (ZipList xs) (ZipList ys) = 560 | ZipList (zipWith f xs ys) 561 | zipF <*> zipX = liftA2 ($) 562 | pure = ??? 563 | \end{minted} 564 | 565 | How to implement \verb"pure" and preverse the applicative laws? 566 | If we define \verb"pure" as below, that would break all axioms of an applicative functor. 567 | \begin{minted}{haskell} 568 | pure x = ZipList [x] 569 | \end{minted} 570 | 571 | \end{frame} 572 | 573 | \begin{frame}[fragile] 574 | \frametitle{The \verb"Applicative" class. Another \verb"Applicative" instance for lists} 575 | 576 | \begin{itemize} 577 | \item Here is the proper instance: 578 | \begin{minted}{haskell} 579 | instance Applicative ZipList where 580 | liftA2 f (ZipList xs) (ZipList ys) = 581 | ZipList (zipWith f xs ys) 582 | zipF <*> zipX = liftA2 ($) 583 | pure a = ZipList $ iterate x 584 | where iterate x = x : iterate x 585 | \end{minted} 586 | \end{itemize} 587 | \end{frame} 588 | 589 | \begin{frame}[fragile] 590 | \frametitle{\verb"Applicative" instance for tuples} 591 | 592 | The \verb"Monoid" type class allows one to have the \verb"Applicative" instance for 593 | tuples as follows: 594 | 595 | \begin{minted}{haskell} 596 | instance Monoid a => Applicative ((,) a) where 597 | pure x = (mempty x, x) 598 | (a, f) <*> (b, x) = (a <> b, f x) 599 | \end{minted} 600 | 601 | \end{frame} 602 | 603 | \section{Traversable} 604 | 605 | \begin{frame}[fragile] 606 | \frametitle{The motivating example} 607 | \begin{minted}{haskell} 608 | dist :: Applicative f => [f a] -> f [a] 609 | dist [] = pure [] 610 | dist (x : xs) = liftA2 (:) x (dist xs) 611 | \end{minted} 612 | 613 | \begin{minted}{haskell} 614 | > dist (Just <$> [1,2,4]) 615 | Just [1,2,4] 616 | > dist [Just 1, Nothing] 617 | Nothing 618 | > getZipList $ dist $ map ZipList [[1,2,3], [4,5,6], [7,8,9]] 619 | [[1,4,7],[2,5,8],[3,6,9]] 620 | \end{minted} 621 | 622 | \end{frame} 623 | 624 | \begin{frame}[fragile] 625 | \frametitle{The \verb"Traversable" definition} 626 | 627 | According to the documentation, \verb"Traversable" describes ``functors representing data structures that can be traversed from left to right''. 628 | 629 | \begin{minted}{haskell} 630 | class (Functor t, Foldable t) => Traversable t where 631 | traverse :: Applicative f => (a -> f b) -> t a -> f (t b) 632 | traverse f = sequenceA . fmap f 633 | 634 | sequenceA :: Applicative f => t (f a) -> f (t a) 635 | sequenceA = traverse id 636 | {-# MINIMAL traverse | sequenceA #-} 637 | \end{minted} 638 | \end{frame} 639 | 640 | \begin{frame}[fragile] 641 | \frametitle{The \verb"Traversable" instances} 642 | 643 | \begin{minted}{haskell} 644 | instance Travesable Maybe where 645 | traverse _ Nothing = Nothing 646 | traverse f (Just x) = Just <$> f x 647 | 648 | instace Traversable [] where 649 | traverse _ g = foldr consF (pure []) 650 | where 651 | consF x ys = liftA2 (:) (g x) ys 652 | \end{minted} 653 | \end{frame} 654 | 655 | \section{Summary} 656 | 657 | \begin{frame} 658 | \frametitle{Summary} 659 | 660 | Today we 661 | \begin{itemize} 662 | \item introduced such type classes as \verb"Functor", \verb"Applicative", \verb"Monoid", \verb"Foldable", 663 | and \verb"Traversable" 664 | \end{itemize} 665 | 666 | \onslide<2->{ 667 | Next time, we will 668 | \begin{itemize} 669 | \item study monads! 670 | \end{itemize} 671 | } 672 | \end{frame} 673 | 674 | \end{document} 675 | -------------------------------------------------------------------------------- /Lecture5/retriever.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture5/retriever.jpeg -------------------------------------------------------------------------------- /Lecture6/Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture6/Slides.pdf -------------------------------------------------------------------------------- /Lecture6/Slides.tex: -------------------------------------------------------------------------------- 1 | \documentclass[10pt]{beamer} 2 | \usepackage[cache=false]{minted} 3 | \usepackage[utf8x]{inputenc} 4 | \usepackage{hyperref} 5 | \usepackage{fontawesome} 6 | \usepackage{graphicx} 7 | \usepackage[english,ngerman]{babel} 8 | \usepackage{bussproofs} 9 | 10 | % ------------------------------------------------------------------------------ 11 | % Use the beautiful metropolis beamer template 12 | % ------------------------------------------------------------------------------ 13 | \usepackage[T1]{fontenc} 14 | \usepackage{fontawesome} 15 | \usepackage{FiraSans} 16 | \newtheorem{defin}{Definition} 17 | \newtheorem{theor}{Theorem} 18 | \newtheorem{prop}{Proposition} 19 | \mode 20 | { 21 | \usetheme[progressbar=foot,numbering=fraction,background=light]{metropolis} 22 | \usecolortheme{default} % or try albatross, beaver, crane, ... 23 | \usefonttheme{default} % or try serif, structurebold, ... 24 | \setbeamertemplate{navigation symbols}{} 25 | \setbeamertemplate{caption}[numbered] 26 | %\setbeamertemplate{frame footer}{My custom footer} 27 | } 28 | 29 | % ------------------------------------------------------------------------------ 30 | % beamer doesn't have texttt defined, but I usually want it anyway 31 | % ------------------------------------------------------------------------------ 32 | \let\textttorig\texttt 33 | \renewcommand<>{\texttt}[1]{% 34 | \only#2{\textttorig{#1}}% 35 | } 36 | 37 | % ------------------------------------------------------------------------------ 38 | % minted 39 | % ------------------------------------------------------------------------------ 40 | 41 | 42 | % ------------------------------------------------------------------------------ 43 | % tcolorbox / tcblisting 44 | % ------------------------------------------------------------------------------ 45 | \usepackage{xcolor} 46 | \definecolor{codecolor}{HTML}{FFC300} 47 | 48 | \usepackage{tcolorbox} 49 | \tcbuselibrary{most,listingsutf8,minted} 50 | 51 | \tcbset{tcbox width=auto,left=1mm,top=1mm,bottom=1mm, 52 | right=1mm,boxsep=1mm,middle=1pt} 53 | 54 | \newtcblisting{myr}[1]{colback=codecolor!5,colframe=codecolor!80!black,listing only, 55 | minted options={numbers=left, style=tcblatex,fontsize=\tiny,breaklines,autogobble,linenos,numbersep=3mm}, 56 | left=5mm,enhanced, 57 | title=#1, fonttitle=\bfseries, 58 | listing engine=minted,minted language=r} 59 | 60 | 61 | % ------------------------------------------------------------------------------ 62 | % Listings 63 | % ------------------------------------------------------------------------------ 64 | \definecolor{mygreen}{HTML}{37980D} 65 | \definecolor{myblue}{HTML}{0D089F} 66 | \definecolor{myred}{HTML}{98290D} 67 | 68 | \usepackage{listings} 69 | 70 | % the following is optional to configure custom highlighting 71 | \lstdefinelanguage{XML} 72 | { 73 | morestring=[b]", 74 | morecomment=[s]{}, 75 | morestring=[s]{>}{<}, 76 | morekeywords={ref,xmlns,version,type,canonicalRef,metr,real,target}% list your attributes here 77 | } 78 | 79 | \lstdefinestyle{myxml}{ 80 | language=XML, 81 | showspaces=false, 82 | showtabs=false, 83 | basicstyle=\ttfamily, 84 | columns=fullflexible, 85 | breaklines=true, 86 | showstringspaces=false, 87 | breakatwhitespace=true, 88 | escapeinside={(*@}{@*)}, 89 | basicstyle=\color{mygreen}\ttfamily,%\footnotesize, 90 | stringstyle=\color{myred}, 91 | commentstyle=\color{myblue}\upshape, 92 | keywordstyle=\color{myblue}\bfseries, 93 | } 94 | 95 | 96 | % ------------------------------------------------------------------------------ 97 | % The Document 98 | % ------------------------------------------------------------------------------ 99 | \title{Functional programming, Seminar No. 6} 100 | \author{Daniel Rogozin \\ Institute for Information Transmission Problems, RAS \\ Serokell O\"{U}} 101 | 102 | \vspace{\baselineskip} 103 | 104 | \date{Higher School of Economics \\ The Department of Computer Science} 105 | 106 | \begin{document} 107 | 108 | \maketitle 109 | 110 | \begin{frame} 111 | \frametitle{Today} 112 | 113 | We will study 114 | \begin{center} 115 | \includegraphics[scale=0.3]{monads.png} 116 | \end{center} 117 | \end{frame} 118 | 119 | \section{Monads} 120 | 121 | \begin{frame} 122 | \frametitle{Motivation} 123 | 124 | We are going to extend pure functions \verb"a -> b", 125 | we would like to extend them to computations with effects: 126 | \begin{itemize} 127 | \item A computation with a possible failure: \verb"a -> Maybe b" 128 | \item A many-valued computation: \verb"a -> [b]" 129 | \item A computation either succeeds or yields an error: \verb"a -> Either e b" 130 | \item A computation with logs: \verb"a -> (s, b)" 131 | \item A computation with reading from an external environment \verb"a -> (e -> b)" 132 | \item A computation with a mutable state: \verb"a -> (State s) b" 133 | \item An input/output computation: \verb"a -> IO b" 134 | \end{itemize} 135 | \end{frame} 136 | 137 | \begin{frame}[fragile] 138 | \frametitle{Motivation} 139 | 140 | If one needs to provide a uniform interface to deal with Kreisli functions, then this interface should satisfy the following two requirements. 141 | 142 | \begin{enumerate} 143 | \item One needs to have an opportunity inject a pure value into the 144 | computational context 145 | \item Kleisli maps should be composable: 146 | \begin{minted}{haskell} 147 | (>=>) :: (a -> m b) -> (b -> m c) -> a -> m c 148 | \end{minted} 149 | \item Generally, we \alert{cannot} extract \verb"a" from \verb"m a" 150 | \end{enumerate} 151 | \end{frame} 152 | 153 | \begin{frame}[fragile] 154 | \frametitle{The definition of the \verb"Monad" class} 155 | 156 | Let us take a look the full definition of the \verb"Monad" class 157 | 158 | \begin{minted}{haskell} 159 | class Applicative m => Monad m where 160 | -- | Sequentially compose two actions, 161 | -- | passing any value produced 162 | -- | by the first as an argument to the second. 163 | (>>=) :: m a -> (a -> m b) -> m b 164 | 165 | -- | Sequentially compose two actions, 166 | -- |discarding any value produced by the first 167 | (>>) :: m a -> m b -> m b 168 | m >> k = m >>= \_ -> k 169 | 170 | -- | Inject a value into the monadic type. 171 | return :: a -> m a 172 | return = pure 173 | \end{minted} 174 | \end{frame} 175 | 176 | \begin{frame}[fragile] 177 | \frametitle{The definition of the \verb"Monad" class} 178 | The \verb"Monad" class has the equivalent definition, the following one: 179 | \begin{minted}{haskell} 180 | class Applicative m => Monad m where 181 | join :: m (m a) -> m a 182 | \end{minted} 183 | \onslide<2->{ 184 | Moreover, such a definition is closer to the original categorical definition 185 | of a monad. But we do not care about categories here. 186 | } 187 | \end{frame} 188 | 189 | \begin{frame}[fragile] 190 | \frametitle{The \verb"return" function} 191 | 192 | One may convert any pure function into a Kleisli one: 193 | \begin{minted}{haskell} 194 | toKleisli :: Monad m => (a -> b) -> a -> m b 195 | toKleisli f = return . f 196 | 197 | cosM :: (Monad m, Floating b) => b -> m b 198 | cosM = toKleisli cos 199 | \end{minted} 200 | 201 | It is clear that $\cos \pi = - 1$, but \verb"cosM pi" has the type \verb"(Monad m, Floating b) => m b" and we have several variants: 202 | \begin{minted}{haskell} 203 | > cosM pi :: Maybe Double 204 | Just (-1.0) 205 | > cosM pi :: [Double] 206 | [-1.0] 207 | > cosM pi :: IO (Double) 208 | -1.0 209 | > cosM pi :: Either String Double 210 | Right (-1.0) 211 | \end{minted} 212 | \end{frame} 213 | 214 | \begin{frame}[fragile] 215 | \frametitle{The monadic bind operator} 216 | 217 | Take a look at the monadic type signature closer: 218 | \begin{minted}{haskell} 219 | (>>=) :: Monad m => m a -> (a -> m b) -> m b 220 | \end{minted} 221 | 222 | 223 | In some sense, it is quite close to the reverse application operator. 224 | \vspace{\baselineskip} 225 | \begin{minted}{haskell} 226 | (&) :: a -> (a -> b) -> b 227 | x & f = f x 228 | \end{minted} 229 | 230 | \end{frame} 231 | 232 | \begin{frame}[fragile] 233 | \frametitle{The monadic bind operator} 234 | 235 | Let's have a look at this analogy closely: 236 | \begin{minted}{haskell} 237 | fmap :: Functor f => (a -> b) -> f a -> f b 238 | (<*>) :: Applicative f => f (a -> b) -> f a -> f b 239 | flip (>>=) :: Monad m => (a -> m b) -> m a -> m b 240 | \end{minted} 241 | 242 | \vspace{\baselineskip} 243 | 244 | Flipped \verb"fmap", flipped \verb"(<*>)" and \verb"(>>=)": 245 | \begin{minted}{haskell} 246 | flip fmap :: Functor f => f a -> (a -> b) -> f b 247 | flip (<*>) :: Applicative f => f a -> f (a -> b) -> f b 248 | (>>=) :: Monad m => m a -> (a -> m b) -> m b 249 | \end{minted} 250 | \end{frame} 251 | 252 | \begin{frame}[fragile] 253 | \frametitle{The very first (trivial) monad. The \verb"Identity" type} 254 | 255 | Let us define the following new type 256 | \begin{minted}{haskell} 257 | {-# LANGUAGE DeriveFunctor #-} 258 | 259 | newtype Identity a = Identity { runIdentity :: a } 260 | deriving (Show, Functor) 261 | 262 | instance Applicative Identity where 263 | pure = Identity 264 | Identity f <*> Identity x = Identity (f x) 265 | 266 | instance Monad Identity where 267 | Identity x >>= k = k x 268 | \end{minted} 269 | 270 | This is a trivial monad. 271 | \end{frame} 272 | 273 | \begin{frame}[fragile] 274 | \frametitle{Playing with the \verb"Identity" monad} 275 | 276 | Let us consider a quite trivial example of a Kleisli function 277 | 278 | \begin{minted}{haskell} 279 | cosId, acosId, sinM 280 | :: Double -> Identity Double 281 | cosId = Identity . cos 282 | acosId = Identity . acos 283 | sinM = Identity . sin 284 | \end{minted} 285 | 286 | \vspace{\baselineskip} 287 | 288 | An example: 289 | 290 | \begin{minted}{haskell} 291 | > runIdentity $ cosId pi >>= acosId 292 | -1.0 293 | > runIdentity $ cosId pi >>= acosId 294 | 3.141592653589793 295 | > runIdentity $ cosId (pi/2) >>= acosId >>= sinM 296 | 1.0 297 | \end{minted} 298 | 299 | In fact, \verb">>=" works similarly to \verb"(&)" in this example. 300 | \end{frame} 301 | 302 | \begin{frame}[fragile] 303 | \frametitle{Some of useful monadic functions} 304 | 305 | Let us take a look at some widely used monadic operations: 306 | 307 | \begin{minted}{haskell} 308 | (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c) 309 | f >=> g = \x -> f x >>= g 310 | 311 | join :: Monad m => m (m a) -> m a 312 | join x = x >>= id 313 | 314 | forever :: Applicative f => f a -> f b 315 | forever a = let a' = a *> a' in a' 316 | \end{minted} 317 | 318 | \end{frame} 319 | 320 | \begin{frame}[fragile] 321 | \frametitle{Monadic laws} 322 | 323 | Any monad satisfies the following law: 324 | 325 | \begin{enumerate} 326 | \item The left identity law: 327 | \begin{minted}{haskell} 328 | return a >>= k = k a 329 | \end{minted} 330 | \item The right identity law: 331 | \begin{minted}{haskell} 332 | m >>= return = m 333 | \end{minted} 334 | \item The monadic bind operation is associative: 335 | \begin{minted}{haskell} 336 | m >>= (\x -> k x >>= h) = (m >>= k) >>= h 337 | \end{minted} 338 | \item There is the strong connection between the notions of monad and monoid, but we drop this connection. 339 | \item Let us illustrate these laws with the \verb"Identity" monad 340 | \end{enumerate} 341 | \end{frame} 342 | 343 | \begin{frame}[fragile] 344 | \frametitle{The identity laws} 345 | According to the identity laws: 346 | \begin{minted}{haskell} 347 | return a >>= k = k a 348 | m >>= return = m 349 | \end{minted} 350 | the \verb"return" function is a sort of a neutral element: 351 | 352 | \begin{minted}{haskell} 353 | > runIdentity $ cosId (pi / 4) 354 | 0.7071067811865476 355 | > runIdentity $ return (pi / 4) >>= cosId 356 | 0.7071067811865476 357 | > runIdentity $ cosId (pi / 4) >>= return 358 | 0.7071067811865476 359 | \end{minted} 360 | \end{frame} 361 | 362 | \begin{frame}[fragile] 363 | \frametitle{The associativity law} 364 | 365 | The associative law: 366 | \begin{minted}{haskell} 367 | m >>= (\x -> k x >>= h) = (m >>= k) >>= h 368 | \end{minted} 369 | 370 | claims that the monadic bind is associative as follows: 371 | \begin{minted}{haskell} 372 | > runIdentity $ cosId (pi/2) >>= acosId >>= sinM 373 | 1.0 374 | > runIdentity $ cosId (pi/2) >>= (\x -> acosId x >>= sinM) 375 | 1.0 376 | \end{minted} 377 | \end{frame} 378 | 379 | \begin{frame}[fragile] 380 | \frametitle{The associativity law} 381 | Let us take a look at these equivalent pipelines: 382 | \begin{minted}{haskell} 383 | go = cosId (pi/2) >>= 384 | acosId >>= 385 | sinM 386 | \end{minted} 387 | 388 | \begin{minted}{haskell} 389 | go2 = cosId (pi/2) >>= (\x -> 390 | acosId x >>= (\y -> 391 | sinM y >>= \z -> 392 | return z)) 393 | \end{minted} 394 | \end{frame} 395 | 396 | \begin{frame}[fragile] 397 | \frametitle{Monads and pseudo-imperative programming} 398 | \begin{minted}{haskell} 399 | go2 = cosId (pi/2) >>= (\x -> 400 | acosId x >>= (\y -> 401 | sinM y >>= \z -> 402 | return z)) 403 | \end{minted} 404 | 405 | \begin{minted}{haskell} 406 | go2 = cosId (pi/2) >>= (\x -> 407 | acosId x >>= (\y -> 408 | sinM y >>= \z -> 409 | return (x, y, z))) 410 | \end{minted} 411 | 412 | \alert{Wow, we have recently invented imperative programming!} 413 | \end{frame} 414 | 415 | \begin{frame}[fragile] 416 | \frametitle{Monads and pseudoimperative programming} 417 | We may ignore one of the results: 418 | \begin{minted}{haskell} 419 | go2 = let alpha = pi/2 in 420 | cosId alpha >>= (\x -> 421 | acosId x >>= (\y -> 422 | sinM y >> 423 | return (alpha, x, y))) 424 | \end{minted} 425 | \end{frame} 426 | 427 | \begin{frame}[fragile] 428 | \frametitle{do-Notation} 429 | 430 | In Haskell, one has a quite useful syntax sugar to write code 431 | within a monad in the ``imperative'' fashion. 432 | 433 | \begin{columns} 434 | \column{0.5\textwidth} 435 | \metroset{block=fill} 436 | \begin{exampleblock}{do-expression} 437 | \begin{minted}{haskell} 438 | do { e1; e2 } 439 | \end{minted} 440 | \end{exampleblock} 441 | 442 | \begin{exampleblock}{do-expression} 443 | \begin{minted}{haskell} 444 | do { p <- e1; e2 } 445 | \end{minted} 446 | \end{exampleblock} 447 | 448 | \begin{exampleblock}{do-expression} 449 | \begin{minted}{haskell} 450 | do { let v = e1; e2 } 451 | \end{minted} 452 | \end{exampleblock} 453 | \column{0.5\textwidth} 454 | \metroset{block=fill} 455 | \begin{exampleblock}{Unsugared version} 456 | \begin{minted}{haskell} 457 | e1 >> e2 458 | \end{minted} 459 | \end{exampleblock} 460 | 461 | \begin{exampleblock}{Unsugared version} 462 | \begin{minted}{haskell} 463 | e1 >>= \p -> e2 464 | \end{minted} 465 | \end{exampleblock} 466 | 467 | \begin{exampleblock}{Unsugared version} 468 | \begin{minted}{haskell} 469 | let v = e1 in do e2 470 | \end{minted} 471 | \end{exampleblock} 472 | \end{columns} 473 | \end{frame} 474 | 475 | \begin{frame}[fragile] 476 | \frametitle{do-Notation. Example} 477 | The example above: 478 | \begin{minted}{haskell} 479 | go2 = let alpha = pi/2 in 480 | cosId alpha >>= (\x -> 481 | acosId x >>= (\y -> 482 | sinM y >> 483 | return (alpha, x, y))) 484 | \end{minted} 485 | 486 | One may rewrite this example using do-notation: 487 | \begin{minted}{haskell} 488 | go2 = do 489 | let alpha = pi/2 490 | x <- cosId alpha 491 | y <- acosId x 492 | z <- sinM y 493 | return (alpha, x, y) 494 | \end{minted} 495 | \end{frame} 496 | 497 | \begin{frame}[fragile] 498 | \frametitle{do-Notation. Example} 499 | Let us consider an example of a monadic function: 500 | \begin{minted}{haskell} 501 | prodM :: Monad m => (a -> m b) -> (c -> m d) 502 | -> m (a, c) -> m (b, d) 503 | prodM f g mp = 504 | mp >>= \(a,b) -> f a >>= \c -> g b >>= \d -> 505 | return (c, d) 506 | \end{minted} 507 | The function above can be implemented as follows: 508 | \begin{minted}{haskell} 509 | prodM :: Monad m => (a -> m b) -> (c -> m d) 510 | -> m (a, c) -> m (b, d) 511 | prodM f g mp = do 512 | (a, b) <- mp 513 | c <- f a 514 | d <- g b 515 | return (c, d) 516 | \end{minted} 517 | \end{frame} 518 | 519 | \section{The Maybe monad} 520 | 521 | \begin{frame}[fragile] 522 | \frametitle{The Maybe monad} 523 | 524 | The \verb"Maybe" data type is one of the simplest non-trivial monads. 525 | \begin{minted}{haskell} 526 | instance Monad Maybe where 527 | return = Just 528 | 529 | Nothing >>= _ = Nothing 530 | (Just x) >>= f = f x 531 | 532 | (Just _) >> a = a 533 | Nothing >> _ = Nothing 534 | \end{minted} 535 | \end{frame} 536 | 537 | \begin{frame}[fragile] 538 | \frametitle{The Maybe monad. Example} 539 | \begin{minted}{haskell} 540 | type Author = String 541 | type Book = String 542 | type Library = [(Author, Book)] 543 | 544 | books :: [Book] 545 | books = ["Faust", "Alice in Wonderland", "The Idiot"] 546 | 547 | authors :: [Author] 548 | authors = ["Goethe", "Carroll", "Dostoevsky"] 549 | 550 | library :: Library 551 | library = zip authors books 552 | \end{minted} 553 | \end{frame} 554 | 555 | \begin{frame}[fragile] 556 | \frametitle{The Maybe monad. Example} 557 | \begin{minted}{haskell} 558 | library' :: Library 559 | library' = ("Dostoevsky", "Demons") : 560 | ("Dostoevsky", "White Nights") : library 561 | 562 | getBook :: Author -> Library -> Maybe Book 563 | getBook author library = lookup author library 564 | 565 | getSecondbook, getLastBook :: Author -> Maybe Book 566 | getFirstbook author = do 567 | let lib' = filter (\p -> fst p == author) library' 568 | book <- getBook author lib' 569 | return book 570 | 571 | getLastBook author = do 572 | let lib' = filter (\p -> fst p == author) library' 573 | book <- getBook author (reverse lib') 574 | return book 575 | \end{minted} 576 | \end{frame} 577 | 578 | \section{The list monad} 579 | 580 | \begin{frame}[fragile] 581 | \frametitle{The list instance} 582 | 583 | The \verb"Monad" instance is the following one: 584 | 585 | \begin{minted}{haskell} 586 | instance Monad [] where 587 | return x = [x] 588 | xs >>= k = concat (map k xs) 589 | \end{minted} 590 | \end{frame} 591 | 592 | \begin{frame}[fragile] 593 | \frametitle{List compeherension once more} 594 | 595 | The following functions are equivalent: 596 | \begin{minted}{haskell} 597 | cartesianProduct :: [a] -> [b] -> [(a, b)] 598 | cartesianProduct xs ys = 599 | xs >>= \x -> ys >>= \y -> return (x, y) 600 | 601 | cartesianProduct' :: [a] -> [b] -> [(a, b)] 602 | cartesianProduct' xs ys = do 603 | x <- xs 604 | y <- ys 605 | return (x, y) 606 | 607 | cartesianProduct'' :: [a] -> [b] -> [(a, b)] 608 | cartesianProduct'' xs ys = [(x, y) | x <- xs, y <- ys] 609 | \end{minted} 610 | \end{frame} 611 | 612 | \end{document} 613 | -------------------------------------------------------------------------------- /Lecture6/monads.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture6/monads.png -------------------------------------------------------------------------------- /Lecture7/Seminar7.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveFunctor #-} 2 | 3 | module Seminar7 where 4 | 5 | import Control.Monad 6 | import Control.Applicative 7 | 8 | toKleisli :: Monad m => (a -> b) -> a -> m b 9 | toKleisli f = return . f 10 | 11 | cosM :: (Monad m, Floating b) => b -> m b 12 | cosM = toKleisli cos 13 | 14 | newtype Identity a = Identity { runIdentity :: a } 15 | deriving (Show, Functor) 16 | 17 | instance Applicative Identity where 18 | pure = Identity 19 | Identity f <*> Identity x = Identity (f x) 20 | 21 | instance Monad Identity where 22 | Identity x >>= k = k x 23 | 24 | cosId, acosId, sinM 25 | :: Double -> Identity Double 26 | cosId = Identity . cos 27 | acosId = Identity . acos 28 | sinM = Identity . sin 29 | 30 | 31 | go = cosId (pi/2) >>= acosId >>= sinM 32 | 33 | go2 = cosId (pi/2) >>= (\x -> 34 | acosId x >>= (\y -> 35 | sinM y >>= \z -> 36 | return z)) 37 | 38 | go2' = cosId (pi/2) >>= (\x -> 39 | acosId x >>= (\y -> 40 | sinM y >>= \z -> 41 | return (x, y, z))) 42 | 43 | go2'' = let alpha = pi/2 in 44 | cosId alpha >>= (\x -> 45 | acosId x >>= (\y -> 46 | sinM y >> 47 | return (alpha, x, y))) 48 | 49 | go2''' = do 50 | let alpha = pi/2 51 | x <- cosId alpha 52 | y <- acosId x 53 | z <- sinM y 54 | return (alpha, x, y) 55 | 56 | prodM :: Monad m => (a -> m b) -> (c -> m d) 57 | -> m (a, c) -> m (b, d) 58 | prodM f g mp = 59 | mp >>= \(a,b) -> f a >>= \c -> g b >>= \d -> return (c, d) 60 | 61 | prodM' :: Monad m => (a -> m b) -> (c -> m d) 62 | -> m (a, c) -> m (b, d) 63 | prodM' f g mp = do 64 | (a, b) <- mp 65 | c <- f a 66 | d <- g b 67 | return (c, d) 68 | 69 | type Author = String 70 | 71 | type Book = String 72 | 73 | type Library = [(Author, Book)] 74 | 75 | books :: [Book] 76 | books = ["Faust", "Alice in Wonderland", "The Idiot"] 77 | 78 | authors :: [Author] 79 | authors = ["Goethe", "Carroll", "Dostoevsky"] 80 | 81 | library :: Library 82 | library = zip authors books 83 | 84 | library' :: Library 85 | library' = ("Dostoevsky", "Demons") : 86 | ("Dostoevsky", "White Nights") : library 87 | 88 | getBook :: Author -> Library -> Maybe Book 89 | getBook author library = lookup author library 90 | 91 | getFirstbook, getLastBook :: Author -> Maybe Book 92 | getFirstbook author = do 93 | let lib' = filter (\p -> fst p == author) library' 94 | book <- getBook author lib' 95 | return book 96 | getLastBook author = do 97 | let lib' = filter (\p -> fst p == author) library' 98 | book <- getBook author (reverse lib') 99 | return book 100 | 101 | {- 102 | (>>=) :: [a] -> (a -> [b]) -> [b] 103 | xs >>= k = concat (map k xs) 104 | 105 | xs :: [a] 106 | k :: a -> [b] 107 | 108 | concat :: forall a. [[a]] -> [a] 109 | 110 | map k xs :: [[b]] 111 | concat (map k xs) :: [b] 112 | -} 113 | 114 | cartesianProduct :: [a] -> [b] -> [(a, b)] 115 | cartesianProduct xs ys = 116 | xs >>= \x -> ys >>= \y -> return (x, y) 117 | 118 | cartesianProduct' :: [a] -> [b] -> [(a, b)] 119 | cartesianProduct' xs ys = do 120 | x <- xs 121 | y <- ys 122 | return (x, y) 123 | 124 | cartesianProduct'' :: [a] -> [b] -> [(a, b)] 125 | cartesianProduct'' xs ys = [(x, y) | x <- xs, y <- ys] 126 | 127 | main :: IO () 128 | main = do 129 | putStrLn "Hello, what is your name?" 130 | name <- getLine 131 | putStrLn $ "Hi, " ++ name 132 | putStrLn $ 133 | "Gotta go, " ++ name ++ 134 | ", have a nice day" 135 | 136 | getLine' :: IO String 137 | getLine' = do 138 | c <- getChar 139 | case c == '\n' of 140 | True -> return [] 141 | False -> do 142 | cs <- getLine' 143 | return (c : cs) 144 | 145 | putStr' :: String -> IO () 146 | putStr' [] = return () 147 | putStr' (x : xs) = putChar x >> putStr' xs 148 | 149 | putStr'' :: String -> IO () 150 | putStr'' = sequence_ . map putChar 151 | 152 | putStr''' :: String -> IO () 153 | putStr''' = mapM_ putChar 154 | 155 | {- 156 | foo = 157 | do { e1 ; e2 } 158 | 159 | foo = do 160 | e1 161 | e2 162 | 163 | foo' = e1 >>= \p -> e2 164 | 165 | foo'' = 166 | do { p <- e1; e2 } 167 | 168 | foo''' = do 169 | p <- e1 170 | e2 -- p might occur in e2 somehow 171 | 172 | foo = let v = e1 in do e2 173 | 174 | foo' = do { let v = e1; e2 } 175 | 176 | foo'' = do 177 | let v = e1 178 | e2 -- v might occur in e2 somehow 179 | -} 180 | {- 181 | instance Monad IO where 182 | return :: a -> IO a 183 | return x = IO $ \w -> (w, x) 184 | 185 | (>>=) :: IO a -> (a -> IO b) -> IO b 186 | -- m :: IO a <-> RealWorld -> (RealWorld, a) 187 | -- k :: a -> IO b <-> a -> (RealWorld -> (RealWorld, b)) 188 | 189 | -- we have to return IO b, that is, 190 | -- RealWorld -> (RealWorld, b) 191 | 192 | -- w :: RealWorld 193 | -- m w :: (RealWorld, a) 194 | -- (w', x) :: (RealWorld, a) 195 | m >>= k = IO $ \w -> 196 | case m w of 197 | (w', x) -> k x w' 198 | -} 199 | 200 | newtype Reader r a = Reader { runReader :: r -> a } 201 | 202 | instance Functor (Reader r) where 203 | -- fmap :: (a -> b) -> Reader r a -> Reader r b 204 | -- f :: a -> b, g :: r -> a 205 | fmap f (Reader g) = Reader $ f . g 206 | 207 | instance Applicative (Reader r) where 208 | -- pure :: a -> Reader r a 209 | pure x = Reader $ const x 210 | 211 | -- (<*>) :: Reader r (a -> b) -> Reader r a -> Reader r b 212 | -- f :: r -> a -> b 213 | -- g :: r -> a 214 | -- smth :: r -> b 215 | Reader f <*> Reader g = Reader $ (\x -> f x (g x)) 216 | 217 | instance Monad (Reader r) where 218 | -- (>>=) :: Reader r a -> (a -> Reader r b) -> Reader r b 219 | -- runReader f :: r -> a 220 | -- e :: r 221 | -- v = runReader f e :: a 222 | 223 | -- k :: a -> Reader r b 224 | -- k v :: Reader r b 225 | -- runReader (k v) :: r -> b 226 | -- runReader (k v) e :: b 227 | -- Reader r b 228 | f >>= k = 229 | Reader $ \e -> let v = runReader f e in runReader (k v) e 230 | 231 | ask :: Reader e e 232 | ask = Reader id 233 | 234 | asks :: (e -> a) -> Reader e a 235 | asks f = Reader f 236 | 237 | local :: (e -> b) -> Reader b a -> Reader e a 238 | local f m = Reader $ runReader m . f 239 | 240 | type Id = Int 241 | 242 | data Environment = Environment { ids :: [Id] 243 | , name :: Id -> String 244 | , near :: Id -> (Id, Id) } 245 | 246 | inEnv :: Id -> Reader Environment Bool 247 | inEnv i = asks (elem i . ids) 248 | 249 | anyInEnv :: (Id, Id) -> Reader Environment Bool 250 | anyInEnv (i, j) = inEnv i ||^ inEnv j 251 | where 252 | -- Bool -> Bool -> Bool 253 | -- Reader Env Bool -> Reader Env Bool -> Reader Env Bool 254 | (||^) = liftA2 (||) 255 | 256 | env = Environment [1..10] (\x -> "This is " ++ show x) (\x -> (x - 1, x + 1)) 257 | 258 | checkNeighbours :: Id -> Reader Environment (Maybe String) 259 | checkNeighbours i = 260 | asks (`near` i) >>= \pair -> 261 | anyInEnv pair >>= \res -> 262 | if res 263 | then Just <$> asks (`name` i) 264 | else pure Nothing 265 | 266 | greeter :: Reader String String 267 | greeter = do 268 | name <- ask 269 | return ("hello, " ++ name ++ "!") 270 | 271 | type Bindings = [(String,Int)] 272 | -- Returns True if the "count" variable contains correct bindings size. 273 | isCountCorrect :: Bindings -> Bool 274 | isCountCorrect bindings = runReader calc_isCountCorrect bindings 275 | 276 | -- The Reader monad, which implements this complicated check. 277 | calc_isCountCorrect :: Reader Bindings Bool 278 | calc_isCountCorrect = do 279 | count <- asks (lookupVar "count") 280 | bindings <- ask 281 | return (count == length bindings) 282 | 283 | -- lookup :: Eq a => a -> [(a,b)] -> Maybe b 284 | 285 | lookupVar :: String -> Bindings -> Int 286 | lookupVar name bindings = maybe 0 id (lookup name bindings) 287 | 288 | sampleBindings = [("1",1), ("b",2)] 289 | 290 | action = do 291 | putStr $ "Count is correct for bindings " ++ (show sampleBindings) ++ ": " 292 | putStrLn $ show (isCountCorrect sampleBindings) 293 | 294 | calculateContentLen :: Reader String Int 295 | calculateContentLen = do 296 | content <- ask 297 | return (length content) 298 | 299 | -- Calls calculateContentLen after adding a prefix to the Reader content. 300 | calculateModifiedContentLen :: Reader String Int 301 | calculateModifiedContentLen = local ("Prefix " ++) calculateContentLen 302 | 303 | action' = do 304 | let s = "12345" 305 | let modifiedLen = runReader calculateModifiedContentLen s 306 | let len = runReader calculateContentLen s 307 | putStrLn $ "Modified 's' length: " ++ (show modifiedLen) 308 | putStrLn $ "Original 's' length: " ++ (show len) 309 | 310 | newtype Writer w a = Writer { runWriter :: (a, w) } 311 | 312 | instance Functor (Writer w) where 313 | fmap = undefined 314 | 315 | instance (Monoid w) => Applicative (Writer w) where 316 | pure = undefined 317 | (<*>) = undefined 318 | 319 | instance Monoid w => Monad (Writer w) where 320 | Writer (x,v) >>= f = let (Writer (y, v')) = f x in Writer (y, v `mappend` v') 321 | 322 | tell :: Monoid w => w -> Writer w () 323 | tell w = Writer ((), w) 324 | 325 | listen :: Monoid w => Writer w a -> Writer w (w, a) 326 | listen (Writer (a,w)) = Writer ((w,a),w) 327 | 328 | pass :: Monoid w => Writer w (a, w -> w) -> Writer w a 329 | pass (Writer ((a, f), w)) = Writer (a, f w) 330 | 331 | execWriter :: Writer w a -> w 332 | execWriter (Writer p) = snd p 333 | 334 | writer :: (a, w) -> Writer w a 335 | writer = Writer 336 | 337 | -- foo x y 338 | -- x `foo` y 339 | 340 | -- foo x y z 341 | -- y `foo x` z 342 | 343 | binPow :: Int -> Int -> Writer String Int 344 | binPow 0 _ = return 1 345 | binPow n a 346 | | even n = binPow (n `div` 2) a >>= \b -> 347 | Writer (b * b, "Square " ++ show b ++ "\n") 348 | | otherwise = 349 | binPow (n - 1) a >>= \b -> 350 | Writer 351 | (a * b, "Mul " ++ show a ++ " and " ++ show b ++ "\n") 352 | 353 | type MyWriter = Writer [Int] String 354 | 355 | half :: Int -> Writer String Int 356 | half x = do 357 | tell ("I just halved " ++ (show x) ++ "!") 358 | return (x `div` 2) 359 | 360 | example :: MyWriter 361 | example = do 362 | tell [1..3] 363 | tell [3..5] 364 | return "foo" 365 | 366 | output :: (String, [Int]) 367 | output = runWriter example 368 | 369 | logNumber2 :: Int -> Writer [String] Int 370 | logNumber2 x = do 371 | tell ["Got number: " ++ show x] 372 | return x 373 | 374 | multWithLog :: Writer [String] Int 375 | multWithLog = do 376 | a <- logNumber 3 377 | b <- logNumber 5 378 | tell ["multiplying " ++ show a ++ " and " ++ show b ] 379 | return (a*b) 380 | 381 | deleteOn :: (Monoid w) => (w -> Bool) -> Writer w a -> Writer w a 382 | deleteOn p m = pass $ do 383 | (w, a) <- listen m 384 | case p w of 385 | True -> return (a, id) 386 | False -> return (a, const mempty) 387 | 388 | deleteOn' :: (Monoid w) => (w -> Bool) -> Writer w a -> Writer w a 389 | deleteOn' p m = pass $ do 390 | a <- m 391 | return (a, (\w -> if p w then mempty else w)) 392 | 393 | logTwo :: Writer [String] () 394 | logTwo = do 395 | deleteOn ((> 5) . length . head) $ tell ["foo"] 396 | deleteOn ((> 5) . length . head) $ tell ["foobar"] 397 | 398 | logNumber :: Int -> Writer [String] Int 399 | logNumber x = writer (x, ["Got number: " ++ show x]) 400 | 401 | -------- State examples --------------------------- 402 | 403 | newtype State s a = State { runState :: s -> (a,s) } 404 | 405 | instance Functor (State s) where 406 | -- fmap :: (a -> b) -> State s a -> State s b 407 | fmap f (State g) = State $ \s -> let (x, y) = g s in (f x, y) 408 | 409 | instance Applicative (State s) where 410 | -- pure :: a -> State s a 411 | pure x = State $ \s -> (x, s) 412 | 413 | -- (<*>) :: State s (a -> b) -> State s a -> State s b 414 | (State sa) <*> (State sb) = State $ 415 | \s -> let (fn, s1) = sa s 416 | (a, s2) = sb s1 417 | in (fn a, s2) 418 | 419 | instance Monad (State s) where 420 | -- (>>=) :: State s a -> (a -> State s b) -> State s b 421 | State act >>= f = State $ \s -> 422 | let (a, s') = act s 423 | in runState (f a) s' 424 | 425 | get :: State s s 426 | get = State $ \s -> (s, s) 427 | 428 | put :: s -> State s () 429 | put s = State $ \_ -> ((), s) 430 | 431 | modify :: (s -> s) -> State s () 432 | modify f = do 433 | s <- get 434 | put (f s) 435 | 436 | gets :: (s -> a) -> State s a 437 | gets f = do 438 | s <- get 439 | return (f s) 440 | 441 | withState :: (s -> s) -> State s a -> State s a 442 | withState f s = modify f >> s 443 | 444 | evalState :: State s a -> s -> a 445 | evalState (State f) s = fst $ f s 446 | 447 | execState :: State s a -> s -> s 448 | execState (State f) s = snd $ f s 449 | 450 | type Stack = [Int] 451 | 452 | emptyStack :: Stack 453 | emptyStack = [] 454 | 455 | pop :: State Stack Int 456 | pop = State $ \(x:xs) -> (x,xs) 457 | 458 | push :: Int -> State Stack () 459 | push a = State $ \xs -> ((),a:xs) 460 | 461 | tos :: State Stack Int 462 | tos = State $ \(x:xs) -> (x,x:xs) 463 | 464 | stackManip :: State Stack Int 465 | stackManip = do 466 | push 10 467 | push 20 468 | a <- pop 469 | b <- pop 470 | push (a+b) 471 | tos 472 | 473 | actionIO :: IO () 474 | actionIO = do 475 | let res = evalState stackManip emptyStack 476 | print res 477 | 478 | 479 | data Post = Post { pTitle :: String, pBody :: String } 480 | 481 | instance Show Post where 482 | show (Post title body) = "Title:" ++ title ++ "\n" ++ "Text: " ++ body 483 | 484 | data Blog = Blog 485 | { bPosts :: [Post] 486 | , bCounter :: Int 487 | } 488 | 489 | mkBlog :: [Post] -> Blog 490 | mkBlog posts = Blog posts (length posts) 491 | 492 | type BlogS = State Blog 493 | 494 | readPostS :: Int -> BlogS Post 495 | readPostS i = do 496 | modify (\b -> b { bCounter = bCounter b + 1 }) 497 | gets ((!! i) . bPosts) 498 | 499 | newPostS :: Post -> BlogS () 500 | newPostS p = modify $ \b -> 501 | b { bPosts = p : bPosts b } 502 | 503 | counterS :: BlogS Int 504 | counterS = gets bCounter 505 | 506 | read12AndNewS :: State Blog (Post, Post) 507 | read12AndNewS = 508 | readPostS 1 509 | >>= \post1 -> 510 | newPostS (Post "Bla" "") >> 511 | readPostS 2 >>= \post2 -> 512 | return (post1, post2) 513 | 514 | evalRead12AndNewS 515 | :: Blog -> (Post, Post) 516 | evalRead12AndNewS = 517 | evalState read12AndNewS 518 | 519 | myPost :: Post 520 | myPost = Post "Spam Title" "Whooo" 521 | 522 | spamWithPosts :: Int -> State Blog () 523 | spamWithPosts n = 524 | replicateM_ n (newPostS myPost) 525 | 526 | posts :: [Post] 527 | posts = (\(x, y) -> Post x y) <$> [("title 1", "lorem ipsum"), ("title 2", "dolor sit amet"), ("title 3", "consectetur adipiscing elit")] 528 | 529 | blog :: Blog 530 | blog = Blog posts (length posts) 531 | 532 | multiNewPost :: [Post] -> State Blog () 533 | multiNewPost = mapM_ newPostS 534 | -------------------------------------------------------------------------------- /Lecture7/Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture7/Slides.pdf -------------------------------------------------------------------------------- /Lecture7/Slides.tex: -------------------------------------------------------------------------------- 1 | \documentclass[10pt]{beamer} 2 | \usepackage[cache=false]{minted} 3 | \usepackage[utf8x]{inputenc} 4 | \usepackage{hyperref} 5 | \usepackage{fontawesome} 6 | \usepackage{graphicx} 7 | \usepackage[english,ngerman]{babel} 8 | \usepackage{bussproofs} 9 | 10 | % ------------------------------------------------------------------------------ 11 | % Use the beautiful metropolis beamer template 12 | % ------------------------------------------------------------------------------ 13 | \usepackage[T1]{fontenc} 14 | \usepackage{fontawesome} 15 | \usepackage{FiraSans} 16 | \newtheorem{defin}{Definition} 17 | \newtheorem{theor}{Theorem} 18 | \newtheorem{prop}{Proposition} 19 | \mode 20 | { 21 | \usetheme[progressbar=foot,numbering=fraction,background=light]{metropolis} 22 | \usecolortheme{default} % or try albatross, beaver, crane, ... 23 | \usefonttheme{default} % or try serif, structurebold, ... 24 | \setbeamertemplate{navigation symbols}{} 25 | \setbeamertemplate{caption}[numbered] 26 | %\setbeamertemplate{frame footer}{My custom footer} 27 | } 28 | 29 | % ------------------------------------------------------------------------------ 30 | % beamer doesn't have texttt defined, but I usually want it anyway 31 | % ------------------------------------------------------------------------------ 32 | \let\textttorig\texttt 33 | \renewcommand<>{\texttt}[1]{% 34 | \only#2{\textttorig{#1}}% 35 | } 36 | 37 | % ------------------------------------------------------------------------------ 38 | % minted 39 | % ------------------------------------------------------------------------------ 40 | 41 | 42 | % ------------------------------------------------------------------------------ 43 | % tcolorbox / tcblisting 44 | % ------------------------------------------------------------------------------ 45 | \usepackage{xcolor} 46 | \definecolor{codecolor}{HTML}{FFC300} 47 | 48 | \usepackage{tcolorbox} 49 | \tcbuselibrary{most,listingsutf8,minted} 50 | 51 | \tcbset{tcbox width=auto,left=1mm,top=1mm,bottom=1mm, 52 | right=1mm,boxsep=1mm,middle=1pt} 53 | 54 | \newtcblisting{myr}[1]{colback=codecolor!5,colframe=codecolor!80!black,listing only, 55 | minted options={numbers=left, style=tcblatex,fontsize=\tiny,breaklines,autogobble,linenos,numbersep=3mm}, 56 | left=5mm,enhanced, 57 | title=#1, fonttitle=\bfseries, 58 | listing engine=minted,minted language=r} 59 | 60 | 61 | % ------------------------------------------------------------------------------ 62 | % Listings 63 | % ------------------------------------------------------------------------------ 64 | \definecolor{mygreen}{HTML}{37980D} 65 | \definecolor{myblue}{HTML}{0D089F} 66 | \definecolor{myred}{HTML}{98290D} 67 | 68 | \usepackage{listings} 69 | 70 | % the following is optional to configure custom highlighting 71 | \lstdefinelanguage{XML} 72 | { 73 | morestring=[b]", 74 | morecomment=[s]{}, 75 | morestring=[s]{>}{<}, 76 | morekeywords={ref,xmlns,version,type,canonicalRef,metr,real,target}% list your attributes here 77 | } 78 | 79 | \lstdefinestyle{myxml}{ 80 | language=XML, 81 | showspaces=false, 82 | showtabs=false, 83 | basicstyle=\ttfamily, 84 | columns=fullflexible, 85 | breaklines=true, 86 | showstringspaces=false, 87 | breakatwhitespace=true, 88 | escapeinside={(*@}{@*)}, 89 | basicstyle=\color{mygreen}\ttfamily,%\footnotesize, 90 | stringstyle=\color{myred}, 91 | commentstyle=\color{myblue}\upshape, 92 | keywordstyle=\color{myblue}\bfseries, 93 | } 94 | 95 | 96 | % ------------------------------------------------------------------------------ 97 | % The Document 98 | % ------------------------------------------------------------------------------ 99 | \title{Functional programming, Seminar No. 7} 100 | \author{Daniel Rogozin \\ Institute for Information Transmission Problems, RAS \\ Serokell O\"{U}} 101 | 102 | \vspace{\baselineskip} 103 | 104 | \date{Higher School of Economics \\ The Department of Computer Science} 105 | 106 | \begin{document} 107 | 108 | \maketitle 109 | 110 | \begin{frame} 111 | \frametitle{Today} 112 | 113 | We will study the following monads 114 | \begin{center} 115 | \includegraphics[scale=0.25]{puppies.png} 116 | \end{center} 117 | \end{frame} 118 | 119 | \section{Input/Output} 120 | 121 | \begin{frame}[fragile] 122 | \frametitle{The \verb"IO" monad, motivation} 123 | \begin{itemize} 124 | \item \verb"IO a" is a type whose values are input/output actions that produce values of \verb"a" 125 | \item Here are first examples of \verb"IO" functions 126 | \begin{minted}{haskell} 127 | getChar :: IO Char 128 | getLine :: IO String 129 | \end{minted} 130 | \item In fact, these functions have the following types: 131 | \begin{minted}{haskell} 132 | getChar :: RealWorld -> (RealWorld, Char) 133 | getLine :: RealWorld -> (RealWorld, String) 134 | \end{minted} 135 | \item A philosophical question: what is \verb"RealWorld"? 136 | \end{itemize} 137 | \end{frame} 138 | 139 | \begin{frame}[fragile] 140 | \frametitle{The approximate definition of \verb"IO"} 141 | \begin{itemize} 142 | \item \verb"IO" is defined approximately as follows: 143 | \begin{minted}{haskell} 144 | newtype IO a = IO (RealWorld -> (RealWorld, a)) 145 | \end{minted} 146 | \item According to Hoogle, ``\verb"RealWorld" is deeply magical. It is primitive... We never manipulate values of type RealWorld... it's only used in the type system'' 147 | \item That is, an engineer has no access to values of \verb"RealWorld" and we cannot use the same \verb"RealWorld" twice! 148 | \end{itemize} 149 | \end{frame} 150 | 151 | \begin{frame}[fragile] 152 | \frametitle{The \verb"IO" as a Monad} 153 | 154 | The \verb"Monad" instance (very roughly): 155 | \begin{minted}{haskell} 156 | instance Monad IO where 157 | return x = IO $ \w -> (w, x) 158 | m >>= k = IO $ \w -> 159 | case m w of 160 | (w', a) -> k a w' 161 | \end{minted} 162 | \begin{itemize} 163 | \item An effect of every action occurs only once. 164 | \item Note that the order of effects matters! 165 | \end{itemize} 166 | \end{frame} 167 | 168 | \begin{frame}[fragile] 169 | \frametitle{Basic console input/output functions} 170 | \begin{itemize} 171 | \item Input: 172 | \begin{minted}{haskell} 173 | getChar :: IO Char 174 | getLine, getContents :: IO String 175 | \end{minted} 176 | \item Output: 177 | \begin{minted}{haskell} 178 | putStrLn :: String -> IO () 179 | print :: Show a => a -> IO () 180 | \end{minted} 181 | \item Input/output: 182 | \begin{minted}{haskell} 183 | interact :: (String -> String) -> IO () 184 | \end{minted} 185 | \end{itemize} 186 | \end{frame} 187 | 188 | \begin{frame}[fragile] 189 | \frametitle{An example of \verb"IO"} 190 | 191 | \begin{minted}{haskell} 192 | main :: IO () 193 | main = do 194 | putStrLn "Hello, what is your name?" 195 | name <- getLine 196 | putStrLn $ "Hi, " ++ name 197 | putStrLn $ 198 | "Gotta go, " ++ name ++ 199 | ", have a nice day" 200 | \end{minted} 201 | \end{frame} 202 | 203 | \begin{frame}[fragile] 204 | \frametitle{The \verb"getLine" function closely} 205 | 206 | Let us take a look at the rough version of \verb"getLine": 207 | 208 | \begin{minted}{haskell} 209 | getLine' :: IO String 210 | getLine' = do 211 | c <- getChar 212 | case c == '\n' of 213 | True -> return [] 214 | False -> do 215 | cs <- getLine' 216 | return (c : cs) 217 | \end{minted} 218 | \end{frame} 219 | 220 | \begin{frame}[fragile] 221 | \frametitle{The \verb"putStr" function} 222 | 223 | \begin{minted}{haskell} 224 | putStr' :: String -> IO () 225 | putStr' [] = return () 226 | putStr' (x : xs) = putChar x >> putStr' xs 227 | \end{minted} 228 | 229 | Using \verb"sequence_": 230 | 231 | \begin{minted}{haskell} 232 | sequence_ :: Monad m => [m a] -> m () 233 | sequence_ = foldr (>>) (return ()) 234 | 235 | putStr'' :: String -> IO () 236 | putStr'' = sequence_ . map putChar 237 | \end{minted} 238 | \end{frame} 239 | 240 | \begin{frame}[fragile] 241 | \frametitle{The \verb"putStr" function} 242 | 243 | Using \verb"sequence_" and \verb"mapM_": 244 | \begin{minted}{haskell} 245 | sequence_ :: Monad m => [m a] -> m () 246 | sequence_ = foldr (>>) (return ()) 247 | 248 | mapM_ :: Monad m => (a -> m b) -> [a] -> m () 249 | mapM_ f = sequence_ . map f 250 | 251 | putStr''' :: String -> IO () 252 | putStr''' = mapM_ putChar 253 | \end{minted} 254 | \end{frame} 255 | 256 | \section{Reader, Writer, and State} 257 | 258 | \begin{frame}[fragile] 259 | \frametitle{Reader} 260 | The \verb"Reader" monad allows one to read values from an environment: 261 | \begin{minted}{haskell} 262 | newtype Reader r a = Reader { runReader :: (r -> a) } 263 | 264 | instance Monad (Reader r) where 265 | -- return :: a -> Reader r a 266 | return x = Reader $ const x 267 | 268 | -- (>>=) :: Reader r a -> (a -> Reader r b) -> Reader r b 269 | Reader f >>= k = Reader $ \e -> let v = runReader m e 270 | in runReader (k v) e 271 | \end{minted} 272 | 273 | \begin{itemize} 274 | \item Here \verb"(>>=)" passes a given environment to both computations 275 | \item Useful functions: 276 | \begin{minted}{haskell} 277 | ask :: Reader e e 278 | asks :: (e -> a) -> Reader e a 279 | local :: (e -> b) -> Reader b a -> Reader e a 280 | \end{minted} 281 | \end{itemize} 282 | \end{frame} 283 | 284 | \begin{frame}[fragile] 285 | \frametitle{Reader. An example} 286 | \begin{minted}{haskell} 287 | data Environment = Environment { ids :: [Int] 288 | , name :: Int -> String 289 | , near :: Int -> (Int, Int) } 290 | 291 | inEnv :: Int -> Reader Environment Bool 292 | inEnv i = asks (elem i . ids) 293 | 294 | anyInEnv :: (Int, Int) -> Reader Environment Bool 295 | anyInEnv (i, j) = inEnv i ||^ inEnv j 296 | 297 | checkNeighbours :: Int -> Reader Environment (Maybe String) 298 | checkNeighbours i = 299 | asks (`near` i) >>= \pair -> 300 | anyInEnv pair >>= \res -> 301 | if res 302 | then Just <$> asks (`name` i) 303 | else pure Nothing 304 | \end{minted} 305 | \end{frame} 306 | 307 | \begin{frame}[fragile] 308 | \frametitle{Writer} 309 | \begin{itemize} 310 | \item The \verb"Writer" monad for computation with logs 311 | \begin{minted}{haskell} 312 | newtype Writer w a = Writer { runWriter :: (a, w) } 313 | 314 | instance Monoid w => Monad (Writer w) where 315 | -- return :: a -> Writer w a 316 | return x = Writer (x, mempty) 317 | 318 | -- (>>=) 319 | -- :: Writer r a -> (a -> Writer r b) -> Writer r b 320 | Writer (x,v) >>= f = let (Writer (y, v')) = f x 321 | in Writer (y, v `mappend` v') 322 | \end{minted} 323 | \item The useful combinators: 324 | \begin{minted}{haskell} 325 | tell :: Monoid w => w -> Writer w () 326 | listen :: Monoid w => Writer w a -> Writer w (w, a) 327 | pass :: Monoid w => Writer w (a, w -> w) -> Writer w a 328 | execWriter :: Writer w a -> w 329 | \end{minted} 330 | \end{itemize} 331 | \end{frame} 332 | 333 | \begin{frame}[fragile] 334 | \frametitle{Writer. An example} 335 | \begin{minted}{haskell} 336 | binPow :: Int -> Int -> Writer String Int 337 | binPow 0 _ = return 1 338 | binPow n a 339 | | even n = binPow (n `div` 2) a >>= \b -> 340 | Writer (b * b, "Square " ++ show b ++ "\n") 341 | | otherwise = 342 | binPow (n - 1) a >>= \b -> 343 | Writer 344 | (a * b, "Mul " ++ show a ++ " and " ++ show b ++ "\n") 345 | \end{minted} 346 | \end{frame} 347 | 348 | \begin{frame}[fragile] 349 | \frametitle{State} 350 | \begin{itemize} 351 | \item The \verb"State" monad for processing of mutable states 352 | \begin{minted}{haskell} 353 | newtype State s a = State { runState :: s -> (a,s) } 354 | 355 | instance Monad (State s) where 356 | -- return :: a -> State s a 357 | return x = State $ \s -> (x, s) 358 | 359 | -- (>>=) :: State s a -> (a -> State s b) -> State s b 360 | State act >>= f = State $ \s -> 361 | let (a, s') = act s 362 | in runState (k a) s' 363 | \end{minted} 364 | \item Useful functions: 365 | \begin{minted}{haskell} 366 | get :: State s s 367 | put :: s -> State s () 368 | modify :: (s -> s) -> State s () 369 | gets :: (s -> a) -> State s a 370 | withState :: (s -> s) -> State s a -> State s a 371 | evalState :: State s a -> s -> a 372 | execState :: State s a -> s -> s 373 | \end{minted} 374 | \end{itemize} 375 | \end{frame} 376 | 377 | \begin{frame}[fragile] 378 | \frametitle{State. An example} 379 | \begin{minted}{haskell} 380 | type Stack = [Int] 381 | 382 | pop :: State Stack Int 383 | pop = State $ \(x:xs) -> (x, xs) 384 | 385 | push :: Int -> State Stack () 386 | push x = State $ \xs -> ((), x:xs) 387 | 388 | stackOps :: State Stack Int 389 | stackOps = pop >>= \x -> push 5 >> push 10 >> return x 390 | \end{minted} 391 | \end{frame} 392 | 393 | \end{document} 394 | -------------------------------------------------------------------------------- /Lecture7/puppies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture7/puppies.png -------------------------------------------------------------------------------- /Lecture8/Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Lecture8/Slides.pdf -------------------------------------------------------------------------------- /Lecture8/Slides.tex: -------------------------------------------------------------------------------- 1 | \documentclass[10pt]{beamer} 2 | \usepackage[cache=false]{minted} 3 | \usepackage[utf8x]{inputenc} 4 | \usepackage{hyperref} 5 | \usepackage{fontawesome} 6 | \usepackage{graphicx} 7 | \usepackage[english,ngerman]{babel} 8 | \usepackage{bussproofs} 9 | 10 | % ------------------------------------------------------------------------------ 11 | % Use the beautiful metropolis beamer template 12 | % ------------------------------------------------------------------------------ 13 | \usepackage[T1]{fontenc} 14 | \usepackage{fontawesome} 15 | \usepackage{FiraSans} 16 | \newtheorem{defin}{Definition} 17 | \newtheorem{theor}{Theorem} 18 | \newtheorem{prop}{Proposition} 19 | \mode 20 | { 21 | \usetheme[progressbar=foot,numbering=fraction,background=light]{metropolis} 22 | \usecolortheme{default} % or try albatross, beaver, crane, ... 23 | \usefonttheme{default} % or try serif, structurebold, ... 24 | \setbeamertemplate{navigation symbols}{} 25 | \setbeamertemplate{caption}[numbered] 26 | %\setbeamertemplate{frame footer}{My custom footer} 27 | } 28 | 29 | % ------------------------------------------------------------------------------ 30 | % beamer doesn't have texttt defined, but I usually want it anyway 31 | % ------------------------------------------------------------------------------ 32 | \let\textttorig\texttt 33 | \renewcommand<>{\texttt}[1]{% 34 | \only#2{\textttorig{#1}}% 35 | } 36 | 37 | % ------------------------------------------------------------------------------ 38 | % minted 39 | % ------------------------------------------------------------------------------ 40 | 41 | 42 | % ------------------------------------------------------------------------------ 43 | % tcolorbox / tcblisting 44 | % ------------------------------------------------------------------------------ 45 | \usepackage{xcolor} 46 | \definecolor{codecolor}{HTML}{FFC300} 47 | 48 | \usepackage{tcolorbox} 49 | \tcbuselibrary{most,listingsutf8,minted} 50 | 51 | \tcbset{tcbox width=auto,left=1mm,top=1mm,bottom=1mm, 52 | right=1mm,boxsep=1mm,middle=1pt} 53 | 54 | \newtcblisting{myr}[1]{colback=codecolor!5,colframe=codecolor!80!black,listing only, 55 | minted options={numbers=left, style=tcblatex,fontsize=\tiny,breaklines,autogobble,linenos,numbersep=3mm}, 56 | left=5mm,enhanced, 57 | title=#1, fonttitle=\bfseries, 58 | listing engine=minted,minted language=r} 59 | 60 | 61 | % ------------------------------------------------------------------------------ 62 | % Listings 63 | % ------------------------------------------------------------------------------ 64 | \definecolor{mygreen}{HTML}{37980D} 65 | \definecolor{myblue}{HTML}{0D089F} 66 | \definecolor{myred}{HTML}{98290D} 67 | 68 | \usepackage{listings} 69 | 70 | % the following is optional to configure custom highlighting 71 | \lstdefinelanguage{XML} 72 | { 73 | morestring=[b]", 74 | morecomment=[s]{}, 75 | morestring=[s]{>}{<}, 76 | morekeywords={ref,xmlns,version,type,canonicalRef,metr,real,target}% list your attributes here 77 | } 78 | 79 | \lstdefinestyle{myxml}{ 80 | language=XML, 81 | showspaces=false, 82 | showtabs=false, 83 | basicstyle=\ttfamily, 84 | columns=fullflexible, 85 | breaklines=true, 86 | showstringspaces=false, 87 | breakatwhitespace=true, 88 | escapeinside={(*@}{@*)}, 89 | basicstyle=\color{mygreen}\ttfamily,%\footnotesize, 90 | stringstyle=\color{myred}, 91 | commentstyle=\color{myblue}\upshape, 92 | keywordstyle=\color{myblue}\bfseries, 93 | } 94 | 95 | 96 | % ------------------------------------------------------------------------------ 97 | % The Document 98 | % ------------------------------------------------------------------------------ 99 | \title{Functional programming, Seminar No. 8} 100 | \author{Daniel Rogozin \\ Lomonosov Moscow State University, \\ Serokell O\"{U}} 101 | 102 | \vspace{\baselineskip} 103 | 104 | \date{Higher School of Economics \\ The Department of Computer Science} 105 | 106 | \begin{document} 107 | 108 | \maketitle 109 | 110 | \begin{frame} 111 | \frametitle{Intro} 112 | 113 | On the previous seminar we 114 | \begin{itemize} 115 | \item studied such monads as \verb"IO", \verb"Reader", \verb"Writer", and \verb"State" 116 | \end{itemize} 117 | 118 | \onslide<2->{ 119 | Today we 120 | \begin{itemize} 121 | \item investigate monad transformers as an uniform method of the effect combining 122 | \end{itemize} 123 | } 124 | \end{frame} 125 | 126 | \section{Alternative and MonadPlus classes} 127 | 128 | \begin{frame}[fragile] 129 | \frametitle{Monoids} 130 | 131 | \begin{minted}{haskell} 132 | class Semigroup a => Monoid a where 133 | mempty :: a 134 | mappend :: a -> a -> a 135 | \end{minted} 136 | 137 | Some of monads are also monoids, e.g., the list data type 138 | 139 | \begin{minted}{haskell} 140 | instance Monoid [a] where 141 | mempty = [] 142 | mappend = (++) 143 | \end{minted} 144 | \end{frame} 145 | 146 | \begin{frame}[fragile] 147 | \frametitle{Two versions of the \verb"Maybe" monoid} 148 | 149 | \begin{minted}{haskell} 150 | instance Monoid a => Monoid (Maybe a) where 151 | mempty = Just memty 152 | Nothing `mappend` _ = Nothing 153 | _ `mappend` Nothing = Nothing 154 | (Just a) `mappend` (Just b) = Just (a `mappend` b) 155 | \end{minted} 156 | 157 | \begin{minted}{haskell} 158 | instance Monoid (Maybe a) where 159 | mempty = Nothing 160 | Nothing `mappend` m = m 161 | m@(Just _) `mappend` _ = m 162 | \end{minted} 163 | \end{frame} 164 | 165 | \begin{frame}[fragile] 166 | \frametitle{The \verb"Alternative" class} 167 | 168 | The \verb"Alternative" class is a generalisation of the idea above: 169 | 170 | \begin{minted}{haskell} 171 | class Applicative f => Alternative (f :: * -> *) where 172 | empty :: f a 173 | (<|>) :: f a -> f a -> f a 174 | some :: f a -> f [a] 175 | many :: f a -> f [a] 176 | {-# MINIMAL empty, (<|>) #-} 177 | 178 | infixl 3 <|> 179 | \end{minted} 180 | \end{frame} 181 | 182 | \begin{frame}[fragile] 183 | \frametitle{The \verb"MonadPlus" class} 184 | 185 | The \verb"Alternative" class has an essential extension called \verb"MonadPlus": 186 | 187 | \begin{minted}{haskell} 188 | class (Alternative m, Monad m) => MonadPlus m where 189 | mzero :: m a 190 | mplus :: m a -> m a -> m a 191 | \end{minted} 192 | 193 | \vspace{\baselineskip} 194 | 195 | This class should satisfy the following conditions: 196 | \begin{minted}{haskell} 197 | mzero >>= f == mzero 198 | v >> mzero == mzero 199 | \end{minted} 200 | \end{frame} 201 | 202 | \begin{frame}[fragile] 203 | \frametitle{The \verb"MonadPlus" uses} 204 | 205 | \begin{minted}{haskell} 206 | mfilter :: (MonadPlus m) => (a -> Bool) -> m a -> m a 207 | mfilter p ma = do 208 | a <- ma 209 | if p a then return a else mzero 210 | 211 | guard :: Alternative f => Bool -> f () 212 | guard True = pure () 213 | guard False = empty 214 | 215 | when :: Applicative f => Bool -> f () -> f () 216 | when p s = if p then s else pure () 217 | \end{minted} 218 | \end{frame} 219 | 220 | \section{Monad transformers} 221 | 222 | \begin{frame}[fragile] 223 | \frametitle{How to compose Reader and Writer} 224 | 225 | \begin{minted}{haskell} 226 | foo :: RWS Int [Int] () Int 227 | foo i = do 228 | baseCounter <- ask 229 | let newCounter = baseCounter + i 230 | put [baseCounter, newCounter] 231 | return newCounter 232 | 233 | foo :: State (Int, [Int]) Int 234 | foo i = do 235 | x <- gets fst 236 | let xi = x + i 237 | put (x, [x, xi]) 238 | return xi 239 | \end{minted} 240 | \end{frame} 241 | 242 | \begin{frame}[fragile] 243 | \frametitle{Maybe and IO} 244 | 245 | The example of a monad composition is the \verb"MaybeIO" monad 246 | 247 | \begin{minted}{haskell} 248 | newtype MaybeIO a = MaybeIO { runMaybeIO :: IO (Maybe a) } 249 | 250 | instance Monad MaybeIO where 251 | return x = MaybeIO (return (Just x)) 252 | MaybeIO action >>= f = MaybeIO $ do 253 | result <- action 254 | case result of 255 | Nothing -> return Nothing 256 | Just x -> runMaybeIO (f x) 257 | \end{minted} 258 | \end{frame} 259 | 260 | \begin{frame}[fragile] 261 | \frametitle{The generalisation of the idea above} 262 | 263 | \begin{minted}{haskell} 264 | newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) } 265 | 266 | instance Monad m => Monad (MaybeT m) where 267 | return :: a -> MaybeT m a 268 | return x = MaybeT (return (Just x)) 269 | 270 | (>>=) :: MaybeT m a -> (a -> MaybeT m b) -> MaybeT m b 271 | MaybeT action >>= f = MaybeT $ do 272 | result <- action 273 | case result of 274 | Nothing -> return Nothing 275 | Just x -> runMaybeT (f x) 276 | \end{minted} 277 | \end{frame} 278 | 279 | \begin{frame}[fragile] 280 | \frametitle{The \verb"MonadTrans" class} 281 | 282 | \begin{minted}{haskell} 283 | class MonadTrans (t :: (* -> *) -> * -> *) where 284 | -- | Lift a computation from 285 | -- | the argument monad to the constructed monad. 286 | lift :: (Monad m) => m a -> t m a 287 | \end{minted} 288 | 289 | \vspace{\baselineskip} 290 | 291 | This class has the following laws: 292 | \begin{minted}{haskell} 293 | lift . return == return 294 | lift (m >>= f) == lift m >>= (lift . f) 295 | \end{minted} 296 | \end{frame} 297 | 298 | \begin{frame}[fragile] 299 | \frametitle{The MonadTrans instances} 300 | 301 | \begin{minted}{haskell} 302 | transformToMaybeT :: Functor m => m a -> MaybeT m a 303 | transformToMaybeT = error "homework" 304 | 305 | instance MonadTrans MaybeT where 306 | lift :: Monad m => m a -> MaybeT m a 307 | lift = transformToMaybeT 308 | \end{minted} 309 | \end{frame} 310 | 311 | \begin{frame}[fragile] 312 | \frametitle{The MaybeT example} 313 | 314 | \begin{minted}{haskell} 315 | emailIsValid :: String -> Bool 316 | emailIsValid email = '@' `elem` email 317 | 318 | askEmail :: MaybeT IO String 319 | askEmail = do 320 | lift $ putStrLn "Input your email, please:" 321 | email <- lift getLine 322 | guard $ emailIsValid email 323 | return email 324 | 325 | main :: IO () 326 | main = do 327 | email <- askEmail 328 | case email of 329 | Nothing -> putStrLn "Wrong email." 330 | Just email' -> putStrLn email' 331 | \end{minted} 332 | \end{frame} 333 | 334 | \begin{frame}[fragile] 335 | \frametitle{The ReaderT monad} 336 | 337 | \begin{minted}{haskell} 338 | newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a } 339 | 340 | type LoggerIO a = ReaderT LoggerName IO a 341 | 342 | logMessage :: Text -> LoggerIO () 343 | 344 | readFileWithLog :: FilePath -> LoggerIO Text 345 | readFileWithLog path = do 346 | logMessage $ "Reading file: " <> T.pack (show path) 347 | lift $ readFile path 348 | \end{minted} 349 | \end{frame} 350 | 351 | \begin{frame}[fragile] 352 | \frametitle{The ReaderT monad} 353 | 354 | \begin{minted}{haskell} 355 | writeFileWithLog :: FilePath -> Text -> LoggerIO () 356 | writeFileWithLog path content = do 357 | logMessage $ "Writing to file: " <> T.pack (show path) 358 | lift $ writeFile path content 359 | 360 | prettifyFileContent :: FilePath -> LoggerIO () 361 | prettifyFileContent path = do 362 | content <- readFileWithLog path 363 | writeFileWithLog path (format content) 364 | 365 | main :: IO () 366 | main = 367 | runReaderT 368 | (prettifyFileContent "foo.txt") 369 | (LoggerName "Application") 370 | \end{minted} 371 | \end{frame} 372 | 373 | \begin{frame}[fragile] 374 | \frametitle{The MonadReader class} 375 | 376 | The class is defined the mtl-package 377 | 378 | \begin{minted}{haskell} 379 | class Monad m => MonadReader r m | m -> r where 380 | ask :: m r 381 | local :: (r -> r) -> m a -> m a 382 | reader :: (r -> a) -> m a 383 | 384 | instance MonadReader r m => MonadReader r (StateT s m) where 385 | ask = lift ask 386 | local = mapStateT . local 387 | reader = lift . reader 388 | \end{minted} 389 | \end{frame} 390 | 391 | \begin{frame}[fragile] 392 | \frametitle{The MonadError class} 393 | 394 | \begin{minted}{haskell} 395 | class (Monad m) => MonadError e m | m -> e where 396 | throwError :: e -> m a 397 | catchError :: m a -> (e -> m a) -> m a 398 | 399 | newtype ExceptT e m a = 400 | ExceptT { runExceptT :: m (Either e a) } 401 | 402 | runExceptT :: ExceptT e m a -> m (Either e a) 403 | 404 | withExceptT :: 405 | Functor m => (e -> e') -> ExceptT e m a -> ExceptT e' m a 406 | \end{minted} 407 | \end{frame} 408 | 409 | \begin{frame}[fragile] 410 | \frametitle{The MonadError class} 411 | 412 | \begin{minted}{haskell} 413 | foo :: MonadError FooError m => ... 414 | bar :: MonadError BarError m => ... 415 | baz :: MonadError BazError m => ... 416 | 417 | data BazError = BazFoo FooError | BazBar BarError 418 | 419 | baz = do 420 | withExcept BazFoo foo 421 | withExcept BazBar ba 422 | \end{minted} 423 | \end{frame} 424 | 425 | \end{document} 426 | -------------------------------------------------------------------------------- /ParserSeminar/Slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/ParserSeminar/Slides.pdf -------------------------------------------------------------------------------- /ParserSeminar/Slides.tex: -------------------------------------------------------------------------------- 1 | \documentclass[10pt]{beamer} 2 | \usepackage[cache=false]{minted} 3 | \usepackage[utf8x]{inputenc} 4 | \usepackage{hyperref} 5 | \usepackage{fontawesome} 6 | \usepackage{graphicx} 7 | \usepackage[english,ngerman]{babel} 8 | \usepackage{bussproofs} 9 | 10 | % ------------------------------------------------------------------------------ 11 | % Use the beautiful metropolis beamer template 12 | % ------------------------------------------------------------------------------ 13 | \usepackage[T1]{fontenc} 14 | \usepackage{fontawesome} 15 | \usepackage{FiraSans} 16 | \newtheorem{defin}{Definition} 17 | \newtheorem{theor}{Theorem} 18 | \newtheorem{prop}{Proposition} 19 | \mode 20 | { 21 | \usetheme[progressbar=foot,numbering=fraction,background=light]{metropolis} 22 | \usecolortheme{default} % or try albatross, beaver, crane, ... 23 | \usefonttheme{default} % or try serif, structurebold, ... 24 | \setbeamertemplate{navigation symbols}{} 25 | \setbeamertemplate{caption}[numbered] 26 | %\setbeamertemplate{frame footer}{My custom footer} 27 | } 28 | 29 | % ------------------------------------------------------------------------------ 30 | % beamer doesn't have texttt defined, but I usually want it anyway 31 | % ------------------------------------------------------------------------------ 32 | \let\textttorig\texttt 33 | \renewcommand<>{\texttt}[1]{% 34 | \only#2{\textttorig{#1}}% 35 | } 36 | 37 | % ------------------------------------------------------------------------------ 38 | % minted 39 | % ------------------------------------------------------------------------------ 40 | 41 | 42 | % ------------------------------------------------------------------------------ 43 | % tcolorbox / tcblisting 44 | % ------------------------------------------------------------------------------ 45 | \usepackage{xcolor} 46 | \definecolor{codecolor}{HTML}{FFC300} 47 | 48 | \usepackage{tcolorbox} 49 | \tcbuselibrary{most,listingsutf8,minted} 50 | 51 | \tcbset{tcbox width=auto,left=1mm,top=1mm,bottom=1mm, 52 | right=1mm,boxsep=1mm,middle=1pt} 53 | 54 | \newtcblisting{myr}[1]{colback=codecolor!5,colframe=codecolor!80!black,listing only, 55 | minted options={numbers=left, style=tcblatex,fontsize=\tiny,breaklines,autogobble,linenos,numbersep=3mm}, 56 | left=5mm,enhanced, 57 | title=#1, fonttitle=\bfseries, 58 | listing engine=minted,minted language=r} 59 | 60 | 61 | % ------------------------------------------------------------------------------ 62 | % Listings 63 | % ------------------------------------------------------------------------------ 64 | \definecolor{mygreen}{HTML}{37980D} 65 | \definecolor{myblue}{HTML}{0D089F} 66 | \definecolor{myred}{HTML}{98290D} 67 | 68 | \usepackage{listings} 69 | 70 | % the following is optional to configure custom highlighting 71 | \lstdefinelanguage{XML} 72 | { 73 | morestring=[b]", 74 | morecomment=[s]{}, 75 | morestring=[s]{>}{<}, 76 | morekeywords={ref,xmlns,version,type,canonicalRef,metr,real,target}% list your attributes here 77 | } 78 | 79 | \lstdefinestyle{myxml}{ 80 | language=XML, 81 | showspaces=false, 82 | showtabs=false, 83 | basicstyle=\ttfamily, 84 | columns=fullflexible, 85 | breaklines=true, 86 | showstringspaces=false, 87 | breakatwhitespace=true, 88 | escapeinside={(*@}{@*)}, 89 | basicstyle=\color{mygreen}\ttfamily,%\footnotesize, 90 | stringstyle=\color{myred}, 91 | commentstyle=\color{myblue}\upshape, 92 | keywordstyle=\color{myblue}\bfseries, 93 | } 94 | 95 | 96 | % ------------------------------------------------------------------------------ 97 | % The Document 98 | % ------------------------------------------------------------------------------ 99 | \title{Functional programming, Seminar No. 8} 100 | \author{Danya Rogozin \\ Institute for Information Transmission Problems, RAS \\ Serokell O\"{U}} 101 | 102 | \vspace{\baselineskip} 103 | 104 | \date{Higher School of Economics \\ The Department of Computer Science} 105 | 106 | \begin{document} 107 | 108 | \maketitle 109 | 110 | \begin{frame}[fragile] 111 | \frametitle{Type of parser} 112 | What is a type of function which parses an integer? 113 | \begin{minted}{haskell} 114 | parseInteger :: String -> Bool 115 | \end{minted} 116 | Not quite, we would like to get an \verb"Integer" 117 | 118 | The second variant. But such a parser can fail. 119 | \begin{minted}{haskell} 120 | parseInteger :: String -> Integer 121 | \end{minted} 122 | 123 | \begin{minted}{haskell} 124 | parseInteger :: String -> Maybe Integer 125 | \end{minted} 126 | Now. How do you parse two integers separated by space? Or by any number of spaces? Or comma-separated list of integers? Or the same list inside square brackets [] with any number of spaces between elements? 127 | 128 | The solution is the following: 129 | \begin{minted}{haskell} 130 | parseInteger :: String -> Maybe (Integer, String) 131 | \end{minted} 132 | \end{frame} 133 | 134 | \begin{frame}[fragile] 135 | \frametitle{Type of parser} 136 | But instead of this: 137 | \begin{minted}{haskell} 138 | parseInteger :: String -> Maybe (Integer, String) 139 | \end{minted} 140 | We introduce \verb"Parser" with the \verb"newtype" wrapper in order to have useful instances: 141 | \begin{minted}{haskell} 142 | newtype Parser a = 143 | Parser { runP :: String -> Maybe (a, String) } 144 | \end{minted} 145 | \end{frame} 146 | 147 | \begin{frame}[fragile] 148 | \frametitle{Some usage examples} 149 | The parser combinator type: 150 | \begin{minted}{haskell} 151 | newtype Parser a = Parser { runP :: String -> Maybe (a, String) } 152 | \end{minted} 153 | 154 | Parsing functions 155 | \begin{minted}{haskell} 156 | parseInteger :: Parser Integer 157 | -- String -> Maybe (Integer, String) 158 | \end{minted} 159 | 160 | How to use it and which behaviour we want? 161 | \begin{minted}{haskell} 162 | runP :: Parser a -> String -> Maybe (a, String) 163 | ghci> runP parseInteger "5" 164 | Just (5, "") :: Maybe (Integer, String) 165 | 166 | ghci> runP parseInteger "42x7" 167 | Just (42, "x7") :: Maybe (Integer, String) 168 | 169 | ghci> runP parseInteger "abc" 170 | Nothing :: Maybe (Integer, String) 171 | \end{minted} 172 | This behaviour allows us to combine parsers relatively easy! 173 | \end{frame} 174 | 175 | \begin{frame}[fragile] 176 | \frametitle{Now, idea and how to do it} 177 | 178 | \begin{itemize} 179 | \item The key idea of parser combinators: implement manually very simple parsers, implement combinators for combining parser and then implement more complex parsers by combining simpler ones. 180 | \item Haskell provides combinators through standard type classes. And it's convenient to use them. What we need is just: 181 | \begin{minted}{haskell} 182 | instance Functor Parser 183 | -- replace parser value 184 | instance Applicative Parser 185 | -- run parsers sequentially one after another 186 | instance Monad Parser 187 | -- same as above but with monadic capabilities 188 | instance Alternative Parser 189 | -- allows one to choose parser 190 | \end{minted} 191 | \end{itemize} 192 | \end{frame} 193 | 194 | \begin{frame}[fragile] 195 | \frametitle{Primitive parsers. \verb"ok"} 196 | 197 | \begin{minted}{haskell} 198 | newtype Parser a = 199 | Parser { runP :: String -> Maybe (a, String) } 200 | 201 | -- always succeeds without consuming any input 202 | ok :: Parser () 203 | ok = error "this is your home" 204 | \end{minted} 205 | \end{frame} 206 | 207 | \begin{frame}[fragile] 208 | \frametitle{Primitive parsers. \verb"isnot"} 209 | 210 | \begin{minted}{haskell} 211 | newtype Parser a = 212 | Parser { runP :: String -> Maybe (a, String) } 213 | 214 | -- fails w/o consuming any input if given parser succeeds, 215 | -- and succeeds if given parser fails 216 | isnot :: Parser a -> Parser () 217 | isnot parser = 218 | Parser $ \s -> case runP parser s of 219 | Just _ -> Nothing 220 | Nothing -> Just ((), s) 221 | \end{minted} 222 | \end{frame} 223 | 224 | \begin{frame}[fragile] 225 | \frametitle{Primitive parsers. \verb"eof"} 226 | 227 | \begin{minted}{haskell} 228 | newtype Parser a = 229 | Parser { runP :: String -> Maybe (a, String) } 230 | 231 | -- succeeds only at the end of input stream 232 | eof :: Parser () 233 | eof = Parser $ \s -> case s of 234 | [] -> Just ((), "") 235 | _ -> Nothing 236 | \end{minted} 237 | \end{frame} 238 | 239 | \begin{frame}[fragile] 240 | \frametitle{Primitive parsers. \verb"ok"} 241 | 242 | \begin{minted}{haskell} 243 | newtype Parser a = 244 | Parser { runP :: String -> Maybe (a, String) } 245 | 246 | -- consumes only single character and 247 | -- returns it if predicate is true 248 | satisfy :: (Char -> Bool) -> Parser Char 249 | satisfy p = Parser $ \s -> case s of 250 | [] -> Nothing 251 | (x:xs) -> if p x then Just (x, xs) else Nothing 252 | \end{minted} 253 | \end{frame} 254 | 255 | \begin{frame}[fragile] 256 | \frametitle{Combining} 257 | \begin{minted}{haskell} 258 | -- always fails without consuming any input 259 | notok :: Parser () 260 | notok = isnot ok 261 | 262 | -- consumes given character and returns it 263 | char :: Char -> Parser Char 264 | char c = satisfy (== c) 265 | 266 | -- consumes any character or any digit only 267 | anyChar, digit :: Parser Char 268 | anyChar = satisfy (const True) 269 | digit = satisfy isDigit 270 | \end{minted} 271 | \end{frame} 272 | 273 | \begin{frame}[fragile] 274 | \frametitle{Combining} 275 | \begin{minted}{haskell} 276 | ghci> runP eof "" 277 | Just ((),"") 278 | ghci> runP eof "aba" 279 | Nothing 280 | ghci> runP (char 'a') "aba" 281 | Just ('a',"ba") 282 | ghci> runP (char 'x') "aba" 283 | Nothing 284 | \end{minted} 285 | \end{frame} 286 | 287 | \begin{frame}[fragile] 288 | \frametitle{Instances} 289 | The \verb"Functor" instance 290 | \begin{minted}{haskell} 291 | newtype Parser a = 292 | Parser { runP :: String -> Maybe (a, String) } 293 | 294 | instance Functor Parser where 295 | fmap :: (a -> b) -> Parser a -> Parser b 296 | fmap f (Parser parser) = Parser (fmap (first f) . parser) 297 | 298 | first :: (a -> b) -> (a, c) -> (b, c) 299 | first f (a, c) = (f a, c) 300 | \end{minted} 301 | \end{frame} 302 | 303 | \begin{frame}[fragile] 304 | \frametitle{Instances} 305 | The \verb"Applicative" instance 306 | \begin{minted}{haskell} 307 | newtype Parser a = 308 | Parser { runP :: String -> Maybe (a, String) } 309 | 310 | instance Applicative Parser where 311 | pure :: a -> Parser a 312 | pure a = Parser $ \s -> Just (a, s) 313 | 314 | (<*>) :: Parser (a -> b) -> Parser a -> Parser b 315 | Parser pf <*> Parser pa = Parser $ \s -> case pf s of 316 | Nothing -> Nothing 317 | Just (f, t) -> case pa t of 318 | Nothing -> Nothing 319 | Just (a, r) -> Just (f a, r) 320 | \end{minted} 321 | \end{frame} 322 | 323 | \begin{frame}[fragile] 324 | \frametitle{Instances} 325 | The \verb"Monad" instance 326 | \begin{minted}{haskell} 327 | newtype Parser a = 328 | Parser { runP :: String -> Maybe (a, String) } 329 | 330 | instance Monad Parser where 331 | (>>=) :: Parser a -> (a -> Parser b) -> Parser b 332 | Parser pf >>= k = Parser $ \s -> do 333 | (x, rest1) <- runP p1 s 334 | runP (k x) rest1 335 | 336 | instance Alternative Parser where 337 | empty :: Parser a 338 | -- always fails 339 | (<|>) :: Parser a -> Parser a -> Parser a 340 | -- run first, if fails — run second 341 | \end{minted} 342 | \end{frame} 343 | 344 | \begin{frame}[fragile] 345 | \frametitle{Simple parser combinators core} 346 | \begin{minted}{haskell} 347 | -- type 348 | newtype Parser a = 349 | Parser { runP :: String -> Maybe (a, String) } 350 | 351 | -- parsers 352 | eof, ok :: Parser () 353 | satisfy :: (Char -> Bool) -> Parser Char 354 | empty :: Parser a 355 | 356 | -- combinators 357 | pure :: a -> Parser a 358 | (<|>) :: Parser a -> Parser a -> Parser a -- orElse 359 | (>>=) :: Parser a -> (a -> Parser b) -> Parser b -- andThen 360 | \end{minted} 361 | \end{frame} 362 | 363 | \begin{frame}[fragile] 364 | \frametitle{Simple parser combinators core} 365 | \begin{minted}{haskell} 366 | -- combinators 367 | -- * Functor 368 | fmap :: (a -> b) -> Parser a -> Parser b 369 | (<$) :: a -> Parser b -> Parser a 370 | 371 | -- * Applicative 372 | (<*>) :: Parser (a -> b) -> Parser a -> Parser b 373 | (<*) :: Parser a -> Parser b -> Parser a 374 | -- run both in sequence, result of first 375 | 376 | -- * Alternative 377 | many :: Parser a -> Parser [a] 378 | some :: Parser a -> Parser [a] 379 | 380 | -- * Monadic 381 | (>>=) :: Parser a -> (a -> Parser b) -> Parser b -- andThen 382 | \end{minted} 383 | \end{frame} 384 | 385 | \begin{frame}[fragile] 386 | \frametitle{Examples} 387 | \begin{minted}{haskell} 388 | ghci> runP (ord <$> char 'A') "A" 389 | Just (65,"") 390 | 391 | ghci> runP ((\x y -> [x, y]) <$> char 'a' <*> char 'b') "abc" 392 | Just ("ab","c") 393 | ghci> runP ((\x y -> [x, y]) <$> char 'a' <*> char 'b') "xxx" 394 | Nothing 395 | 396 | ghci> runP (char 'a' <* eof) "a" 397 | Just ('a',"") 398 | ghci> runP (char 'a' <* eof) "ab" 399 | Nothing 400 | \end{minted} 401 | \end{frame} 402 | 403 | \begin{frame}[fragile] 404 | \frametitle{Examples} 405 | \begin{minted}{haskell} 406 | ghci> runP (many $ char 'a') "aaabcd" 407 | Just ("aaa","bcd") 408 | ghci> runP (many $ char 'a') "xxx" 409 | Just ("","xxx") 410 | ghci> runP (some $ char 'a') "xxx" 411 | Nothing 412 | 413 | ghci> runP (many $ char 'a') "aaabcd" 414 | Just ("aaa","bcd") 415 | ghci> runP (many $ char 'a') "xxx" 416 | Just ("","xxx") 417 | ghci> runP (some $ char 'a') "xxx" 418 | Nothing 419 | \end{minted} 420 | \end{frame} 421 | 422 | \begin{frame}[fragile] 423 | \frametitle{Examples} 424 | \begin{minted}{haskell} 425 | ghci> runP (many $ char 'a') "aaabcd" 426 | Just ("aaa","bcd") 427 | ghci> runP (many $ char 'a') "xxx" 428 | Just ("","xxx") 429 | ghci> runP (some $ char 'a') "xxx" 430 | Nothing 431 | 432 | ghci> runP (many $ char 'a') "aaabcd" 433 | Just ("aaa","bcd") 434 | ghci> runP (many $ char 'a') "xxx" 435 | Just ("","xxx") 436 | ghci> runP (some $ char 'a') "xxx" 437 | Nothing 438 | \end{minted} 439 | \end{frame} 440 | 441 | \begin{frame}[fragile] 442 | \frametitle{Examples} 443 | \begin{minted}{haskell} 444 | string :: String -> Parser String 445 | -- like 'char' but for string 446 | oneOf :: [String] -> Parser String 447 | -- parse first matched string from list 448 | 449 | data Answer = Yes | No 450 | 451 | yesP :: Parser Answer 452 | yesP = Yes <$ oneOf ["y", "Y", "yes", "Yes", "ys"] 453 | 454 | noP :: Parser Answer 455 | noP = No <$ oneOf ["n", "N", "no", "No"] 456 | 457 | answerP :: Parser Answer 458 | answerP = yesP <|> noP 459 | \end{minted} 460 | \end{frame} 461 | 462 | 463 | \end{document} 464 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### (Approximate) Syllabus 2 | 3 | 1. `stack`, `cabal`, and `Hello World` in Haskell. Module system. `GHC` and `GHCi`. `Hackage` and `Hoogle`. 4 | 2. Introduction to Haskell: Basic syntax, partial application, currying, infix operators. Lists, infinite lists, list comprehension. 5 | 3. Polymorphism: parametric polymorphism and ad-hoc polymorphism. Typeclasses and constraints. Classes `Eq`, `Ord`, `Num`, `Enum` and their instances. 6 | 4. Datatypes: data, newtype, type. Pattern-matching. 7 | 5. `Functor` and its laws, `Foldable`, `Monoid`. Examples. 8 | 6. `Applicative` and its laws, `Traversable`. Examples. 9 | 7. `Monad` and its laws, examples. Do-notation. Alternative and `MonadPlus`. 10 | 8. Monads: `IO`, `State`, `Writer`, `Reader`. 11 | 9. Monad transformers. 12 | 10. Concurrent and parallel Haskell: `async` library. 13 | 14 | ### Sources 15 | 16 | #### Articles and blog posts 17 | 18 | 1. [Philip Wadler. Comprehending Monads](https://ncatlab.org/nlab/files/WadlerMonads.pdf) 19 | 2. [Philip Wadler. Monads for functional programming](https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf) 20 | 3. [Philip Wadler. Theorems for Free](https://people.mpi-sws.org/~dreyer/tor/papers/wadler.pdf) 21 | 4. [Simon Peyton Jones, Andrew Gordon, Sigbjorn Finne. Concurrent Haskell](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.47.7494&rep=rep1&type=pdf) 22 | 5. [Paul Hudak, John Hughes, Simon Peyton Jones, Philip Wadler. A history of Haskell: being lazy with class](https://dl.acm.org/doi/abs/10.1145/1238844.1238856) 23 | 6. [Simon Peyton Jones, Dimitrios Vytiniotis, Stephanie Weirich, Mark Shields. Practical type inference for arbitrary-rank types](https://www.cambridge.org/core/journals/journal-of-functional-programming/article/abs/practical-type-inference-for-arbitraryrank-types/5339FB9DAB968768874D4C20FA6F8CB6) 24 | 7. [Cordelia V Hall, Kevin Hammond, Simon Peyton Jones, Philip L Wadler. Type classes in Haskell](https://dl.acm.org/doi/abs/10.1145/227699.227700) 25 | 8. [Heitor Toledo Lassarote de Paula. A Brief Introduction to Template Haskell](https://serokell.io/blog/introduction-to-template-haskell) 26 | 9. [Vladislav Zavialov. Type Families in Haskell: The Definitive Guide](https://serokell.io/blog/type-families-haskell) 27 | 10. [Vladislav Zavialov. Why Dependent Haskell is the Future of Software Development](https://serokell.io/blog/why-dependent-haskell) 28 | 11. [Vladislav Zavialov. Haskell to Core: Understanding Haskell Features Through Their Desugaring](https://serokell.io/blog/haskell-to-core) 29 | 12. [Simon Marlow, Simon Peyton Jones. The Glasgow Haskell Compiler](https://www.aosabook.org/en/ghc.html) 30 | 31 | #### Books 32 | 33 | 1. [Miran Lipovača. Learn You a Haskell for Great Good](http://learnyouahaskell.com/) 34 | 2. [Sandy Maguire. Thinking with Types: Type-Level Programming in Haskell](https://leanpub.com/thinking-with-types) 35 | 3. [Vitaly Bragilevsky. Haskell in Depth](https://www.manning.com/books/haskell-in-depth) 36 | 4. [Alejandro Serrano Mena. Practical Haskell](https://www.apress.com/gp/book/9781484244791) 37 | 5. [Graham Hutton. Programming in Haskell](https://www.cs.nott.ac.uk/~pszgmh/pih.html) 38 | 39 | #### Types and lambda 40 | 41 | 1. [Benjamin C. Pierce. Types and Programming Languages](https://www.cis.upenn.edu/~bcpierce/tapl/) 42 | 2. [Morten Heine Sørensen, Pawel Urzyczyn. Lectures on the Curry-Howard Isomorphism](https://www.elsevier.com/books/lectures-on-the-curry-howard-isomorphism/sorensen/978-0-444-52077-7) 43 | 3. [J. Roger Hindley. Basic Simple Type Theory](https://www.cambridge.org/core/books/basic-simple-type-theory/0C0B4DB68D19B96E2F2F8AAF8DD738C7) 44 | 4. [Henk Barendregt. Lambda calculi with types](https://home.ttic.edu/~dreyer/course/papers/barendregt.pdf) 45 | 5. [Therry Coquand. Type theory](https://plato.stanford.edu/entries/type-theory/) 46 | 6. [Jean-Yves Girard, Yves Lafont, Paul Taylor. Proofs and types](https://www.paultaylor.eu/stable/prot.pdf) 47 | 48 | #### Videos 49 | 50 | 1. [Simon Peyton Jones. Haskell is Useless](https://www.youtube.com/watch?v=iSmkqocn0oQ) 51 | 2. [Simon Peyton Jones. A History of Haskell: being lazy with class](https://www.youtube.com/watch?v=06x8Wf2r2Mc) 52 | 3. [Philip Wadler. Propositions as types](https://www.youtube.com/watch?v=IOiZatlZtGU) 53 | 4. [Philip Wadler. The First Monad Tutorial](https://www.youtube.com/watch?v=yjmKMhJOJos) 54 | 5. [A Haskell course by Bartosz Milewski](https://www.youtube.com/playlist?list=PL0pwx9zqJ9IamHxRXTf34dC3JeQ2oYmfJ) 55 | 6. [A more comprehensive (than ours) Haskell course by Denis Moskvin, Computer Science Centre (in Russian)](https://compscicenter.ru/courses/func-prog/2019-spring/) 56 | 7. [A lecture course on GHC by Vitaly Bragilevsky, Computer Science Club (in Russian)](https://www.lektorium.tv/node/32421) 57 | 8. [A lecture course on type inference by Vitaly Bragilevsky, Computer Science Club (in Russian)](https://compsciclub.ru/courses/2019-spring/6.423-types/) 58 | 9. [Vladislav Zavialov. Introduction to GUI programming in Haskell](https://www.youtube.com/watch?v=k1aq8ikO-8Q) 59 | 10. [Simon Marlow. Parallel and concurrent programming in Haskell](https://www.youtube.com/watch?v=lqG3mURwUxo) 60 | 61 | ### Guidelines 62 | 63 | We strictly recommend you to follow the Haskell style guideline described in the [following link](https://github.com/serokell/style/blob/master/haskell.md) in order to make in your homework code more readable. 64 | -------------------------------------------------------------------------------- /Theory/slides01.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/slides01.pdf -------------------------------------------------------------------------------- /Theory/slides02.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/slides02.pdf -------------------------------------------------------------------------------- /Theory/slides03.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/slides03.pdf -------------------------------------------------------------------------------- /Theory/slides04.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/slides04.pdf -------------------------------------------------------------------------------- /Theory/slides05.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/slides05.pdf -------------------------------------------------------------------------------- /Theory/slides06.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/slides06.pdf -------------------------------------------------------------------------------- /Theory/slides07.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/slides07.pdf -------------------------------------------------------------------------------- /Theory/src/CardinalMale2007.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/src/CardinalMale2007.jpg -------------------------------------------------------------------------------- /Theory/src/Common-Kestrel-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/src/Common-Kestrel-3.jpg -------------------------------------------------------------------------------- /Theory/src/Kestrel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/src/Kestrel.jpg -------------------------------------------------------------------------------- /Theory/src/Mountain_Bluebird.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/src/Mountain_Bluebird.jpg -------------------------------------------------------------------------------- /Theory/src/ezhik.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/Theory/src/ezhik.jpg -------------------------------------------------------------------------------- /Theory/src/slides01.tex: -------------------------------------------------------------------------------- 1 | \documentclass[xcolor=dvipsnames]{beamer} 2 | 3 | \usetheme[progressbar=frametitle,numbering=fraction,block=fill]{metropolis} 4 | \usepackage{proof} 5 | \usepackage{multirow,bigdelim} 6 | \usepackage[russian]{babel} 7 | \usepackage{minted} 8 | \usepackage{libertinus} 9 | \usefonttheme{serif} 10 | 11 | \usepackage[matrix,arrow]{xy} 12 | \usepackage{tikz} 13 | \usetikzlibrary{shapes.geometric,patterns,positioning,matrix,calc,arrows,shapes,fit,decorations,decorations.pathmorphing} 14 | \usepackage{pifont} 15 | 16 | \newcommand{\adisj}{\vee} 17 | \newcommand{\aconj}{\wedge} 18 | 19 | \newcommand{\Kc}{\mathcal{K}} 20 | 21 | \newcommand{\Ix}{\mathbf{I}} 22 | \newcommand{\Yx}{\mathbf{Y}} 23 | \newcommand{\Bx}{\mathbf{B}} 24 | 25 | \newcommand{\Fx}{\mathbf{F}} 26 | \newcommand{\Tx}{\mathbf{T}} 27 | 28 | \newcommand{\ifxx}[3]{\bigl(\mathbf{if}\ {#1}\ \mathbf{then}\ {#2}\ \mathbf{else}\ {#3}\bigr)} 29 | 30 | \newenvironment{mypic} 31 | {\begin{center}\begin{tikzpicture}[line width=1.5pt]} 32 | {\end{tikzpicture}\end{center}} 33 | 34 | 35 | \newcommand{\BS}{\mathop{\backslash}} 36 | \newcommand{\SL}{\mathop{/}} 37 | \newcommand{\Pc}{\mathcal{P}} 38 | \newcommand{\ACT}{\mathbf{ACT}} 39 | \newcommand{\ACTomega}{\ACT_\omega} 40 | \newcommand{\TM}{\mathfrak{M}} 41 | \newcommand{\Gc}{\mathcal{G}} 42 | 43 | \newcommand{\MALC}{\mathbf{MALC}} 44 | \newcommand{\ILL}{\mathbf{ILL}} 45 | \newcommand{\IAL}{\mathbf{IAL}} 46 | \newcommand{\AMALC}{\mathbf{AMALC}} 47 | 48 | \newcommand{\eL}{\mathbf{\boldsymbol{!}L}} 49 | \newcommand{\rL}{\mathbf{\boldsymbol{!}^r L}} 50 | \newcommand{\reL}{\mathbf{\boldsymbol{!}^{re} L}} 51 | 52 | \newcommand{\exL}{\boldsymbol{!}_{\leqslant 1}\mathbf{L}} 53 | \newcommand{\rxL}{\boldsymbol{!}_{\leqslant 1}^{\mathbf{r}} \mathbf{L}} 54 | \newcommand{\rexL}{\boldsymbol{!}_{\leqslant 1}^{\mathbf{re}} \mathbf{L}} 55 | 56 | \newcommand{\Dc}{\mathcal{D}} 57 | 58 | \newcommand{\Int}{\mathbf{Int}} 59 | 60 | \newcommand{\Factx}{\mathrm{Fact}} 61 | \newcommand{\Prevx}{\mathbf{Prev}} 62 | 63 | \newtheorem{theoremr}{Теорема} 64 | 65 | \begin{document} 66 | 67 | \title{Функциональное программирование} 68 | \subtitle{Лекция 1} 69 | \date{} 70 | \author{Степан Львович Кузнецов} 71 | \institute{НИУ ВШЭ, факультет компьютерных наук} 72 | 73 | \maketitle 74 | 75 | \begin{frame}{О курсе} 76 | 77 | \begin{itemize}[<+->] 78 | \item Курс посвящён функциональной парадигме программирования на примере одного из наиболее известных функциональных языков --- Haskell. 79 | \item На лекциях: теоретические основы функционального программирования ($\lambda$-исчисление, выведение типов, монады-лимонады и проч.). 80 | \item На практических занятиях (Даниил Рогозин и Юрий Сыровецкий): программирование на Haskell'е. 81 | \item Теория и практика связаны между собой: как в шутку говорят, {\em Haskell --- это язык, в котором нельзя напечатать ``Hello, World'' без знания теории категорий.} 82 | \end{itemize} 83 | 84 | 85 | \end{frame} 86 | 87 | \begin{frame}{Функции как объекты} 88 | 89 | \begin{itemize}[<+->] 90 | \item Функциональная парадигма программирования существенно отличается от обычной (императивной). 91 | \item Мы постепенно будем обсуждать её особенности. 92 | \item {\bf Первое свойство,} объясняющее термин {\em <<функциональный>>:} функции являются полноправными <<гражданами>> (объектами) языка. Functions are first-class citizens. 93 | \item В частности, функция может быть передана как аргумент другой функции. В этом случае последняя называется {\em функцией высшего порядка.} 94 | \end{itemize} 95 | 96 | 97 | \end{frame} 98 | 99 | 100 | \begin{frame}[fragile]{Функция как объект в C} 101 | 102 | \begin{itemize}[<+->] 103 | \item Начнём с примеров функций высших порядков, которые встречаются в императивных языках. 104 | \item Так, в стандартной библиотеке C есть функция сортировки: 105 | \begin{minted}{c} 106 | void qsort(void *base, size_t nmemb, size_t size, 107 | int (*compar)(const void *, const void *)); 108 | \end{minted} 109 | 110 | \item Эта функция может сортировать массив {\em произвольных данных.} 111 | \item Отсюда тип \mintinline{c}{void*} --- указатель на произвольный объект. (При этом не производится проверка корректности типов данных, что плохо.) 112 | \end{itemize} 113 | 114 | \end{frame} 115 | 116 | \begin{frame}[fragile]{Функция как объект в C} 117 | 118 | \begin{itemize}[<+->] 119 | \item Функция \mintinline{c}{compar} возвращает значение $<0$, если первый аргумент меньше второго, $=0$, если равны, и $>0$, если второй аргумент меньше. 120 | \item Например, для сравнения строк (\mintinline{c}{char*}) по алфавиту используется функция \mintinline{c}{strcmp} с соответствующим приведением типов: 121 | \begin{minted}{c} 122 | int cmpstringp(const void *p1, const void *p2) 123 | { 124 | return strcmp(*(const char **) p1, *(const char **) p2); 125 | } 126 | \end{minted} 127 | \item Технически передача функции как аргумента реализуется в C как передача указателя на место в памяти, где находится код этой функции --- так что сгенерировать новую функцию <<на лету>> не получится. 128 | \end{itemize} 129 | 130 | 131 | \end{frame} 132 | 133 | 134 | \begin{frame}[fragile]{Функция как объект в Python'е} 135 | 136 | \begin{itemize}[<+->] 137 | \item Аналогично устроена сортировка в Python'е: 138 | \begin{minted}{python} 139 | bigrams = {"AB": [10, 11, 12], "BC": [5, -5, 8], 140 | "CD": [105, 1, 0], "DE": [6, 6], "EF": [15, 20, 15], 141 | "FG": [22, 11, 32], "GH": [20, 20, 20]} 142 | srtbg = sorted(bigrams, key=lambda key: sum(bigrams[key]), 143 | reverse=True) 144 | \end{minted} 145 | \item Здесь ради эффективности используется не функция сравнения, а функция вычисления ключа (которые потом сравниваются как целые числа). 146 | \item Интересно использование ключевого слова \mintinline{python}{lambda} для создания безымянной функции <<на месте>>. 147 | \end{itemize} 148 | 149 | \end{frame} 150 | 151 | \begin{frame}{$\lambda$-оператор} 152 | 153 | \begin{itemize}[<+->] 154 | \item Знаком $\lambda$ выделяется та переменная, которую мы будем считать аргументом функции. 155 | \item В теоретическом материале мы будем использовать обозначение $\lambda x. u$, где $u$ --- выражение ({\em терм}), возможно содержащее $x$: 156 | \[ 157 | \lambda x . \underbrace{\mbox{\fbox{ $\ldots x \ldots x \ldots x \ldots$}}}_u 158 | \] 159 | \item При вычислении значения функции $\lambda x . u$ на аргументе $x = a$ нужно подставить $a$ вместо $x$ вместо всех {\em свободных} (т.е. не связанных другими $\lambda$'ми) вхождений $x$ в $u$. 160 | \item Это называется {\em $\beta$-преобразованием,} о нём мы поговорим позже. 161 | \item В математике вместо $\lambda x .u $ пишут $x \mapsto u$. 162 | \end{itemize} 163 | 164 | 165 | 166 | \end{frame} 167 | 168 | \begin{frame}[fragile]{Функции и изменяемость} 169 | 170 | \begin{itemize}[<+->] 171 | \item Посмотрим на следующий код: 172 | \begin{minted}{python} 173 | x=5 174 | f=lambda y : y+x 175 | print f(2) 176 | x=7 177 | print f(2) 178 | \end{minted} 179 | \item Значение \mintinline{python}{f(2)} изменилось: действительно, \mintinline{python}{lambda} создаёт новую безымянную функцию, которая, помимо своего аргумента \mintinline{python}{y} имеет также неявный доступ к переменной \mintinline{python}{x}. 180 | \end{itemize} 181 | 182 | 183 | \end{frame} 184 | 185 | 186 | \begin{frame}[fragile]{Функции и изменяемость} 187 | 188 | \begin{itemize}[<+->] 189 | \item Таким образом, в Python'е функции, введённые с помощью \mintinline{python}{lambda}, ведут себя всё же не совсем как обычные объекты. 190 | \item Действительно, если бы вместо \mintinline{python}{f} была бы числовая переменная: 191 | \begin{minted}{python} 192 | x=5 193 | f=x+2 194 | print f 195 | x=7 196 | print f 197 | \end{minted} 198 | то значение бы не поменялось. 199 | \end{itemize} 200 | 201 | \end{frame} 202 | 203 | \begin{frame}{Функции и изменяемость} 204 | 205 | \begin{itemize}[<+->] 206 | \item Во многих функциональных языках (в частности, в Haskell'е) проблема с изменением значений решена радикально. 207 | \item В этом состоит {\bf второе свойство} --- immutability: значения переменных вообще запрещено изменять! 208 | \item Это свойство выглядит довольно дико, принуждая к созданию большого числа объектов вместо изменений одного. Однако этот негативный эффект компенсируется сборкой мусора и оптимизацией. 209 | \end{itemize} 210 | \end{frame} 211 | 212 | \begin{frame}{Неизменяемость} 213 | \begin{itemize}[<+->] 214 | \item За счёт неизменяемости функции получаются {\em чистыми} в математическом смысле: возвращаемое значение однозначно определяется значениями аргументов, и при этом функция не имеет {\em побочных эффектов.} 215 | \item В императивных языках, наоборот, функции взаимодействуют с неким {\em состоянием внешнего мира.} 216 | \item Это делает осмысленными, в частности, функции, которые ничего не принимают и не возвращают: 217 | \mintinline{c}{void func();} 218 | \item Конечно, связь с внешним миром нужна, но в <<чистых>> функциональных языках она прописывается явно. 219 | \item В Haskell'е для этого (в частности --- для ввода-вывода) используется механизм {\em монад,} основанный на теоретико-категорной конструкции. 220 | \end{itemize} 221 | \end{frame} 222 | 223 | \begin{frame}{Вычисление как преобразование} 224 | 225 | \begin{itemize}[<+->] 226 | \item Наконец, ещё более фундаментальное {\bf третье свойство,} отличающее функциональные языки от императивных, заключается в самом понятии вычислительного процесса. 227 | \item В функциональной парадигме вычисление есть последовательное {\em преобразование} некоего выражения ({\em терма}), пока он не дойдёт до некоторой далее не преобразуемой формы. (Например, терм, в явном виде представляющий натуральное число.) 228 | \item Преобразования призваны <<упрощать>> терм, и поэтому также называются {\em редукциями.} 229 | \item В реальности редукции не всегда упрощают терм, и возможны бесконечные их последовательности (что соответствует неостанавливающейся программе на императивном языке). 230 | \end{itemize} 231 | 232 | 233 | \end{frame} 234 | 235 | \begin{frame}{Вычисление как преобразование} 236 | 237 | \begin{itemize}[<+->] 238 | \item В этом смысле исполнение функциональной программы напоминает вычисление арифметического выражения: 239 | \[ 240 | (1+2) \cdot (3+4) \to 241 | 3 \cdot (3+4) \to 3 \cdot 7 \to 21. 242 | \] 243 | \item При этом, в отличие от императивной программы, порядок преобразований не задан жёстко: 244 | \[ 245 | (1+2) \cdot (3+4) \to 246 | (1+2) \cdot 7 \to 3 \cdot 7 \to 21. 247 | \] 248 | 249 | \item Преобразование можно применить к любому подвыражению (подтерму), которое может быть упрощено. Такой подтерм называется {\em редексом.} 250 | \end{itemize} 251 | 252 | 253 | 254 | \end{frame} 255 | 256 | 257 | \begin{frame}{Конфлюэнтность} 258 | 259 | \begin{itemize}[<+->] 260 | \item Если синтаксис разработан неправильно, то разные последовательности редукций могут давать разные ответы. Например, так получится, если не использовать скобки: 261 | \[ 262 | \xymatrix@-1em{ 263 | 1+2 \cdot 3+4 \ar[r]\ar[dd] & 3 \cdot 3 + 4 \ar[r]\ar[d] & 3 \cdot 7 \ar[r] & 21\\ 264 | & 9 + 4 \ar[r] & 13\\ 265 | 1+6+4 \ar[r] & 7+4 \ar[r] & 11 266 | } 267 | \] 268 | \item В <<хороших>> системах этого не происходит за счёт {\em конфлюэнтности (свойства Чёрча -- Россера):} 269 | если $u \twoheadrightarrow v_1$ и $u \twoheadrightarrow v_2$, то существует такой терм $w$, что $v_1 \twoheadrightarrow w$ и $v_2 \twoheadrightarrow w$. 270 | \end{itemize} 271 | 272 | 273 | \end{frame} 274 | 275 | \begin{frame}{Ленивость} 276 | 277 | \begin{itemize}[<+->] 278 | \item За счёт порядка преобразований какие-то подтермы могут оказаться вообще не вычисленными. 279 | \item Например, $\mathrm{length} [ u,v,w ]$ можно сразу редуцировать к $3$, не пытаясь вычислить значения $u$, $v$, $w$. 280 | \item Это свойство называется {\em ленивостью} вычислений. 281 | \end{itemize} 282 | 283 | 284 | \end{frame} 285 | 286 | 287 | \begin{frame}{$\lambda$-исчисление} 288 | 289 | \begin{itemize} 290 | \item $\lambda$-исчисление --- простейшая модель и основа функциональных языков программирования. 291 | \item<2-> Термы $\lambda$-исчисления ({\em $\lambda$-термы}) строятся из переменных с помощью всего лишь двух операций: 292 | \begin{itemize} 293 | \item {\em применение:} если $u$ и $v$ --- термы, то $(uv)$ --- терм; 294 | \item {\em $\lambda$-абстракция:} 295 | если $u$ --- терм, $x$ --- переменная, то 296 | $\lambda x . u$ --- терм. 297 | \end{itemize} 298 | \item<3-> Запись $(uv)$ означает применение функции $u$ к $v$. 299 | \item<4-> Более привычное обозначение было бы $u(v)$, однако бесскобочное обозначение также применяется в математике --- например, $\sin \alpha$. 300 | \item<5-> В функциональных языках чаще используется бесскобочная запись. 301 | \end{itemize} 302 | 303 | 304 | \end{frame} 305 | 306 | \begin{frame}{Функции многих аргументов} 307 | 308 | \begin{itemize}[<+->] 309 | \item С помощью $\lambda$-абстракции можно задать функцию {\em одного} аргумента $x$. Как быть с функциями многих аргументов? 310 | \item Для этого используется приём, называемый {\em каррированием} (в честь Х.\,Карри): $f = \lambda x. \lambda y.\lambda z. u$. 311 | \item В каррированном виде функция $f$ является функцией одного аргумента ($x$), возвращающая, в свою очередь, опять же функцию одного аргумента ($y$) и т.д. 312 | \item Для каррированных функций многих аргументов используется сокращённое обозначение $\lambda xyz. u$. 313 | \end{itemize} 314 | 315 | 316 | \end{frame} 317 | 318 | \begin{frame}[fragile]{Примеры и бестиповость} 319 | 320 | \begin{itemize}[<+->] 321 | \item Простейший пример $\lambda$-терма: $\Ix = \lambda x.x$. Этот терм реализует тождественную функцию: 322 | \begin{minted}{python} 323 | def identity(x): 324 | return x 325 | \end{minted} 326 | \item Отметим, что наше $\lambda$-исчисление (как и Python) {\em бестиповое:} любой терм можно применить, как функцию, к любому другому. 327 | 328 | \item Более содержательный пример --- абстрактная программа для композиции функций 329 | \[ 330 | \Bx = \lambda f g x . f(gx). 331 | \] 332 | 333 | \end{itemize} 334 | 335 | \end{frame} 336 | 337 | \begin{frame}{Преобразования $\lambda$-термов} 338 | 339 | \begin{itemize}[<+->] 340 | \item Главное преобразование термов в $\lambda$-исчислении --- {\em $\beta$-редукция:} 341 | \[ 342 | (\lambda x . u) v \to_\beta 343 | u[x := v]. 344 | \] 345 | \vspace*{-1em} 346 | \begin{itemize} 347 | \item Запись $u[x:=v]$ означает подстановку $v$ вместо каждого свободного вхождения $x$ в $u$. 348 | \item Условие корректности подстановки: переменные, свободные в $v$, не должны оказаться связанными в $u$. (Например, 349 | $(\lambda x. \lambda y. x) y \mathop{\not\to_\beta} \lambda y .y$.) 350 | \end{itemize} 351 | \item $\beta$-редукция может применяться к произвольному редексу вида $(\lambda x .u)v$: 352 | \[ 353 | \mbox{\fbox{$\quad\ldots\quad (\lambda x.u)v \quad \ldots\quad$}} \to_\beta 354 | \mbox{\fbox{$\quad\ldots\quad u[x:=v] \quad \ldots\quad$}} 355 | \] 356 | 357 | \end{itemize} 358 | 359 | 360 | \end{frame} 361 | 362 | \begin{frame}{Преобразования $\lambda$-термов} 363 | 364 | \begin{itemize}[<+->] 365 | \item Помимо $\beta$-редукции имеется вспомогательное преобразование --- {\em $\alpha$-конверсия:} 366 | \[ 367 | \lambda x. u \to_\alpha \lambda y. u[x := y], 368 | \] 369 | где $y$ --- новая переменная. 370 | 371 | \item Термы, которые можно свести к одному и тому же $\alpha$-конверсиями, называются {\em $\alpha$-равными} и в дальнейшем считаются вариантами одного терма. 372 | 373 | \item $\alpha$-конверсия помогает решить проблему с недопустимой подстановкой при $\beta$-редукции: 374 | \[ 375 | (\lambda x .\lambda y. x) y =_\alpha 376 | (\lambda x . \lambda z. x) y \to_\beta 377 | \lambda z. y 378 | \] 379 | 380 | \end{itemize} 381 | 382 | 383 | \end{frame} 384 | 385 | \begin{frame}{Нормализация} 386 | 387 | \begin{itemize}[<+->] 388 | \item {\em Нормальная форма} --- это терм, в котором нет $\beta$-редексов (т.е. который далее нельзя редуцировать). 389 | 390 | \item {\bf Теорема.} $\beta$-редукция обладает свойством Чёрча -- Россера: 391 | \[ 392 | \xymatrix{ 393 | & v_1 \ar@{-->>}[dr] & \\ 394 | u \ar@{->>}[ur]\ar@{->>}[dr] & & w \\ 395 | & v_2 \ar@{-->>}[ur] 396 | } 397 | \] 398 | 399 | \begin{itemize} 400 | \item Доказательство этой, как и некоторых других, теорем, будет опубликовано в виде конспекта. 401 | \end{itemize} 402 | 403 | 404 | \item {\bf Следствие.} Данный терм не может редуцироваться к двум $\alpha$-разным нормальным формам. 405 | \end{itemize} 406 | 407 | 408 | \end{frame} 409 | 410 | \begin{frame}{Нормализация} 411 | 412 | \begin{itemize}[<+->] 413 | \item Поскольку нормальная форма не зависит от пути, которым мы к ней пришли, её можно считать {\em результатом вычисления значения} данного $\lambda$-терма. 414 | 415 | \item Однако всё не так просто. 416 | 417 | \item Бывают термы, которые вообще не приводятся к нормальной форме (любое вычисление бесконечно). 418 | 419 | \item Бывают и такие, для которых один путь приводит к нормальной форме ({\em слабая нормализуемость}), а другой бесконечен. 420 | 421 | \item Наконец, если все пути приводят к нормальной форме, то такой терм {\em сильно нормализуем.} 422 | \end{itemize} 423 | 424 | 425 | \end{frame} 426 | 427 | \begin{frame}{Примеры} 428 | 429 | \begin{itemize} 430 | \item Пусть $\omega = \lambda x. (xx)$, а $\Omega = \omega\omega$. Тогда $\Omega$ редуцируется только сам к себе: 431 | \[\Omega = (\lambda x.(xx)) (\lambda x. (xx)) \to_\beta (xx)[x := \omega] = \omega\omega = \Omega,\] 432 | значит, он не нормализуем. 433 | \item Можно построить и терм, который будет при <<редукции>> бесконечно разрастаться. 434 | \item Бывает и слабо нормализуемый терм, не являющийся сильно нормализуемым: например, $(\lambda x . y) \Omega$. 435 | \end{itemize} 436 | 437 | 438 | \end{frame} 439 | 440 | 441 | \begin{frame}{Нормализуемость} 442 | 443 | \begin{itemize}[<+->] 444 | \item Из-за существования слабо, но не сильно нормализуемых термов важен порядок, или {\em стратегия,} применения редукций. 445 | \item О различных стратегиях редукций мы поговорим на следующей лекции. 446 | \item А пока что коротко обсудим вычислительные возможности бестипового $\lambda$-исчисления. 447 | \end{itemize} 448 | 449 | 450 | \end{frame} 451 | 452 | 453 | \begin{frame}{Натуральные числа по Чёрчу} 454 | 455 | \begin{itemize}[<+->] 456 | \item Натуральное число $n$ можно представить следующим образом с помощью константы $o$ (ноль) и функции $s$ (взятие следующего): 457 | \[ 458 | \underbrace{s(s \ldots (s}_{\text{$n$ раз}} 459 | o) \ldots) 460 | \] 461 | 462 | \item В <<чистом>> $\lambda$-исчислении у нас нет констант, поэтому мы просто абстрагируем $s$ и $o$ как переменные, получив замкнутый (без свободных переменных) терм, называемый {\em нумералом Чёрча:} 463 | \[ 464 | \underline{n} = \lambda s o. \underbrace{s(s \ldots (s}_{\text{$n$ раз}} 465 | o) \ldots) 466 | \] 467 | 468 | \end{itemize} 469 | 470 | 471 | \end{frame} 472 | 473 | \begin{frame}{Представление функций} 474 | 475 | \begin{itemize}[<+->] 476 | \item Заметим, что нумералы Чёрча не содержат $\beta$-редексов, т.е. являются нормальными формами. 477 | 478 | \item Таким образом, можно считать, что некий $\lambda$-терм $F$ является программой, вычисляющей $k$-местную функцию $f$ на натуральных числах, если 479 | \[F \, \underline{n_1} \ldots \underline{n_k} 480 | \twoheadrightarrow_\beta 481 | \underline{f(n_1, \ldots, n_k)}\] 482 | 483 | \item Здесь, в соответствии с функциональной парадигмой, процесс {\em вычисления} значения функции $f$ представляется в виде {\em редукции} терма $F \, \underline{n_1} \ldots \underline{n_k}$. 484 | 485 | \item В силу конфлюэнтности, результат вычисления определяется однозначно. 486 | \end{itemize} 487 | 488 | 489 | \end{frame} 490 | 491 | \begin{frame}{Представление функций} 492 | 493 | \begin{itemize}[<+->] 494 | \item Однако возможна ситуация слабой нормализуемости, при которой мы можем пойти по <<неправильному>> пути и не достичь нормальной формы (которая при этом существует). 495 | 496 | \item Бороться с этим нужно выбором правильной {\em стратегии нормализации,} о чём мы поговорим на следующей лекции. 497 | 498 | \item Короткий ответ: если нормальная форма существует, то её можно достичь, всегда редуцируя {\em самый левый} (считая по начальной $\lambda$'е) $\beta$-редекс. 499 | \end{itemize} 500 | 501 | 502 | \end{frame} 503 | 504 | 505 | \begin{frame}{Представление функций} 506 | 507 | \begin{itemize} 508 | \item На нумералах Чёрча легко определить операции сложения и умножения: 509 | \begin{align*} 510 | & \underline{n} + \underline{m} = 511 | \lambda s o. (\underline{n} s)(\underline{m} s o); 512 | \\ 513 | & \underline{n} \cdot \underline{m} = 514 | \lambda s o. \underline{m}(\underline{n} s) o. 515 | \end{align*} 516 | 517 | \item Абстрагируя, получаем термы для (двуместных) функций сложения и умножения: 518 | \begin{align*} 519 | & \boldsymbol{+} = \lambda xyso. (xs)(yso);\\ 520 | & \boldsymbol{\cdot} = \lambda xyso. x(ys)o. 521 | \end{align*} 522 | 523 | \item {\bf Задача.} Задайте $\lambda$-термом функцию <<предшественник>>: 524 | \[ 525 | \mathrm{Prev}(n) = \left\{ 526 | \begin{aligned} 527 | & 0, && \mbox{если $n = 0$;}\\ 528 | & n-1, && \mbox{если $n > 0$.} 529 | \end{aligned} \right. 530 | \] 531 | 532 | \end{itemize} 533 | 534 | 535 | 536 | \end{frame} 537 | 538 | \begin{frame}{Представление функций} 539 | 540 | \begin{itemize}[<+->] 541 | \item На самом деле, $\lambda$-термы умеют намного больше, чем сложение и умножение: с их помощью можно записать {\bf любую алгоритмически вычислимую} функцию на натуральных числах. 542 | \item При этом функция может быть не всюду определённой --- тогда на соответствующих значениях аргументов терм $F\, \underline{n_1} \ldots \underline{n_k}$ будет ненормализуемым. 543 | \item Мы обсуждаем такой <<низкоуровневый>> язык, как $\lambda$-исчисление, чтобы не перегружать изложение синтаксическими деталями. 544 | \item Можно сказать, что всё остальное в функциональных языках --- надстройка для удобства, <<синтаксический сахар>>. 545 | \end{itemize} 546 | 547 | \end{frame} 548 | 549 | 550 | \begin{frame}{Булевы операции} 551 | 552 | \begin{itemize}[<+->] 553 | \item В $\lambda$-исчислении можно ввести константы <<истина>> и <<ложь>> как функции выбора из двух аргументов: 554 | \[ 555 | \Tx = \lambda t. \lambda f. t; \qquad 556 | \Fx = \lambda t. \lambda f. f. 557 | \] 558 | 559 | \item Условный оператор: 560 | \( 561 | \ifxx{b}{u}{v} = b\,u\, v. 562 | \) 563 | 564 | \item Логические операции: 565 | \begin{align*} 566 | & (b_1 \mathop{\mathbf{and}} b_2) = 567 | \ifxx{b_1}{\ifxx{b_2}{\Tx}{\Fx}}{\Fx}\\ 568 | & \ldots 569 | \end{align*} 570 | 571 | \item Проверка на ноль: 572 | $\mathbf{Zero} = \lambda x. (x \, (\lambda z. \Fx) \, \Tx)$. 573 | \end{itemize} 574 | 575 | 576 | \end{frame} 577 | 578 | 579 | \begin{frame}{Рекурсия} 580 | 581 | \begin{itemize}[<+->] 582 | \item Чтобы достичь полноты по Тьюрингу, осталось реализовать {\bf рекурсию} (которая в функциональных языках используется повсеместно, в т.ч. вместо циклов). 583 | 584 | \item Пример: факториал $f(n) = n! = 1 \cdot 2 \cdot \ldots \cdot n$. 585 | 586 | \item Рекурсивная реализация: 587 | \[ 588 | \Factx = \lambda x. 589 | \ifxx{\mathbf{Zero}\ x}{\underline{1}}{(\Factx\,(\Prevx\ x) \cdot x)} 590 | \] 591 | 592 | \item Проблема: $\Factx$ определяется через самоё себя. 593 | 594 | \item С помощью $\lambda$-абстракции можно сделать зависимость в правой части явной (функциональной): 595 | \[ 596 | \Factx = \underbrace{\bigl(\lambda g. \lambda x. 597 | \ifxx{\mathbf{Zero}\ x}{\underline{1}}{(g\,(\Prevx\ x) \cdot x)} \bigr)}_F \, 598 | \Factx 599 | \] 600 | 601 | \end{itemize} 602 | 603 | 604 | \end{frame} 605 | 606 | 607 | 608 | \begin{frame}{Рекурсия} 609 | 610 | \begin{itemize}[<+->] 611 | \item Чтобы реализовать рекурсивно определённую функцию, используется {\em комбинатор неподвижной точки} ($\Yx$-комбинатор, или комбинатор Карри) со следующим свойством: $\Yx\, F =_\beta F(\Yx\,F)$. 612 | \item $\Yx = \lambda f. \bigl( 613 | (\lambda x. f(xx)) (\lambda x. f(xx)) \bigr)$ 614 | \item Имеем $\Yx\, F \to_\beta Y_F = 615 | (\lambda x. F(xx)) (\lambda x. F(xx))$, при этом $Y_F$ --- неподвижная точка для $F$: $Y_F \to_\beta F(Y_F)$. 616 | \item Терм, использующий $\Yx$-комбинатор, никогда не будет сильно нормализуемым: 617 | $Y_F \to_\beta F(Y_F) \to_\beta F(F(Y_F)) \to_\beta \ldots$ 618 | \item Однако если разбирать $F$, то процесс может сойтись: например, $\Factx \, \underline{n} \twoheadrightarrow_\beta \underline{n!}$ 619 | \end{itemize} 620 | 621 | 622 | 623 | \end{frame} 624 | 625 | 626 | \begin{frame}{Рекурсия} 627 | \[\hspace*{-1em} 628 | \Factx\, \underline{0} \to_\beta 629 | Y_F \, \underline{0} \to_\beta F \, Y_F \, \underline{0} \twoheadrightarrow_\beta 630 | \ifxx{\mathbf{Zero}\, \underline{0}}{\underline{1}}{(Y_F \, (\Prevx\ \underline{0})) \cdot \underline{0}} \twoheadrightarrow_\beta \underline{1} 631 | \] 632 | 633 | \visible<2->{ 634 | \begin{multline*} 635 | \Factx\, \underline{n+1} \to_\beta 636 | Y_F \, \underline{n+1} \to_\beta 637 | F \, Y_F \, \underline{n+1} 638 | \twoheadrightarrow_\beta\\ 639 | \twoheadrightarrow_\beta 640 | \ifxx{\mathbf{Zero}\, \underline{n+1}} 641 | {\underline{1}} 642 | {(Y_F \, (\Prevx\ \underline{n+1})) \cdot \underline{n+1}} 643 | \twoheadrightarrow_\beta\\ 644 | \twoheadrightarrow_\beta 645 | (Y_F \, \underline{n}) \cdot \underline{n+1} 646 | \end{multline*} 647 | 648 | } 649 | 650 | 651 | \end{frame} 652 | 653 | 654 | \begin{frame}{Рекурсия} 655 | 656 | \begin{itemize}[<+->] 657 | \item Если рекурсивное определение <<плохое>> (например, забыто $\Prevx$), то терм будет ненормализуемым: {\bf любая} последовательность редукций бесконечна. 658 | \item Статически проверить это невозможно, поскольку задача останова алгоритмически неразрешима. 659 | \item $\Yx$ --- не единственный комбинатор неподвижной точки. Таков, например, также {\em комбинатор Тьюринга} 660 | $\boldsymbol{\Theta} = 661 | (\lambda xy. y(xxy)) (\lambda xy. y(xxy))$ 662 | \item ... и даже $??????????????????????????$, где\\ 663 | \mbox{$? = \lambda abcdef ghijklmnopqstuvwxyzr.r(thisisaf ixedpointcombinator)$} 664 | \end{itemize} 665 | 666 | \end{frame} 667 | 668 | \begin{frame}[fragile]{Y-комбинатор в Python'е} 669 | 670 | \begin{itemize}[<+->] 671 | \item Терм, содержащий $\Yx$-комбинатор, не будет корректным, если следить за типами данных. Действительно, он содержит $xx$, значит, переменная $x$ должна одновременно быть некоторого типа $A$ и типа функции $A \to B$. 672 | \item Тем не менее, в бестиповом языке, таком как Python, $\Yx$-комбинатор можно реализовать. 673 | \item Наивная попытка: 674 | \begin{minted}{python} 675 | Y = lambda f : ((lambda x : f(x(x))) (lambda x : f(x(x)))) 676 | fact = Y (lambda g : lambda n : (n and n * g(n-1)) or 1) 677 | \end{minted} 678 | \item Не работает: ``maximum recursion depth exceeded''. Python использует не тот порядок вычислений и уходит в бесконечное вычисление. 679 | \end{itemize} 680 | 681 | 682 | \end{frame} 683 | 684 | \begin{frame}[fragile]{Y-комбинатор в Python'е} 685 | 686 | \begin{itemize} 687 | \item Положение можно исправить, заменив $xx$ на $\lambda z . xxz$: 688 | \end{itemize} 689 | \vspace*{-1.5em} 690 | {\footnotesize 691 | \hspace*{-2em} 692 | \begin{minted}{python} 693 | Y = lambda f : ((lambda x : f(x(x))) (lambda x : f(lambda z : x(x)(z)))) 694 | \end{minted} 695 | } 696 | 697 | 698 | \begin{itemize} 699 | \item<2-> Математически $h$ и $\lambda z. hz$ эквивалентны (если $h$ не зависит от $z$), однако $\beta$-редукцией друг к другу не сводятся --- это {\em $\eta$-эквивалентность.} 700 | \item<3-> Вычисление откладывается до тех пор, пока \mintinline{python}{lambda z : x(x)(z)} окажется к чему-то применено. 701 | \item<4-> Теперь всё работает: например, \mintinline{python}{fact(6)} даёт 720. 702 | \end{itemize} 703 | 704 | 705 | 706 | \end{frame} 707 | 708 | \begin{frame}{Y-комбинатор в Python'е} 709 | 710 | \begin{itemize}[<+->] 711 | \item {\bf Упражнение.} Реализуйте на Python'е комбинатор Тьюринга $\boldsymbol{\Theta} = 712 | (\lambda xy. y(xxy)) (\lambda xy. y(xxy))$ (с соответствующим $\eta$-преобразованием). 713 | \item {\bf Упражнение.} Верно ли, что для комбинатора $\widetilde{\Yx} = \lambda f. (\lambda x. f(xx)) (\lambda x. f(\lambda z. xxz))$ и терма $F$ из определения факториала терм $\widetilde{\Yx} F$ сильно нормализуем? 714 | \end{itemize} 715 | 716 | 717 | \end{frame} 718 | 719 | 720 | 721 | \end{document} 722 | 723 | -------------------------------------------------------------------------------- /final_exam_2021_autumn.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/final_exam_2021_autumn.pdf -------------------------------------------------------------------------------- /quiz2021_autumn.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serokell/hse-haskell-course-src/bfed3f0a572341810a66fa24e3d6934d2db8372f/quiz2021_autumn.pdf --------------------------------------------------------------------------------