From ce837453e0e2b47901254e71c38dfb0e0349f9f7 Mon Sep 17 00:00:00 2001 From: Trifon Trifonov Date: Thu, 5 Dec 2024 09:12:24 +0200 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=B7=D1=82=D1=80=D0=B8=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=20=D0=BD=D0=B0=20=D0=BD=D0=B5=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B1=D0=BB=D0=B5=D0=BC=D0=BD=D0=B8=D1=82=D0=B5=20=D0=BB=D0=B5?= =?UTF-8?q?=D0=BA=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 29 +- 0.0-org.tex | 90 --- 0.1-intro.tex | 383 ---------- 1.1-scheme_basics.tex | 403 ----------- 1.2-scheme_envs.tex | 1041 --------------------------- 1.4-scheme_lists.tex | 657 ----------------- 1.5-scheme_ds.tex | 1317 ----------------------------------- 1.6-scheme_mutation.tex | 97 --- 1.7-scheme_streams.tex | 344 --------- 2.1-haskell_basics.tex | 374 ---------- 2.2-haskell_defs.tex | 352 ---------- 2.3-haskell_lists.tex | 765 -------------------- 2.4-haskell_lazy.tex | 688 ------------------ 2.5-haskell_data.tex | 616 ---------------- 2.6-haskell_io.tex | 414 ----------- 2.7-haskell_func.tex | 338 --------- 16 files changed, 1 insertion(+), 7907 deletions(-) delete mode 100644 0.0-org.tex delete mode 100644 0.1-intro.tex delete mode 100644 1.1-scheme_basics.tex delete mode 100644 1.2-scheme_envs.tex delete mode 100644 1.4-scheme_lists.tex delete mode 100644 1.5-scheme_ds.tex delete mode 100644 1.6-scheme_mutation.tex delete mode 100644 1.7-scheme_streams.tex delete mode 100644 2.1-haskell_basics.tex delete mode 100644 2.2-haskell_defs.tex delete mode 100644 2.3-haskell_lists.tex delete mode 100644 2.4-haskell_lazy.tex delete mode 100644 2.5-haskell_data.tex delete mode 100644 2.6-haskell_io.tex delete mode 100644 2.7-haskell_func.tex diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 73cf588..b773dba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,22 +21,7 @@ jobs: strategy: matrix: file: [ - 0.0-org, - 0.1-intro, - 1.1-scheme_basics, - 1.2-scheme_envs, - # 1.3-scheme_highorder, - 1.4-scheme_lists, - 1.5-scheme_ds, - 1.6-scheme_mutation, - 1.7-scheme_streams, - 2.1-haskell_basics, - 2.2-haskell_defs, - 2.3-haskell_lists, - 2.4-haskell_lazy, - # 2.5-haskell_data, - # 2.6-haskell_io, - # 2.7-haskell_func + 1.4-scheme_lists ] # The type of runner that the job will run on runs-on: ubuntu-latest @@ -52,15 +37,3 @@ jobs: with: root_file: ${{ matrix.file }}.tex latexmk_shell_escape: true - # Upload main file to OwnCloud - - name: Upload main file to Owncloud - uses: wei/curl@v1.1.1 - with: - args: | - -X PUT https://triffon:${{ secrets.OWNCLOUD_TOKEN }}@intranet.fmi.uni-sofia.bg/remote.php/webdav/%D0%A3%D1%87%D0%B5%D0%B1%D0%BD%D0%B8%20%D0%BC%D0%B0%D1%82%D0%B5%D1%80%D0%B8%D0%B0%D0%BB%D0%B8/2024-25/%D0%A4%D0%9F%202024-25/${{ matrix.file }}.pdf --data-binary @${{ matrix.file }}.pdf - # Upload trans file to OwnCloud - - name: Upload trans file to Owncloud - uses: wei/curl@v1.1.1 - with: - args: | - -X PUT https://triffon:${{ secrets.OWNCLOUD_TOKEN }}@intranet.fmi.uni-sofia.bg/remote.php/webdav/%D0%A3%D1%87%D0%B5%D0%B1%D0%BD%D0%B8%20%D0%BC%D0%B0%D1%82%D0%B5%D1%80%D0%B8%D0%B0%D0%BB%D0%B8/2024-25/%D0%A4%D0%9F%202024-25/${{ matrix.file }}-trans.pdf --data-binary @${{ matrix.file }}-trans.pdf diff --git a/0.0-org.tex b/0.0-org.tex deleted file mode 100644 index f4f6865..0000000 --- a/0.0-org.tex +++ /dev/null @@ -1,90 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} -\usepackage{qrcode} - -\title{Организация на курса} - -\date{2 октомври 2024 г.} - -\hypersetup{colorlinks,urlcolor=blue,linkcolor=white} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\begin{frame} - \frametitle{Екип} - - \begin{itemize} - \item Специалност „Информатика“ - \begin{itemize} - \item \textbf{1 група:} Петър Колев - \item \textbf{2 група:} Ангел Ангелов - \end{itemize} - \item Специалност „Компютърни науки“, 2 поток - \begin{itemize} - \item \textbf{5 група:} Ангел Ангелов - \item \textbf{6 група:} Атанас Орманов - \item \textbf{7 група:} Андрей Дренски - \item \textbf{8 група:} Георги Атанасов - \end{itemize} - \item Избираема дисциплина: Генчо Жилков - \item \textbf{Практикум:} Павел Атанасов и Давид Петров -\end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Компоненти за оценяване} - - \begin{itemize} - \item Големи контролни: 2 $\times$ 30 т. - \item Малки контролни: 2 $\times$ 10 т. - \item Проект: 1 $\times$ 60 т. максимум - \item Блиц тестове: 5 $\times$ 2 т. \alert{(минимум 5 т.)} - \item Изпит задачи: 1 $\times$ 50 т. \alert{(минимум 15 т.)} - \item Изпит теория: 1 $\times$ 50 т. \alert{(минимум 20 т.)} - \item \textbf{Максимум:} 250 т. - \item \textbf{Максимум текущ контрол:} 150 т. - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Схема за оценяване} - - \begin{itemize} - \item 180 т. = Отличен 6.00 - \item 100 т. = освобождаване от изпит на задачи с 20 т. - \item 60 т. = Среден 3.00 - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Канали за комуникация} - \begin{columns}[T,onlytextwidth] - \begin{column}{.7\textwidth} - \begin{itemize} - \item Learn.fmi: Бакалаври, зимен семестър 2024/2025 - \begin{itemize} - \item КН - \begin{itemize} - \item \href{https://learn.fmi.uni-sofia.bg/course/view.php?id=10481}{ФП (И+КН.2+избираема) 2024/25} - \end{itemize} - \end{itemize} - \vspace{7ex} - \item \href{https://discord.gg/YBEZjk5CBN}{Discord сървър} - \begin{itemize} - \item код за покана \tt{YBEZjk5CBN} - \end{itemize} - \end{itemize} - \end{column} - \begin{column}{.3\textwidth} - \qrcode{https://learn.fmi.uni-sofia.bg/course/view.php?id=10481} - - \vspace{4ex} - \qrcode{https://discord.gg/YBEZjk5CBN} - \end{column} - \end{columns} - \end{frame} -\end{document} diff --git a/0.1-intro.tex b/0.1-intro.tex deleted file mode 100644 index defaca0..0000000 --- a/0.1-intro.tex +++ /dev/null @@ -1,383 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -\title[Какво е ФП?]{Какво е функционално програмиране?} - -\newcommand{\lang}[1]{\onslide<2->{\hspace{2ex}[\textbf{#1}]}} -\newcommand{\scheme}{\lang{Scheme}} -\newcommand{\haskell}{\lang{Haskell}} - -\newboolfalse{turing} -\newboolfalse{noncomputable} -\newboolfalse{halting} -\newboolfalse{computable} - -\date{2 октомври 2024 г.} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section*{Императивен и декларативен стил} - -\begin{frame} - \frametitle{Императивен стил} - - Описваме последователно изчислителните стъпки.\\[2ex] - \begin{columns}[t,onlytextwidth] - - \column{0.5\textwidth} - \textbf{Неструктурирано\\програмиране}\\[2ex] - \begin{enumerate} - \item Въведи \tt a, \tt b - \item Ако \tt{a $=$ b}, към 6. - \item Ако \tt{a $>$ b}, към 5. - \item \tt{b $\leftarrow$ b $-$ a}; към 2. - \item \tt{a $\leftarrow$ a $-$ b}; към 2. - \item Изведи a - \item Край - \end{enumerate} - - \column{0.5\textwidth} - \textbf{Структурирано\\програмиране}\\[2ex] - \begin{itemize} - \item Въведи \tt a, \tt b - \item Докато \tt{a $\neq$ b} - \begin{itemize} - \item Ако \tt{a $>$ b} - \begin{itemize} - \item \tt{a $\leftarrow$ a $-$ b} - \end{itemize} - \item В противен случай - \begin{itemize} - \item \tt{b $\leftarrow$ b $-$ a} - \end{itemize} - \end{itemize} - \item Изведи \tt a - \end{itemize} - - \end{columns} -\end{frame} - -\begin{frame} - \frametitle{Декларативен стил} - - Описваме свойствата на желания резултат.\\[2ex] - \textbf{Програмиране с ограничения} - \begin{itemize} - \item Дадени са \tt a и \tt b. - \item Търсим \tt d, такова че: - \begin{itemize} - \item \tt{1 $\leq$ d $\leq$ a,b} - \item „\tt d е делител на \tt a“ - \item „\tt d е делител на \tt b“ - \item \tt d е възможно най-голямо, - \item където за дадени \tt x и \tt y: - \begin{itemize} - \item „\tt x е делител на \tt y“, ако - \item намерим такова естествено число \tt k, че - \item \tt{1 $\leq$ k $\leq$ y} - \item \tt k * \tt x = \tt y - \end{itemize} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Декларативен стил (2)} - - Описваме свойствата на желания резултат.\\[2ex] - \textbf{Логическо програмиране} - \begin{itemize} - \item Описваме релацията над естествени числа $gcd(a,b,c)$ - \item $\forall a \, gcd(a,a,a)$ \hspace{2ex}\textbf{[факт]} - \item $\forall a\forall b ( a > b \land \forall c (gcd(a-b,b,c) \rightarrow gcd(a,b,c)))$ \hspace{2ex}\textbf{[правило 1]} - \item $\forall a\forall b ( a < b \land \forall c (gcd(a,b-a,c) \rightarrow gcd(a,b,c)))$ \hspace{2ex}\textbf{[правило 2]} - \item Дадени са $a, b$ - \item Намери такова $c$, за което $gcd(a,b,c)$ - \end{itemize} - \pause - \textbf{Пример:} - Нека $a = 8, b = 12$. Тогава:\\ - $\xrightarrow{\text{факт}} gcd(4,4,4) \xrightarrow{\text{правило 1}} gcd(8,4,4) \xrightarrow{\text{правило 2}} gcd(8,12,4)$ -\end{frame} - - -\begin{frame} - \frametitle{Декларативен стил (3)} - Описваме свойствата на желания резултат.\\[2ex] - \textbf{Функционално програмиране} - \begin{itemize} - \item Функцията над естествени числа $gcd(a,b)$ притежава следните свойства: - \item $gcd(a,a) = a$ \hspace{2ex}\textbf{(свойство 1)} - \item $gcd(a-b,b) = gcd(a,b)$, ако $a > b$ \hspace{2ex}\textbf{(свойство 2)} - \item $gcd(a,b-a) = gcd(a,b)$, ако $b > a$ \hspace{2ex}\textbf{(свойство 3)} - \item Дадени са $a, b$ - \item Да се пресметне $gcd(a,b)$. - \end{itemize} - \pause - \textbf{Пример:} - Нека $a = 8, b = 12$.\\ - $gcd(8,12) \stackrel{\text{свойство 3}}= gcd(8,4) \stackrel{\text{свойство 2}}= gcd(4,4) \stackrel{\text{свойство 1}}= 4$. -\end{frame} - -\begin{frame} - \frametitle{Още един пример} - - Да се намери сумата на квадратите на нечетните числа в списъка \tt l.\\[2ex] - \begin{columns}[t,onlytextwidth] - \column{0.5\textwidth} - \textbf{Императивен стил} - \begin{itemize} - \item Нека \tt{s = 0}. - \item За \tt i от 1 до \tt{length(l)}: - \begin{itemize} - \item Ако \tt{l[i]} е нечетно, то - \begin{itemize} - \item \tt{s = s + l[i]$^2$}. - \end{itemize} - \end{itemize} - \item Изведи \tt s. - \end{itemize} - - \column{0.5\textwidth} - \textbf{Функционален стил} - \begin{itemize} - \item От елементите на \tt l\ldots - \item \ldots избираме нечетните, \ldots - \item \ldots прилагаме над тях функцията $x^2$ \ldots - \item \ldots и ги групираме с операцията $+$. - \end{itemize} - \end{columns} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Още един пример (2)} - \textbf{C++:} -\begin{verbatim} -int s = 0; -for(int i = 0; i < sizeof(l); i++) - if (l[i] % 2 != 0) - s += l[i] * l[i]; -cout << s; -\end{verbatim} - \pause - \textbf{Scheme:} \tt{(apply + (map square (filter odd? l)))}\\[2ex] - \pause - \textbf{Haskell:} \tt{foldr1 (+) [ x\^{}2 | x <- l, odd x ]}\\[2ex] - \pause - \textbf{Haskell:} \tt{sum . map (\^{}2) . filter odd} -\end{frame} - -\section*{Изчислителни модели} - -\begin{frame} - \frametitle{Какво може да се сметне с компютър?} - - Нека $f:\mathbb N\to\mathbb N$ е функция над естествени числа.\\[2ex] - - \textbf{Примери:} $f(x) = x^2$, $f(x) = x$-тото число на Фибоначи.\\[4ex] - \pause - \textbf{Въпрос 1:} Какво означава да изчислим $f$ с компютър?\\[4ex] - \pause - \textbf{Въпрос 2:} Какво означава „алгоритъм“ или „програма“?\\[4ex] - \pause - \textbf{Въпрос 3:} Има ли функции, които не могат да бъдат изчислени с компютър? -\end{frame} - -\begin{frame}<\switch{turing}> - \frametitle{Машина на Turing} - - % TODO: да се нарисува с TikZ - \vspace*{-4ex} - \begin{center} - \includegraphics[width=0.75\textwidth]{images/turing.pdf} - \end{center} - \pause - \vspace*{-1ex} - \textbf{$M$ изчислява функцията $f_M$}, ако при лента с числото $n$ машината $M$ завършва и записва върху лентата числото $f_M(n)$.\\ - \pause - Ако $M$ не завърши за някое $n$, казваме, че \textbf{$f_M(n)$ не е дефинирана}. -\end{frame} - -\begin{frame}<\switch{noncomputable}> - \frametitle{Има неизчислими функции!} - - \begin{itemize}[<+->] - \item Всяка машина на Turing може да се кодира като дълго естествено число. - \item Всяка изчислима функция се изчислява от (поне една) машина. - \item Следователно, изчислимите функции са не повече от естествените числа (изброимо много). - \item Но функциите от вида $\mathbb N \to \mathbb N$ са колкото редиците от естествени числа -\ldots - \item \ldots които са неизброимо много! (защо?). - \item Следователно, има неизброимо много неизчислими функции. \qed - \item \alert{Но кои са те?} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{halting}> - \frametitle{Стоп проблем} - - \small - Нека с $\mt n$ означаваме машината на Turing с код $n$. - Разглеждаме функцията: - \begin{equation*} - halts(n) = - \begin{cases} - 1,&\text{ ако }\mt n\text{ завършва над лента с числото }n,\\ - 0,&\text{ иначе}. - \end{cases} - \end{equation*} - \pause - \alert{$halts$ не е изчислима!}\\ - \pause - \begin{proof} - Да допуснем, че $halts$ се изчислява от машина на Turing $H$. - Дефинираме нова машина $D$:\\ - \setlength{\leftmargini}{30pt} - \begin{enumerate} - \setbeamertemplate{enumerate items}[default] - \item (тук слагаме всички инструкции на $H$) - \item[$k+1$.] \tt{IFZERO} $k+3$ - \item[$k+2$.] \tt{JUMP} $k+1$ - \item[$k+3$.] \tt{STOP} - \end{enumerate} - Нека $D = \mt d$. Завършва ли $D$ над $d$? - \end{proof} -\end{frame} - -\begin{frame}<\switch{computable}> - \frametitle{Въпроси за изчислимост} - - Според вас изчислими ли са следните функции? - \begin{itemize}[<+->] - \item $f_1(n) = n$ е просто число - \item $f_2(n) = n$-тото поред просто число - \item $f_3(n) = n$-тата цифра на числото $\pi$ - \item $f_4(n) = $ има $n$ последователни седмици в числото $\pi$ - \item $f_5(n) = n$ е код на множество от матрици $3 \times 3$, които могат да се умножат в някакъв ред, така че да се получи O - \item $f_6(n) = n$ е код на вярна съждителна формула - \item $f_7(n) = n$ е код на вярна предикатна формула - \item $f_8(n) = m$, където $\mt m$ пресмята $f_8$ - \item $f_9(n) = $ машините $\mt n$ и $\mt{2n}$ изчисляват еднакви функции - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{$\lambda$-смятане} - - Нека разполагаме с изброимо много променливи $x,y,z,\ldots$\\[2ex] - Три вида $\lambda$-изрази ($E$) - \begin{itemize} - \item $x$ (променлива) - \item $E_1(E_2)$ (апликация, прилагане на функция) - \item $\lambda x \, E$ (абстракция, конструиране на функция) - \end{itemize} - \vspace{1em} - \textbf{Примери:} $\lambda x\, x, \quad (\lambda x\, x)(z), \quad \lambda f\lambda x\, f(f(f(x)))$\\[2ex] - \pause - Едно изчислително правило: - \begin{equation*} - (\lambda x\,E_1)(E_2) \mapsto E_1[x := E_2]. - \end{equation*} -\end{frame} - -\begin{frame} - \frametitle{Машини на Turing = $\lambda$-смятане} - - \begin{theorem}[Alan Turing, 1937] - Функциите, които могат да се изчислят с машина на Turing са точно тези, които могат да се дефинират с $\lambda$-израз. - \end{theorem} - \pause - \begin{center} - \begin{tabular}{|rcl|} - \hline - Машини на Turing & = & императивен стил за програмиране\\ - $\lambda$-смятане & = & функционален стил за програмиране\\ - \hline - \end{tabular} - \end{center} - \pause - \textbf{Факт: }Практически всички съвременни езици за програмиране са със същата изчислителна сила като на машините на Turing.\\[2ex] - \pause - \textbf{Тезис на Church-Turing:} Всяка функция, чието изчисление може да се автоматизира, може да бъде пресметната с машина на Turing. -\end{frame} - -\section*{Особености на функционалното програмиране} - -\begin{frame} - \frametitle{Във функционалното програмиране...} - - ... има: - \begin{itemize}[<+->] - \item функции с параметри, (абстракция) - \item които могат да се прилагат над аргументи, (апликация) - \item които могат да са други функции (функции от висок ред) - \item и могат да се дефинират чрез себе си, (рекурсия) - \end{itemize} - \onslide<+-> - ... но няма: - \begin{itemize}[<+->] - \item памет - \item присвояване - \item цикли - \item прескачане (goto, break, return) - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Защо функционално програмиране?} - - \begin{itemize}[<+->] - \item Кратки и ясни програми (изразителност) - \item Лесна проверка за коректност - \item При еднакви входни данни връщат един и същ резултат (референциална прозрачност), \onslide<+-> което позволява... - \item Избягване на повторно пресмятане на резултати чрез запомняне (мемоизация) - \item Премахване на части от програмата, които не участват в крайния резултат (мъртъв код) - \item Пренареждане на програмата за по-ефективно изпълнение (стратегия за оценяване) - \item Паралелно изпълнение на независими части от програмата (паралелизация) - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Видове функционални езици} - - \begin{itemize} - \item според типовата система - \begin{itemize} - \item динамично типизирани (стойностите имат тип) \scheme - \item статично типизирани (променливите имат тип) \haskell - \end{itemize} - \item според страничните ефекти - \begin{itemize} - \item нечисти (със странични ефекти) \scheme - \item чисти (без странични ефекти) \haskell - \end{itemize} - \item според стратегията за оценяване - \begin{itemize} - \item стриктно (първо сметни, после предай) \scheme - \item лениво (първо предай, после смятай) \haskell - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{История на функционалното програмиране} - - \setlength{\leftmargini}{11ex} - \begin{itemize}[<+->] - \item[(1936)] Church и Rosser дефинират $\lambda$-смятането - \item[(1960)] McCarthy създава първия функционален език LISP - \item[(1975)] Steele и Sussman създават \textbf{Scheme}, диалект на LISP - \item[(1977)] Backus (авторът на FORTRAN) популяризира функционалния стил - \item[(1985)] Turner създава Miranda, първият комерсиален чист функционален език - \item[(1990)] Публикувана е първата версия на \textbf{Haskell} - \item[(1998)] Отваряне на кода на реализацията на Erlang - \item[(1990--2000)] Функционални елементи в императивни езици: Python (1991), JavaScript (1995), Ruby (1995), ActionScript (1998) - \item[(2000--)] Функционалният стил на програмиране превзема света: Scala (2003), F\# (2005), C\# (2007), Clojure (2007), C++11 (2011), Elixir (2011), Java 8 (2014), AWS Lambda (2014), Azure Functions (2016) - \end{itemize} -\end{frame} - -\end{document} diff --git a/1.1-scheme_basics.tex b/1.1-scheme_basics.tex deleted file mode 100644 index 1c75707..0000000 --- a/1.1-scheme_basics.tex +++ /dev/null @@ -1,403 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -\title{Основни понятия в Scheme} - -\date{2--9 октомври 2024 г.} - -\lstset{language=Scheme} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section{Въведение в Scheme} - -\begin{frame} - \frametitle{Що за език е Scheme?} - - \begin{itemize} - \item Създаден през 1975 г. от Guy L.~Steele и Gerald Jay Sussman - \item Диалект на LISP, създаден с учебна цел - \item „Structure and Interpretation of Computer Programs“, Abelson \& Sussman, MIT Press, 1985. - \item Минималистичен синтаксис - \item Най-разпространен стандарт: R$^5$RS (1998) - \item Най-нов стандарт: R$^7$RS (2013) - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Програмиране на Scheme} - - \begin{itemize} - \item Среда за програмиране: DrRacket - \item Има компилатори и интерпретатори - \begin{itemize} - \item Ние ще ползваме интерпретатор - \end{itemize} - \item REPL = Read-Eval-Print-Loop - \item Програма = списък от дефиниции - \item Изпълнение = оценка на израз - \end{itemize} -\end{frame} - -\section{Синтаксис и семантика} - -\begin{frame}[fragile] - \frametitle{Синтаксис в Scheme} - - \begin{itemize}[<+->] - \item Литерали - \begin{itemize} - \item Булеви константи (\lst{#f}, \lst{#t}) - \item Числови константи (\lst{15}, \lst{2/3}, \lst{-1.532}) - \item Знакови константи (\lst{#\a}, \lst{#\newline}) - \item Низови константи (\lst{"Scheme"}, \lst{"hi "}) - \end{itemize} - \item Символи (\lst{f}, \lst{square}, \lst{+}, \lst{find-min}) - \item Комбинации\\[2ex] - \alert({}<израз$_1$> <израз$_2$> \ldots <израз$_n$>\alert) - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Оценки на литерали и символи} - - На всеки израз се дава оценка. - \begin{itemize}[<+->] - \item Оценката на булевите константи, знаците, числата и низовете са самите те - \begin{itemize} - \item \evalsto 5 5 - \item \evalsto{\#t}{\#t} - \item \evalsto{\#\\a}{\#\\a} - \item \evalsto{\"scheme\"}{\"scheme\"} - \end{itemize} - \item Оценката на символ е стойността, свързана с него - \begin{itemize} - \item \evalsto +{\#} - \item \evalstoerr a - \item \lst{(define a 5)} - \item \evalsto a5 - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Основно правило за оценяване} - - Оценка на комбинация \textbf{(основно правило за оценяване)}\\[2ex] - \begin{equation*} - \newcommand{\evals}{\text{\small се оценява до}} - \underbrace{% - \begin{array}{cccccc} - (&\text{<израз}_0\text{>}&\text{<израз}_1\text{>}&\ldots&\text{<израз}_n\text{>}&)\\ - &\vert&\vert&&\vert&\\ - &\evals&\evals&&\evals&\\ - &\bda&\bda&&\bda&\\ - (&f&v_1&\ldots&v_n&) - \end{array} - }_{% - \begin{array}{c} - \vert\\ - \evals\\ - \bda\\ - f(v_1,\ldots,v_n) - \end{array}} - \end{equation*}\\[2ex] - \pause - Ако $f$ не е функция --- \alert{грешка!} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Пример за оценяване на комбинации} - \begin{fixedarea}[.7] - \begin{equation*} - \underbrace{% - \begin{tabular}{cccc} - \tt{(+}&$\underbrace{\tt{(* 2 3)}}_{}$&$\underbrace{\tt{(- 14 6 5)}}_{}$&\tt)\\ - &\bda&\bda&\\ - \tt{(+}&\tt6&\tt3&\tt) - \end{tabular} - }_{% - \begin{tabular}{c} - \bda\\ - \tt 9 - \end{tabular}} - \end{equation*}\\[4ex] - \pause - \onslide<+-> - \begin{center} - \evalstoerrp {(1 2 3)} - \end{center} - \end{fixedarea} -\end{frame} - -\section{Дефиниции в Scheme} - -\begin{frame} - \frametitle{Дефиниция на символи} - - \begin{itemize}[<+->] - \item \tta{(define} <символ> <израз>\tta) - \item Оценява <израз> и свързва <символ> с оценката му. - \item Примери: - \begin{itemize} - \item \lst{(define s "Scheme is cool")} - \item \evalsto s{\"Scheme is cool\"} - \item \lst{(define x 2.5)} - \item \evalsto x{2.5} - \item \evalsto{(+ x 3.2)}{5.7} - \item \lst{(define y (+ x 3.2))} - \item \evalsto{(> y 3)}{\#t} - \item \evalstoerr{(define z (+ y z))} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Специални форми} - - \begin{itemize}[<+->] - \item По основното правило ли се оценява \lst{(define x 2.5)}? - \item \alert{Не!} - \item В синтаксиса на Scheme има конструкции, които са изключение от стандартното правило - \item Такива конструкции се наричат \textbf{специални форми} - \item \tt{define} е пример за специална форма - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Цитиране} - - \begin{itemize}[<+->] - \item \tta{(quote} <израз>\tta) - \item Алтернативен запис: \tta'<израз> - \item Оценката на \tt{(quote} <израз>\tt) или \tt'{}<израз> е самият <израз> - \item \textbf{Примери:} - \begin{itemize} - \item \evalsto{'2}2 - \item \evalsto{'+}+ - \item \evalsto{'(+ 2 3)}{(+ 2 3)} - \item \evalsto{(quote quote)}{quote} - \item \evalstoerr{('+ 2 3)} - \item \evalstoerr{(/ 2 0)} - \item \evalsto{'(/ 2 0)}{(/ 2 0)} - \item \evalsto{'(+ 1 '(* 3 4))}{(+ 1 (quote (* 3 4)))} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Дефиниция на функции} - - \begin{itemize}[<+->] - \item \tta{(define (}{}<функция> \{{}<параметър>\}\tta) <тяло>\tta) - \item {}<функция> и <параметър> са символи - \item {}<тяло> е <израз> - \item Символът <функция> се свързва с поредица от инструкции, които пресмятат <тяло> при подадени стойности на <параметър> - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Примери за дефиниция на функции} - - \begin{itemize}[<+->] - \item \lst{(define (square x) (* x x))} - \item \evalsto{(square 5)}{25} - \item \lst{(define (1+ k) (+ k 1))} - \item \evalsto{(square (1+ (square 3)))}{100} - \item \lst{(define (f x y) (+ (square (1+ x)) (square y) 5))} - \item \evalstop{(f 2 4)}{30} - \item \lst{(define (g x) (- (g (+ x 1)) 1))} - \item \evalstop{(g 0)}{...} - \item \lst{(define (h) (+ 2 3))} - \item \evalsto{h}{\#} - \item \evalsto{(h)}5 - \end{itemize} - -\end{frame} - -\begin{frame} - \frametitle{Оценяване на комбинации с дефинирани функции} - \begin{center} - \evalchain{ - "(f 2 4)" -> - "(+ (square (1+ 2)) (square 4) 5)" -> - "(+ (square (+ 2 1)) (square 4) 5)" -> - "(+ (square 3) (square 4) 5)" -> - "(+ (* 3 3) (* 4 4) 5)" -> - "(+ 9 16 5)" -> - "30" - } - \end{center} -\end{frame} - -\section{Стандартни функции} - -\begin{frame} - \frametitle{Стандартни числови функции} - - Аритметични операции\\ - \tt{+}, \tt{-}, \tt{*}, \tt{/}\\[1em] - Други числови функции\\ - \tt{remainder}, \tt{quotient}, \tt{max}, \tt{min}, \tt{gcd}, \tt{lcm}\\[1em] - Функции за закръгляне\\ - \tt{floor}, \tt{ceiling}, \tt{round}\\[1em] - Функции над дробни числа\\ - \tt{exp}, \tt{log}, \tt{sin}, \tt{cos}, \tt{tan}, \tt{asin}, \tt{acos}, \tt{atan}, \tt{expt}, \tt{sqrt} -\end{frame} - -\begin{frame} - \frametitle{Стандартни предикати} - - Предикати за сравнение на числа\\ - \tt{<}, \tt{>}, \tt{=}, \tt{<=}, \tt{>=}\\[1em] - Числови предикати\\ - \tt{zero?}, \tt{negative?}, \tt{positive?}, \tt{odd?}, \tt{even?}\\[1em] - Предикати за проверка на тип\\ - \tt{boolean?}, \tt{number?}, \tt{char?}, \tt{string?}, \tt{symbol?}, \tt{procedure?} -\end{frame} - -\section{Условни изрази} - -\begin{frame} - \frametitle{Условна форма \tt{if}} - - \begin{itemize}[<+->] - \item \tta{(if} <условие> <израз$_1$> <израз$_2$>\tta) - \item Оценява се <условие> - \begin{itemize} - \item Ако оценката е \tt{\#t} --- връща се оценката на <израз$_1$> - \item Ако оценката е \tt{\#f} --- връща се оценката на <израз$_2$> - \end{itemize} - \item \alert{\tt{if} е специална форма!} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Примери с условната форма \tt{if}} - - \begin{itemize}[<+->] - \item \evalsto{(if (< 3 5) (+ 7 3) (- 4 2))}{10} - \item \lst{(define (abs x) (if (< x 0) (- x) x))} - \item \evalsto{(abs -5)}5, \evalsto{(abs (+ 1 2))}3 - \item \lst{(define (f x) (if (< x 5) (+ x 2) "Error"))} - \item \evalsto{(f 3)}5, \evalsto{(f 5)}{\"Error\"} - \item \lst{(define (g x y) (if (< x y) (+ x y) (* x y)))} - \item \lst{(define (g x y) ((if (< x y) + *) x y))} - \item \evalsto{(g 2 3)}5, \evalsto{(g 3 2)}6 - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Форма за многозначен избор \tt{cond}} - - \begin{itemize}[<+->] - \item \tta{(cond} \{\tta({}<условие> <израз>\tta)\} [\tta{(else} <израз>\tta)]\tta) - \item \tta{(cond (}{}<условие$_1$> <израз$_1$>\tta)\\ - \tta{\hskip 7ex(}{}<условие$_2$> <израз$_2$>\tta)\\ - \hskip 7ex\ldots\\ - \tta{\hskip 7ex(}{}<условие$_n$> <израз$_n$>\tta)\\ - \tta{\hskip 7ex(else} <израз$_{n+1}$>\tta{))} - \item Оценява се <условие$_1$>, при \tt{\#t} се връща <израз$_1$>, а при \tt{\#f}: - \item Оценява се <условие$_2$>, при \tt{\#t} се връща <израз$_2$>, а при \tt{\#f}: - \item \ldots - \item Оценява се <условие$_n$>, при \tt{\#t} се връща <израз$_n$>, а при \tt{\#f}: - \item Връща се <израз$_{n+1}$> - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Пример с формата \tt{cond}} - -\begin{lstlisting} -(define (grade x) - (cond ((>= x 5.5) "Отличен") - ((>= x 4.5) "Много добър") - ((>= x 3.5) "Добър") - ((>= x 3) "Среден") - (else "Слаб"))) -\end{lstlisting} -\end{frame} - -\begin{frame} - \frametitle{Форма за разглеждане на случаи \tt{case}} - - \begin{itemize}[<+->] - \item \tta{(case} <тест> \{\tta({}\tta(\{<случай>\}\tta) <израз>\tta)\} [\tta{(else} <израз>\tta)]\tta) - \item \tta{(case} <тест> \tta{((}{}<случай$_{1,1}$> \ldots <случай$_{1,k_1}$>\tta) <израз$_1$>\tta)\\ - \tta{\hskip 16ex((}{}<случай$_{2,1}$> \ldots <случай$_{2,k_2}$>\tta) <израз$_2$>\tta)\\ - \hskip 16ex\ldots\\ - \tta{\hskip 16ex((}{}<случай$_{n,1}$> \ldots <случай$_{n,k_n}$>\tta) <израз$_n$>\tta)\\ - \tta{\hskip 16ex(else} <израз$_{n+1}$>\tta{))} - \item Оценява се <тест> - \item при някое от <случай$_{1,1}$>\ldots<случай$_{1,k_1}$> $\rightarrow$ <израз$_1$>, иначе: - \item при някое от <случай$_{2,1}$>\ldots<случай$_{2,k_2}$> $\rightarrow$ <израз$_2$>, иначе: - \item \ldots - \item при някое от <случай$_{n,1}$>\ldots<случай$_{n,k_n}$> $\rightarrow$ <израз$_n$>, иначе: - \item Връща се <израз$_{n+1}$> - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Пример с формата \tt{case}} - -\begin{lstlisting} -(define (days-in-month m y) - (case m - ((1 3 5 7 8 10 12) 31) - ((4 6 9 11) 30) - (else (if (leap? y) 29 28)))) -\end{lstlisting} -\end{frame} - -\begin{frame} - \frametitle{Логически операции} - - \begin{itemize}[<+->] - \item \tta{(not} <булев-израз>\tta) - \begin{itemize} - \item Връща отрицанието на <булев-израз> - \end{itemize} - \item \tta{(and} \{<булев-израз>\}\tta) - \item \tta{(and} <булев-израз$_1$> <булев-израз$_2$> \ldots <булев-израз$_n$>\tta) - \begin{itemize} - \item Оценява последователно всички <булев-израз$_i$> - \item Ако всички се оценяват до \tt{\#t}, връща \tt{\#t} - \item Ако <булев-израз$_i$> се оценява до \tt{\#f}, връща - \tt{\#f} без да оценява следващите <булев-израз$_{i+1}$> \ldots <булев-израз$_n$> - \end{itemize} - \item \tta{(or} \{<булев-израз>\}\tta) - \item \tta{(or} <булев-израз$_1$> <булев-израз$_2$> \ldots <булев-израз$_n$>\tta) - \begin{itemize} - \item Оценява последователно всички <булев-израз$_i$> - \item Ако всички се оценяват до \tt{\#f}, връща \tt{\#f} - \item Ако <булев-израз$_i$> се оценява до \tt{\#t}, връща - \tt{\#t} без да оценява следващите <булев-израз$_{i+1}$> \ldots <булев-израз$_n$> - \end{itemize} - \item \alert{\tt{and} и \tt{or} са специални форми!} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Примери с логически операции} - - \begin{tabular}{lcl} - \lstinline!(not x)! &\eqv& \lstinline!(if x #f #t)!\\ - \lstinline!(and x y)! &\eqv& \lstinline!(if x y #f)!\\ - \lstinline!(or x y)! &\eqv& \lstinline!(if x #t y)! - \end{tabular} - \pause -\begin{lstlisting} -(define (divisible? a b) - (= (remainder a b) 0)) - -(define (leap? y) - (and (divisible? y 4) - (or (not (divisible? y 100)) - (divisible? y 400)))) -\end{lstlisting} -\end{frame} -\end{document} diff --git a/1.2-scheme_envs.tex b/1.2-scheme_envs.tex deleted file mode 100644 index 64bc727..0000000 --- a/1.2-scheme_envs.tex +++ /dev/null @@ -1,1041 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -\title[Среди и процеси]{Модел на средите и изчислителни процеси} - -\newbooltrue{receqs} -\newbooltrue{fixpoint} -\newboolfalse{semantics} - -\date{9--16 октомври 2024 г.} - -\lstset{language=Scheme} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section{Модел на средите} - -\begin{frame} - \frametitle{Среди в Scheme} - - \begin{itemize}[<+->] - \item Връзката между символите и техните оценки се записват в речник, който се нарича \textbf{среда}. - \item Всеки символ има най-много една оценка в дадена среда. - \item В даден момент могат да съществуват много среди. - \item Символите винаги се оценяват в една конкретна среда. - \item \alert{Символите могат да има различни оценки в различни среди.} - \item При стартиране Scheme по подразбиране работи в \textbf{глобалната среда}. - \item В глобалната среда са дефинирани символи за стандартни операции и функции. - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Пример за среда} - - \begin{columns}[T,onlytextwidth] - \begin{column}{.5\textwidth} - \begin{itemize}[<+->] - \item \lst{(define a 8)} - \item \evalstoerr r - \item \lst{(define r 5)} - \item \evalsto{(+ r 3)}8 - \item \lst{(define (f x) (* x r))} - \item \evalsto{(f 3)}{15} - \item \evalsto{(f r)}{25} - \end{itemize} - \end{column} - - \begin{column}{.5\textwidth} - \begin{tikzpicture} - \envir{E}{ - \kv a8 - \only<3->{\kv r5} - \only<5->{\kf fx{(* x r)}E} - } - \end{tikzpicture} - \end{column} - \end{columns} -\end{frame} - -\begin{frame} - \frametitle{Функции и среди} - - \begin{itemize}[<+->] - \item Всяка функция \tt f пази указател към средата \env E, в която е дефинирана. - \item При извикване на \tt f: - \begin{itemize} - \item създава се нова среда \env{E_1}, която разширява \env E - \item в \env{E_1} всеки символ означаващ формален параметър се свързва с оценката на фактическия параметър - \item тялото на $f$ се оценява в \env{E_1} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Дърво от среди} - \begin{itemize}[<+->] - \item Всяка среда пази указател към своя „родителска среда“, която разширява - \item така се получава дърво от среди - \item при оценка на символ в дадена среда \env E - \begin{itemize} - \item първо се търси оценката му в \env E - \item ако символът не е дефиниран в \env E, се преминава към родителската среда - \item при достигане на най-горната среда, ако символът не е дефиниран и в нея се извежда съобщение за грешка - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Извикване на дефинирана функция} - - \begin{fixedarea} - \begin{columns}[T,onlytextwidth] - \begin{column}{.5\textwidth} - \begin{itemize}[<+->] - \item \lst{(define r 5)} - \item \lst{(define a 3)} - \item \lst{(define (f x) (* x r))}\\[2ex] - \evalchain{ - "(f a)"[env=E] -> - "(f 3)"[env=E] -> - "(* x r)"[env=E_1] -> - "15"; - } - \end{itemize} - \end{column} - - \begin{column}{.5\textwidth} - \begin{tikzpicture} - \envir{E}{ - \kv r5 - \only<2->{\kv a3} - \only<3->{\kf fx{(* x r)}E} - } - \childenvir[6-]{below=4em}E{E_1}{\kv x3} - \end{tikzpicture} - \end{column} - \end{columns} - \end{fixedarea} -\end{frame} - -\section{Рекурсия} - -\subsection{Рекурсивни функции} - -\begin{frame} - \frametitle{Какво е рекурсия?} - - \pause - \begin{center} - \imageWithAttr{0.5\textwidth}{images/matroska.jpg}{Matryoshka dolls}{User:Fanghong (оригинал) и User:Gnomz007 (производна)}{https://commons.wikimedia.org/wiki/File:Russian-Matroshka_no_bg.jpg}{\CCBYSA{3.0}} - \end{center} -\end{frame} - -\begin{frame} - \frametitle{Какво е рекурсия?} - - \begin{center} - % TODO: да се нарисува с TikZ и foreach - \imageWithAttr{.9\textwidth}{images/sierpinski.png}{Sierpinski triangle, the evolution in five iterations}{Solkoll}{https://commons.wikimedia.org/wiki/File:Sierpinsky_triangle_(evolution).png}{\PDWC} - \end{center} -\end{frame} - -\begin{frame} - \frametitle{Какво е рекурсия?} - - \pause - Повторение чрез позоваване на себе си\\[2ex] - \pause - Рекурсивна функция: дефинира се чрез себе си\\ - \begin{equation*} - n! = \left\{ - \begin{array}{l@{}l@{\qquad}l} - 1,&\text{ при }n = 0,&\textbf{(база)}\\ - n\cdot (n-1)!,&\text{ при }n > 0.&\textbf{(стъпка)} - \end{array}\right. - \end{equation*}\\[2ex] - \pause - \begin{itemize} - \item Дава се отговор на най-простата задача (база, дъно) - \item Показва се как сложна задача се свежда към една или няколко по-прости задачи от същия вид (стъпка) - \end{itemize} -\end{frame} - -\begin{frame}<\switch{receqs}> - \frametitle{Рекурсивни уравнения} - - Какво означава „да дефинираме функция чрез себе си“?\\[2ex] - \pause - Да разгледаме \emph{рекурсивното уравнение}, в което $F$ е неизвестно: - \begin{equation*} - F(n) = - \underbrace{\begin{cases} - 1,&\text{ при }n = 0,\\ - n \cdot F(n-1),&\text{ при }n > 0. - \end{cases}}_{\Gamma(F)(n)} - \end{equation*} - \pause - \alert{$n!$ е „най-малкото“ решение на уравнението $F = \Gamma(F)$.} -\end{frame} - -\begin{frame}<\switch{fixpoint}>[fragile] - \frametitle{Най-малка неподвижна точка} - - \begin{theorem}[Knaster-Tarski] - Ако $\Gamma$ е изчислим оператор, то уравнението $F = \Gamma(F)$ има единствено най-малко решение $f$ \pause (\textbf{най-малка неподвижна точка на $\Gamma$}). \pause Нещо повече, решението точно съответства на рекурсивна програма пресмятаща $f$ чрез $\Gamma$. - \end{theorem} - \pause -\begin{lstlisting} -(define (fact n) - (if (= n 0) 1 - (* n (fact (- n 1))))) -\end{lstlisting} - \pause - Кое е \textbf{най-малкото решение} на уравнението $F(x) = F(x+1) - 1$? - \pause -\lstinline{(define (g x) (- 1 (g (+ x 1)))}\\ -\evalsto{(g 0)}?\\ - \pause - $g$ е „празната функция“, т.е. $\mathrm{dom}(g) = \emptyset$. -\end{frame} - -\begin{frame}<\switch{semantics}> - \frametitle{Операционна и денотационна семантика} - - Два подхода за описание на смисъла на функциите в Scheme.\\ - \pause - Нека \tt{(define (f x) $\Gamma$[f])} е рекурсивно дефинирана функция.\\ - \pause - \alert{Коя е математическата функция $f$, която се пресмята от \tt f?}\\[2ex] - \pause - \textbf{Денотационна семантика}\\ - $f$ е най-малката неподвижна точка на уравнението $F = \Gamma(F)$.\\[2ex] - \pause - \textbf{Операционна семантика}\\ - Разглеждаме редицата от последователни оценки на комбинации\\ - \tt{(f a)} $\rightarrow$ \tt{$\Gamma$[f][x $\mapsto$ a]} $\rightarrow\ldots$\\ - Ако стигнем до елемент \tt b, който не е комбинация, то $f(a) := b$.\\[2ex] - \pause - \alert{Функциите в Scheme имат дуален, но еквивалентен смисъл:} - \begin{itemize} - \item решения на рекурсивни уравнения - \item изчислителни процеси, генериращи се при оценка - \end{itemize} -\end{frame} - -\subsection{Рекурсивни процеси} - -\begin{frame} - \frametitle{Оценка на рекурсивна функция} - - \begin{center} - \sizeboth\scriptsize - % TODO: да се реализира с foreach - \evalchain[(-1)]{ - "\lst{(fact 4)}" -> - "\alt<+->{\lst{(* 4 (fact 3))}} - {\lst{(if (= 4 0) 1 (* 4 (fact (- 4 1))))}}" -> - "\alt<+->{\lst{(* 4 (* 3 (fact 2)))}} - {\lst{(* 4 (if (= 3 0) 1 (* 3 (fact (- 3 1)))))}}" -> - "\alt<+->{\lst{(* 4 (* 3 (* 2 (fact 1))))}} - {\lst{(* 4 (* 3 (if (= 2 0) 1 (* 2 (fact (- 2 1))))))}}" -> - "\alt<+->{\lst{(* 4 (* 3 (* 2 (* 1 (fact 0)))))}} - {\lst{(* 4 (* 3 (* 2 (if (= 1 0) 1 (* 1 (fact (- 1 1)))))))}}" -> - "\alt<+->{\lst{(* 4 (* 3 (* 2 (* 1 1))))}} - {\lst{(* 4 (* 3 (* 2 (* 1 (if (= 0 0) 1 (* 0 (fact (- 0 1))))))))}}" ->[v] - "\lst{(* 4 (* 3 (* 2 1)))}" ->[v] - "\lst{(* 4 (* 3 2))}" ->[v] - "\lst{(* 4 6)}" ->[v] - 24; - } - \end{center} -\end{frame} - -\begin{frame} - \frametitle{Оценка на рекурсивна функция в среда} - - \begin{columns}[T,onlytextwidth] - \sizeboth\tiny - \begin{column}{.68\textwidth} - \begin{center} - % TODO: да се реализира с foreach - \evalchain[(-1)]{ - "\lst{(fact 4)}"[env=E] -> - "\alt<+->{\lst{(* 4 (fact 3))}} - {\lst{(if (= n 0) 1 (* n (fact (- n 1))))}}"[env=E_1] -> - "\alt<+->{\lst{(* 4 (* 3 (fact 2)))}} - {\lst{(* 4 (if (= n 0) 1 (* n (fact (- n 1)))))}}"[env=E_2] -> - "\alt<+->{\lst{(* 4 (* 3 (* 2 (fact 1))))}} - {\lst{(* 4 (* 3 (if (= n 0) 1 (* n (fact (- n 1))))))}}"[env=E_3] -> - "\alt<+->{\lst{(* 4 (* 3 (* 2 (* 1 (fact 0)))))}} - {\lst{(* 4 (* 3 (* 2 (if (= n 0) 1 (* n (fact (- n 1)))))))}}"[env=E_4] -> - "\alt<+->{\lst{(* 4 (* 3 (* 2 (* 1 1))))}} - {\lst{(* 4 (* 3 (* 2 (* 1 (if (= n 0) 1 (* n (fact (- n 1))))))))}}"[env=\alt<10>{E_5}{E_4}] ->[v] - "\lst{(* 4 (* 3 (* 2 1)))}"[envv=E_3] ->[v] - "\lst{(* 4 (* 3 2))}"[envv=E_2] ->[v] - "\lst{(* 4 6)}"[envv=E_1] ->[v] - 24[envv=E]; - } - \end{center} - \end{column} - \begin{column}{.32\textwidth} - \begin{tikzpicture} - \envir{E}{\kf{fact}n\ldots E} - \childenvir[2- ]{below left =2em and -2em}E{E_1}{\kv n4} - \childenvir[4- ]{below =2em }E{E_2}{\kv n3} - \childenvir[6- ]{below right=2em and -2em}E{E_3}{\kv n2} - \childenvir[8- ]{below left =7em and -3em}E{E_4}{\kv n1} - \childenvir[10-]{below right=7em and -3em}E{E_5}{\kv n0} - \end{tikzpicture} - \end{column} - \end{columns} - \vspace{2ex} - \onslide<+-> - Линеен рекурсивен процес -\end{frame} - -\subsection{Итеративни процеси} - -\begin{frame}[fragile] - \frametitle{Факториел с цикъл} - - \small - \begin{columns}[T,onlytextwidth] - \begin{column}{.5\textwidth} - \textbf{Факториел на C++}\\ -%TODO: може ли да се използва lstlisting тук? -\begin{semiverbatim} -\altbox<3| trans:0>{int fact(int n)} \{ - \altbox<4| trans:0>{int r = 1;} - \altbox<0| trans:0>{for(\altbox<5| trans:0>{int i = 1};\altbox<6| trans:0>{i <= n};\altbox<7| trans:0>{i++})} - \altbox<8| trans:0>{r *= i;} - \altbox<9| trans:0>{return r;} -\} -\end{semiverbatim} - \end{column} - \pause - \begin{column}{.5\textwidth} - \textbf{Превод на Scheme}\\ -%TODO: може ли да се използва lstlisting тук? -\begin{semiverbatim} -(define (for n \altbox<4,8| trans:0>{r}\altbox<5,7| trans:0>{i}) - (if \altbox<6| trans:0>{(<= i n)} - (for n \altbox<8| trans:0>{(* r i)}\altbox<7| trans:0>{(+ i 1)}) - \altbox<9| trans:0>{r})) - -\altbox<3| trans:0>{(define (fact n)} - (for n \altbox<4| trans:0>{1}\altbox<5| trans:0>{1})) -\end{semiverbatim} - \end{column} - \end{columns} -\end{frame} - -\begin{frame} - \frametitle{Оценка на итеративен факториел} - - \begin{fixedarea} - \begin{center} - \sizeboth\small - % TODO: да се реализира с foreach - \evalchain[(-1)]{ - "\lst{(fact 4)}" ->[v] - "\lst{(for 4 1 1)}" -> - "\alt<+->{\lst{(for 4 1 2)}}{\lst{(if (<= 1 4) (for 4 (* 1 1) (+ 1 1)) 1)}}" -> - "\alt<+->{\lst{(for 4 2 3)}}{\lst{(if (<= 2 4) (for 4 (* 1 2) (+ 2 1)) 2)}}" -> - "\alt<+->{\lst{(for 4 6 4)}}{\lst{(if (<= 3 4) (for 4 (* 2 3) (+ 3 1)) 6)}}" -> - "\alt<+->{\lst{(for 4 24 5)}}{\lst{(if (<= 4 4) (for 4 (* 6 4) (+ 4 1)) 24)}}" -> - "\alt<+->{\lst{24}}{\lst{(if (<= 5 4) (for 4 (* 24 5) (+ 5 1)) 24)}}"; - } - \end{center} - \vspace{2ex} - \onslide<+-> - Линеен итеративен процес - \end{fixedarea} -\end{frame} - -\begin{frame}<1-13>[label=iterenv] - \frametitle{Оценка на итеративен факториел със среди} - - \begin{columns}[T,onlytextwidth] - \begin{column}{.62\textwidth} - \sizeboth\scriptsize - \begin{center} - % TODO: да се реализира с foreach - \evalchain[(-1)]{ - "\lst{(fact 4)}"[env=E] -> - "\alt<+->{\tt{(for \alert<14>4 1 1)}}{\lst{(for n 1 1)}}"[env=E_0] -> - "\alt<+->{\tt{(for \alert<14>4 1 2)}}{\lst{(if (<= i n) (for n (* r i) (+ i 1)) r)}}"[env=E_1] -> - "\alt<+->{\tt{(for \alert<14>4 2 3)}}{\lst{(if (<= i n) (for n (* r i) (+ i 1)) r)}}"[env=E_2] -> - "\alt<+->{\tt{(for \alert<14>4 6 4)}}{\lst{(if (<= i n) (for n (* r i) (+ i 1)) r)}}"[env=E_3] -> - "\alt<+->{\tt{(for \alert<14>4 24 5)}}{\lst{(if (<= i n) (for n (* r i) (+ i 1)) r)}}"[env=E_4] -> - "\alt<+->{\lst{24}}{\lst{(if (<= i n) (for n (* r i) (+ i 1)) r)}}"[env=E_5]; - } - \end{center} - \end{column} - \begin{column}{.38\textwidth} - \tiny - \begin{tikzpicture} - \envir{E}{ - \kf{fact}n{(for n 1 1)}E - \kf{for}{\alert<14>n r i}\ldots E - } - \childenvir[2- ]{above=1em}E{E_0}{\kv n4} - \childenvir[4- ]{below left =1em and -3em }E{E_1}{\kv n4\kv r1 \kv i1} - \childenvir[6- ]{below =1em }E{E_2}{\kv n4\kv r1 \kv i2} - \childenvir[8- ]{below right=1em and -3em }E{E_3}{\kv n4\kv r2 \kv i3} - \childenvir[10-]{below left =7em and -4.5em}E{E_4}{\kv n4\kv r6 \kv i4} - \childenvir[12-]{below right=7em and -4.5em}E{E_5}{\kv n4\kv r{24}\kv i5} - \end{tikzpicture} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}<1-2>[fragile,label=reciter] - \frametitle{Рекурсивен и итеративен процес} - \vspace{-2ex} - \begin{columns}[T,onlytextwidth] - \begin{column}{.5\textwidth} - \begin{center} - \tiny - % TODO: да се реализира с foreach - \evalchainx{ - "(fact 4)" -> - "(* 4 (fact 3))" -> - "(* 4 (* 3 (fact 2)))" -> - "(* 4 (* 3 (* 2 (fact 1))))" -> - "(* 4 (* 3 (* 2 (* 1 (fact 0)))))" -> - "(* 4 (* 3 (* 2 (* 1 1))))" -> - "(* 4 (* 3 (* 2 1)))" -> - "(* 4 (* 3 2))" -> - "(* 4 6)" -> - "24"; - } - \end{center} - \scriptsize -\begin{semiverbatim} - (define (fact n) - (if (= n 0) 1 - \altbox<2>{(* n }(fact (- n 1))))) -\end{semiverbatim} - \end{column} - \begin{column}{.5\textwidth} - \begin{center} - \tiny - % TODO: да се реализира с foreach - \evalchainx{ - "(fact 4)" -> - "(for \alert<3> 4 1 1)" -> - "(for \alert<3> 4 1 2)" -> - "(for \alert<3> 4 2 3)" -> - "(for \alert<3> 4 6 4)" -> - "(for \alert<3> 4 24 5)" -> - "24"; - } - \end{center} - \scriptsize -\begin{semiverbatim} -(define (for \alert<3>n r i) - (if (<= i n) - (for \alert<3>n (* r i) (+ i 1)) - r)) - -(define (fact n) - (for \alert<3>n 1 1)) -\end{semiverbatim} - \end{column} - \end{columns} -\end{frame} - -\begin{frame} - \frametitle{Опашкова рекурсия} - - \begin{itemize}[<+->] - \item Функциите, в които има отложени операции генерират същински \textbf{рекурсивни процеси} - \item Рекурсивно извикване, при което няма отложена операция се нарича \textbf{опашкова рекурсия} - \item Функциите, в които всички рекурсивни извиквания са опашкови генерират \textbf{итеративни процеси} - \item При итеративните процеси липсва етап на свиването на рекурсията - \item Опашковата рекурсия се използва за симулиране на цикли - \item В Scheme опашковата рекурсия \alert{по стандарт} се интерпретира като цикъл - \begin{itemize} - \item т.е. не се заделя памет за всяко рекурсивно извикване - \end{itemize} - \end{itemize} -\end{frame} - -\section{Вложени дефиниции} - -\againframe<3>{reciter} - -\againframe<14>{iterenv} - -\subsection{Влагане на \tt{define}} - -\begin{frame}[fragile] - \frametitle{Вложени дефиниции} - - \begin{itemize}[<+->] - \item \tta{(define (}<функция> \{<параметър\}\tta) \{<дефиниция>\} <тяло>\tta) - \item При извикване на <функция> първо се оценяват всички <дефиниция> и след това се оценява <тяло> - \begin{itemize} - \item Първо се създава среда $E_1$, в която формалните параметри се свързват с оценките на фактическите - \item След това се създава среда $E_2$, която разширява $E_1$, за вложените дефиниции - \item В средата $E_2$ се записват всички символи от вложени дефиниции \alert{без стойности} - \item Всички вложени дефиниции се \textbf{оценяват} в $E_2$ - \item Накрая получените оценки се \textbf{свързват} със съответните си символи в $E_2$ - \end{itemize} - \item \textbf{Пример:}\hspace{5ex} - \begin{minipage}[t]{.5\textwidth} - \lstsmall -\begin{lstlisting}[aboveskip=-1.4\medskipamount] -(define (dist x1 y1 x2 y2) - (define dx (- x2 x1)) - (define dy (- y2 y1)) - (define (sq x) (* x x)) - (sqrt (+ (sq dx) (sq dy)))) -\end{lstlisting} - \end{minipage} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Оценка на вложени функции} - - \sizeboth\scriptsize - \begin{fixedarea} - \begin{columns}[T,onlytextwidth] - \begin{column}{.5\textwidth} - \evalchain{ - "\lst{(dist 2 5 -1 9)}\only<+->{}"[label={[vp] \inenv E}] -> - "\lst{(define dx (- x2 x1))}"[env=E_2] -!- - "\lst{(define dy (- y2 y1))}"[env=E_2] -!- - "\lst{(define (sq x) (* x x))}"[env={E_2}] -!- - "\lst{(sqrt (+ (sq dx) (sq dy)))}"[env=E_2] -> - "\lst{(sqrt (+ (* x x) (sq dy)))}"[env=E_3] -> - "\lst{(sqrt (+ 9 (* x x)))}"[env=E_4] -> - "\lst{(sqrt (+ 9 16))}"[env=E_2] -> - "\lst{(sqrt 25)}"[env=E_2] -> - "\tt 5"[env=E_2]; - } - \end{column} - \begin{column}{.5\textwidth} - \begin{tikzpicture} - \envir{E}{\kf{dist}{x1 y1 x2 y2}\ldots E} - \childenvir[2-]{below=1em}E{E_1}{ - \kv{x1}2 - \kv{y1}5 - \kv{x2}{-1} - \kv{y2}9 - } - \childenvir[3-]{below=1em}{E_1}{E_2}{ - \only<3->{\kv{dx}{\only<6->{-3}}} - \only<4->{\kv{dy}{\only<6->{4}}} - \only<5->{\alt<5| trans:0>{\kv{sq}{}}{\kf{sq}x{(* x x)}{E_2}}} - } - \childenvir[7-]{above left =1em and -3em}{E_2}{E_3}{\kv x{-3}} - \childenvir[8-]{above right=1em and -3em}{E_2}{E_4}{\kv x4} - \end{tikzpicture} - \end{column} - \end{columns} - \end{fixedarea} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Вложена помощна итеративна функция} - - При итеративни функция е удобно помощната функция да е вложена. - \begin{fixedarea}[.5] - \begin{onlyenv}<1| trans:0> -\begin{lstlisting} -(define (for n r i) - (if (<= i n) - (for n (* r i) (+ i 1)) - r)) - -(define (fact n) - (for n 1 1)) -\end{lstlisting} - \end{onlyenv} - \begin{onlyenv}<2-> -\begin{lstlisting} -(define (fact n) - (define (for r i) - (if (<= i n) - (for (* r i) (+ i 1)) - r)) - (for 1 1)) -\end{lstlisting} - \end{onlyenv} - \end{fixedarea} - \onslide<3-> - Вложените дефиниции „виждат“ символите на обхващащите им дефиниции. -\end{frame} - -\begin{frame} - \frametitle{Оценка на итеративен факториел с вложена функция} - - \begin{columns}[T,onlytextwidth] - \begin{column}{.63\textwidth} - \sizeboth\scriptsize - \begin{center} - % TODO: да се реализира с foreach - \evalchain[(-1)]{ - "\lst{(fact 4)}\only<+->{}"[label={[vp] \inenv E}] -> - "\lst{(define (for r i)...)}"[envv={\alert{E_1}}] ->[v] - "(for 1 1)"[envv=E_1] ->[v] - "\alt<+->{\lst{(for 1 2)}}{\lst{(if (<= i n) (for (* r i) (+ i 1)) r)}}"[env=E_2] -> - "\alt<+->{\lst{(for 2 3)}}{\lst{(if (<= i n) (for (* r i) (+ i 1)) r)}}"[env=E_3] -> - "\alt<+->{\lst{(for 6 4)}}{\lst{(if (<= i n) (for (* r i) (+ i 1)) r)}}"[env=E_4] -> - "\alt<+->{\lst{(for 24 5)}}{\lst{(if (<= i n) (for (* r i) (+ i 1)) r)}}"[env=E_5] -> - "\alt<+->{\lst{24}}{\lst{(if (<= i n) (for (* r i) (+ i 1)) r)}}"[env=E_6]; - } - \end{center} - \end{column} - \begin{column}{.37\textwidth} - \tiny - \begin{tikzpicture} - \envir{E}{\kf{fact}n{(for 1 1)}E} - \childenvir[2- ]{below=1em}{E}{E_0}{\kv n4} - \childenvir[3- ]{below=1em}{E_0}{E_1}{\kf{for}{r i}\ldots{\alert<3>{E_1}}} - \childenvir[5- ]{below left =2em and -2em}{E_1}{E_2}{\kv r1 \kv i1} - \childenvir[7- ]{below =2em }{E_1}{E_3}{\kv r1 \kv i2} - \childenvir[9- ]{below right=2em and -2em}{E_1}{E_4}{\kv r2 \kv i3} - \childenvir[11-]{below left =7em and -3em}{E_1}{E_5}{\kv r6 \kv i4} - \childenvir[13-]{below right=7em and -3em}{E_1}{E_6}{\kv r{24}\kv i5} - \end{tikzpicture} - \end{column} - \end{columns} -\end{frame} - -\subsection{\tt{let} и \tt{let*}} - -\begin{frame} - \frametitle{Специална форма \tt{let}} - - \begin{itemize}[<+->] - \item \tta{(let} \tta(\{\tta({}<символ> <израз>\tta)\}\tta) <тяло>\tta) - \item \tta{(let ((}{}<символ$_1$> <израз$_1$>\tta)\\ - \tta{\hskip 7ex(}{}<символ$_2$> <израз$_2$>\tta)\\ - \hskip 7ex\ldots\\ - \tta{\hskip 7ex(}{}<символ$_n$> <израз$_n$>\tta{))}\\ - \hskip 7ex{}<тяло>\tta) - \item При оценка на \tt{let} в среда \env E: - \begin{itemize}[<+->] - \item Създава се нова среда \env{E_1} разширение на текущата - среда \env E - \item Оценката на <израз$_1$> в \env E се свързва със <символ$_1$> в \env{E_1} - \item Оценката на <израз$_2$> в \env E се свързва със <символ$_2$> в \env{E_1} - \item \ldots - \item Оценката на <израз$_n$> в \env E се свързва със <символ$_n$> в \env{E_1} - \item Връща се оценката на <тяло> в средата \env{E_1} - \end{itemize} - \item \alert{\tt{let} няма странични ефекти върху средата!} - \end{itemize} -\end{frame} - -\begin{frame}<1-3>[fragile] - \frametitle{Пример за \tt{let}} - -\begin{lstlisting} -(define (dist x1 y1 x2 y2) - (let ((dx (- x2 x1)) - (dy (- y2 y1))) - (sqrt (+ (sq dx) (sq dy))))) -\end{lstlisting} -\pause -\begin{lstlisting} -(define (area x1 y1 x2 y2 x3 y3) - (let ((a (dist x1 y1 x2 y2)) - (b (dist x2 y2 x3 y3)) - (c (dist x3 y3 x1 y1)) - @\alert<3>{(p (/ (+ a b c) 2))})@ - (sqrt (* p (- p a) (- p b) (- p c))))) -\end{lstlisting} -\end{frame} - -\begin{frame} - \frametitle{Оценка на \tt{let}} - - \sizeboth\scriptsize - \begin{columns}[T,onlytextwidth] - \begin{column}{.55\textwidth} - \begin{center} - \evalchain{ - "\lst{(dist 2 5 -1 9)}"[env=E] -> - "\lst{(let ((dx (- x2 x1))}\\\hskip 7ex\lst{(dy (- y2 y1)))}\\\hskip 2ex\lst{(sqrt (+ (sq dx) (sq dy))))}"[env=E_1,align=left] -> - "\lst{(sqrt (+ (sq dx) (sq dy)))}"[env=E_2] -> - "\lst{(sqrt (+ (* x x) (sq dy)))}"[env=E_3] -> - "\lst{(sqrt (+ 9 (* x x)))}"[env=E_4] -> - "\lst{(sqrt (+ 9 16))}"[env=E_2] -> - "\lst{(sqrt 25)}"[env=E_2] -> - "\tt 5"[env=E_2]; - } - \end{center} - \end{column} - \begin{column}{.45\textwidth} - \begin{tikzpicture} - \envir{E}{\kf{dist}{x1 y1 x2 y2}\ldots E} - \childenvir[2-]{below=2em}E{E_1}{ - \kv{x1}2 - \kv{y1}5 - \kv{x2}{-1} - \kv{y2}9 - } - \childenvir[3-]{below=2em}{E_1}{E_2}{ - \kv{dx}{-3} - \kv{dy}4 - } - \childenvir[4-]{below left =2em and -4em}E{E_3}{\kv x{-3}} - \childenvir[5-]{below right=2em and -4em}E{E_4}{\kv x4} - \end{tikzpicture} - \end{column} - \end{columns} -\end{frame} - -\begin{frame} - \frametitle{Специална форма \tt{let*}} - - \begin{itemize}[<+->] - \item \tta{(let*} \tta(\{\tta({}<символ> <израз>\tta)\}\tta) <тяло>\tta) - \item \tta{(let* ((}{}<символ$_1$> <израз$_1$>\tta)\\ - \tta{\hskip 8ex(}{}<символ$_2$> <израз$_2$>\tta)\\ - \hskip 7ex\ldots\\ - \tta{\hskip 8ex(}{}<символ$_n$> <израз$_n$>\tta{))}\\ - \tta{\hskip 8ex}{}<тяло>\tta) - \item При оценка на \tt{let*} в среда \env E: - \begin{itemize}[<+->] - \item Създава се нова среда \env{E_1} разширение на текущата - среда \env E - \item Оценката на <израз$_1$> в \env E се свързва със <символ$_1$> в \env{E_1} - \item Създава се нова среда \env{E_2} разширение на текущата - среда \env{E_1} - \item Оценката на <израз$_2$> в \env{E_1} се свързва със <символ$_2$> в \env{E_2} - \item \ldots - \item Създава се нова среда \env{E_n} разширение на текущата - среда \env{E_{n-1}} - \item Оценката на <израз$_n$> в \env{E_{n-1}} се свързва със <символ$_n$> в \env{E_n} - \item Връща се оценката на <тяло> в средата \env{E_n} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Пример за \tt{let*}} - -\begin{lstlisting} -(define (area x1 y1 x2 y2 x3 y3) - (let* ((a (dist x1 y1 x2 y2)) - (b (dist x2 y2 x3 y3)) - (c (dist x3 y3 x1 y1)) - (p (/ (+ a b c) 2))) -\end{lstlisting} - \pause - \alert{Редът има значение!} -\begin{lstlisting} -(define (area x1 y1 x2 y2 x3 y3) - (let* (@\alert{(p (/ (+ a b c) 2))}@ - (a (dist x1 y1 x2 y2)) - (b (dist x2 y2 x3 y3)) - (c (dist x3 y3 x1 y1))) - (sqrt (* p (- p a) (- p b) (- p c))))) -\end{lstlisting} -\end{frame} - -\begin{frame} - \frametitle{Оценка на \tt{let*}} - - \sizeboth\scriptsize - \begin{columns}[T,onlytextwidth] - \begin{column}{.55\textwidth} - \begin{center} - \evalchain{ - "\lst{(dist 2 5 -1 9)}"[env=E] ->[visible on=<+(-1)->] - "\lst{(let* ((dx (- x2 x1))}\\\hskip 8ex\lst{(dy (- y2 y1)))}\\\hskip 2ex\lst{(sqrt (+ (sq dx) (sq dy))))}"[env=E_1,align=left] -> - "\lst{(sqrt (+ (sq dx) (sq dy)))}"[env=E_3] -> - "\lst{(sqrt (+ (* x x) (sq dy)))}"[env=E_4] -> - "\lst{(sqrt (+ 9 (* x x)))}"[env=E_5] -> - "\lst{(sqrt (+ 9 16))}"[env=E_3] -> - "\lst{(sqrt 25)}"[env=E_3] -> - "\tt 5"[env=E_3]; - } - \end{center} - \end{column} - \begin{column}{.45\textwidth} - \begin{tikzpicture} - \envir{E}{\kf{dist}{x1 y1 x2 y2}\ldots E} - \childenvir[2-]{below=1.5em}E{E_1}{ - \kv{x1}2 - \kv{y1}5 - \kv{x2}{-1} - \kv{y2}9 - } - \childenvir[3-]{below=1em}{E_1}{E_2}{\kv{dx}{-3}} - \childenvir[4-]{below=1em}{E_2}{E_3}{\kv{dy}4} - \childenvir[5-]{below left =1.5em and -4em}E{E_4}{\kv x{-3}} - \childenvir[6-]{below right=1.5em and -4em}E{E_5}{\kv x4} - \end{tikzpicture} - \end{column} - \end{columns} -\end{frame} - -\section{Нелинейни изчислителни процеси} - -\subsection{Логаритмични процеси} - -\begin{frame}[fragile] - \frametitle{Степенуване} - - Функцията $x^n$ може да се дефинира по следния начин: - \begin{equation*} - x^n = \begin{cases} - 1,&\text{ ако }n = 0,\\ - \frac 1 {x^{-n}},&\text{ ако }n < 0,\\ - x\cdot x^{n-1},&\text{ ако }n > 0. - \end{cases} - \end{equation*} - \pause -\begin{lstlisting} -(define (pow x n) - (cond ((= n 0) 1) - ((< n 0) (/ 1 (pow x (- n)))) - (else (* x (pow x (- n 1)))))) -\end{lstlisting} -\end{frame} - -\begin{frame} - \frametitle{Оценка на степенуване} - \begin{center} - \tiny - \vspace{-2ex} - % TODO: да се реализира с foreach - \tikzset{/evalchain/.append style={grow down sep=1.5ex}} - \evalchain{ - "(pow 2 6)" -> - "(* 2 (pow 2 5))" -> - "(* 2 (* 2 (pow 2 4)))" -> - "(* 2 (* 2 (* 2 (pow 2 3))))" -> - "(* 2 (* 2 (* 2 (* 2 (pow 2 2)))))" -> - "(* 2 (* 2 (* 2 (* 2 (* 2 (pow 2 1))))))" -> - "(* 2 (* 2 (* 2 (* 2 (* 2 (* 2 (pow 2 0)))))))" -> - "(* 2 (* 2 (* 2 (* 2 (* 2 (* 2 1))))))" -> - "(* 2 (* 2 (* 2 (* 2 (* 2 2)))))" -> - "(* 2 (* 2 (* 2 (* 2 4))))" -> - "(* 2 (* 2 (* 2 8)))" -> - "(* 2 (* 2 16))" -> - "(* 2 32)" -> - "64"; - } - \end{center} - \vspace{-4ex} - \onslide<+-> - Линеен рекурсивен процес -\end{frame} - -\begin{frame}[fragile] - \frametitle{Бързо степенуване} - - Алтернативна дефиниция на $x^n$: - \begin{equation*} - x^n = \begin{cases} - 1,&\text{ ако }n = 0,\\ - \frac 1 {x^{-n}},&\text{ ако }n < 0,\\ - (x^{\frac n2})^2,&\text{ ако }n > 0, n\text{ --- четно},\\ - x\cdot x^{n-1},&\text{ ако }n > 0, n\text{ --- нечетно}. - \end{cases} - \end{equation*} - \pause -\begin{lstlisting} -(define (qpow x n) - (define (sqr x) (* x x)) - (cond ((= n 0) 1) - ((< n 0) (/ 1 (qpow x (- n)))) - ((even? n) (sqr (qpow x (quotient n 2)))) - (else (* x (qpow x (- n 1)))))) -\end{lstlisting} -\end{frame} - -\begin{frame} - \frametitle{Оценка на бързо степенуване} - - \begin{center} - \scriptsize - % TODO: да се реализира с foreach - \evalchain{ - "(qpow 2 6)" -> - "(sqr (qpow 2 3))" -> - "(sqr (* 2 (qpow 2 2)))" -> - "(sqr (* 2 (sqr (qpow 2 1))))" -> - "(sqr (* 2 (sqr (* 2 (qpow 2 0)))))" -> - "(sqr (* 2 (sqr (* 2 1))))" -> - "(sqr (* 2 (sqr 2)))" -> - "(sqr (* 2 4))" -> - "(sqr 8)" -> - "64"; - } - \end{center} - \vspace{-4ex} - \onslide<+-> - Логаритмичен рекурсивен процес -\end{frame} - -\subsection{Дървовидни рекурсивни процеси} - -\begin{frame}[fragile] - \frametitle{Числа на Фибоначи} - - $0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, \ldots$\\ - \pause - \begin{equation*} - f_n = - \begin{cases} - 0, &\text{ за }n = 0,\\ - 1, &\text{ за }n = 1,\\ - f_{n-1} + f_{n-2}, &\text{ за }n \geq 2. - \end{cases} - \end{equation*} - \pause -\begin{lstlisting} -(define (fib n) - (cond ((= n 0) 0) - ((= n 1) 1) - (else (+ (fib (- n 1)) (fib (- n 2)))))) -\end{lstlisting} - \pause - $f_{40} = ?$ -\end{frame} - -\begin{frame} - \frametitle{Дървовидна рекурсия} - - % TODO: да се реализира с foreach - \begin{center} - \only<1 |trans:0>{ - \begin{forest} for tree={edge=ptr} - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] [\tt{(fib 0)} - [\tt 0]]] - \end{forest} - } - \only<2 |trans:0>{ - \begin{forest} for tree={edge=ptr} - [\tt{(fib 3)} - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] - [\tt{(fib 0)} [\tt 0]]] - [\tt{(fib 1)} [\tt 1]]] - \end{forest} - } - \only<3 |trans:0>{ - \begin{forest} for tree={edge=ptr} - [\tt{(fib 4)} - [\tt{(fib 3)} - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] - [\tt{(fib 0)} [\tt 0]]] - [\tt{(fib 1)} [\tt 1]]] - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] - [\tt{(fib 0)} [\tt 0]]]] - \end{forest} - } - \only<4 |trans:0>{ - \scriptsize - \begin{forest} for tree={edge=ptr} - [\tt{(fib 5)} - [\tt{(fib 4)} - [\tt{(fib 3)} - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] - [\tt{(fib 0)} [\tt 0]]] - [\tt{(fib 1)} [\tt 1]]] - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] - [\tt{(fib 0)} [\tt 0]]]] - [\tt{(fib 3)} - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] - [\tt{(fib 0)} [\tt 0]]] - [\tt{(fib 1)} [\tt 1]]]] - \end{forest} - } - \only<5->{ - \tiny - \begin{forest} for tree={edge=ptr,s sep=1pt,inner sep=1pt} - [\tt{(fib 6)} - [\tt{(fib 5)} - [\tt{(fib 4)} - [\tt{(fib 3)} - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] - [\tt{(fib 0)} [\tt 0]]] - [\tt{(fib 1)} [\tt 1]]] - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] - [\tt{(fib 0)} [\tt 0]]]] - [\tt{(fib 3)} - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] - [\tt{(fib 0)} [\tt 0]]] - [\tt{(fib 1)} [\tt 1]]]] - [\tt{(fib 4)} - [\tt{(fib 3)} - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] - [\tt{(fib 0)} [\tt 0]]] - [\tt{(fib 1)} [\tt 1]]] - [\tt{(fib 2)} - [\tt{(fib 1)} [\tt 1]] - [\tt{(fib 0)} [\tt 0]]]]] - \end{forest} - } - \end{center}\ \\ - \onslide<6>{Дървовиден рекурсивен процес} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Как да оптимизираме?} - - \textbf{Решение №1: мемоизация}\\ - Да помним вече пресметнатите стойности, вместо да ги смятаме пак.\\ - \pause - \alert{За ефективна реализация обикновено са нужни странични ефекти.}\\[2ex] - \pause - \textbf{Решение №2: динамично програмиране}\\ - Строим последователно всички числа на Фибоначи в нарастващ ред.\\ - \pause - \alert{Нужно е да помним само последните две числа!}\\ - \pause -\begin{lstlisting} -(define (fib n) - (define (iter i fi fi-1) - (if (= i n) fi - (iter (+ i 1) (+ fi fi-1) fi))) - (if (= n 0) 0 - (iter 1 1 0))) -\end{lstlisting} -\end{frame} - -\begin{frame} - \frametitle{Итеративно генериране на числата на Фибоначи} - - \footnotesize - \begin{center} - % TODO: да се реализира с foreach - \evalchain{ - "(fib 7)" -> - "(iter 1 1 0)" -> - "(iter 2 1 1)" -> - "(iter 3 2 1)" -> - "(iter 4 3 2)" -> - "(iter 5 5 3)" -> - "(iter 6 8 5)" -> - "(iter 7 13 8)" -> - "13"; - } - \end{center} -\end{frame} - -\end{document} diff --git a/1.4-scheme_lists.tex b/1.4-scheme_lists.tex deleted file mode 100644 index ab50a8a..0000000 --- a/1.4-scheme_lists.tex +++ /dev/null @@ -1,657 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -\title{Списъци} - -\date{16--23 октомври 2024 г.} -\lstset{language=Scheme} - -% взели ли сме вече функции връщащи функции? -\newboolfalse{highorder} - -% вариадични функции -\newboolfalse{variadic} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section{Наредени двойки} - -\begin{frame} - \frametitle{Наредени двойки} - - \begin{columns}[t,onlytextwidth] - \begin{column}{.5\textwidth} - \vspace{2ex} - \begin{center} - \tt{(A . B)} - \end{center} - \end{column} - \begin{column}{.5\textwidth} - \begin{center} - \begin{tikzpicture} - \pointcellxx cAB - \end{tikzpicture} - \end{center} - \end{column} - \end{columns} - \pause - \vspace{2ex} - \begin{itemize}[<+->] - \item \tta{(cons} <израз$_1$> <израз$_2$>\tta) - \item Наредена двойка от оценките на <израз$_1$> и <израз$_2$> - \item \tta{(car} <израз>\tta) - \item \textbf{Първият} компонент на двойката, която е оценката на <израз> - \item \tta{(cdr} <израз>\tta) - \item \textbf{Вторият} компонент на двойката, която е оценката на <израз> - \item \tta{(pair?} <израз>\tta) - \item Проверява дали оценката на <израз> е наредена двойка - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Примери} - - \begin{columns}[T,onlytextwidth] - \begin{column}{.6\textwidth} - \evalchainx{ - "(cons (cons 2 3) (cons 8 13))" -> "((2 . 3) . (8 . 13))" - } - \vspace{8ex} - \onslide<3->{ - \evalchainx{ - "(cons 3 (cons (cons 13 21) 8))" -> "(3 . ((13 . 21) . 8))" - } - } - \end{column} - \begin{column}{.4\textwidth} - \onslide<2->{ - \begin{tikzpicture} - \pointcell a - - \pointcellxx[below=2ex of a]b23 - \draw[ptr] (adata) to (bdata); - - \pointcellxx[right=2em of a]c8{13} - \draw[ptr] (anext) to (c); - \end{tikzpicture}\\[3ex] - } - \onslide<4>{ - \begin{tikzpicture} - \pointcellx b3 - - \pointcell[below=2ex of anext.south east]b - \draw[ptr] (anext) to (bdata); - - \val[right=2em of b]v8 - \draw[ptr] (bnext) to (v); - - \pointcellxx[below=2ex of bdata.south east]c{13}{21} - \draw[ptr] (bdata) to (cdata); - \end{tikzpicture} - } - \end{column} - \end{columns} -\end{frame} - -\begin{frame} - \frametitle{S-изрази} - - \begin{definition} - S-израз наричаме: - \begin{itemize} - \item атоми (булеви, числа, знаци, символи, низове, функции) - \item наредени двойки \tt{(S$_1$ . S$_2$)}, където \tt{S$_1$} и \tt{S$_2$} са S-изрази - \end{itemize} - \end{definition} - \vspace{2ex} - \pause - \alert{S-изразите са най-общият тип данни в Scheme.}\\[2ex] - С тяхна помощ могат да се дефинират произволно сложни структури от данни. -\end{frame} - -\begin{frame}<\switch{highorder}>[fragile] - \frametitle{All you need is $\lambda$ --- наредени двойки} - - Можем да симулираме \tt{cons}, \tt{car} и \tt{cdr} чрез \tt{lambda}!\\[2ex] - \pause - \textbf{Вариант №1:} -\begin{lstlisting} -(define (lcons x y) (lambda (p) (if p x y))) -(define (lcar z) (z #t)) -(define (lcdr z) (z #f)) -\end{lstlisting} - \pause - \textbf{Вариант №2:} -\begin{lstlisting} -(define (lcons x y) (lambda (p) (p x y))) -(define (lcar z) (z (lambda (x y) x))) -(define (lcdr z) (z (lambda (x y) y))) -\end{lstlisting} -\end{frame} - -\section{Списъци} - -\begin{frame} - \frametitle{Списъци в Scheme} - - \begin{definition} - \begin{enumerate} - \item Празният списък \tt{()} е списък - \item \tt{(h . t)} е списък ако \tt t е списък - \begin{itemize} - \item \tt h --- глава на списъка - \item \tt t --- опашка на списъка - \end{itemize} - \end{enumerate} - \end{definition} - \vspace{4ex} - \pause - \begin{tikzpicture} - \pointcellx{a1}{a_1} - \nextcellx{a2}{a_2}{a1} - \nextdots{a2} - \dotsnextcellx{an}{a_n} - \nullptr{annext} - \end{tikzpicture}\\[3ex] - \tt{($a_1$ . ($a_2$ . ( \ldots ( $a_n$ . () ) ) ) ) \eqv\ ($a_1$ $a_2$ \ldots\ $a_n$)} -\end{frame} - -\begin{frame} - \frametitle{Вградени функции за списъци} - - \begin{itemize}[<+->] - \item \tta{(null?} <израз>\tta) --- дали <израз> е празният списък \tt{()} - \item \tta{(list?} <израз>\tta) --- дали <израз> е списък - \begin{itemize} - \item \scriptsize \lst{(define (list? l) (or (null? l) (and (pair? l) (list? (cdr l)))))} - \end{itemize} - \item \tta{(list} \{<израз>\}\tta) --- построява списък с елементи <израз> - \item \tt{(list} <израз$_1$> <израз$_2$> \ldots <израз$_n$>\tt) \eqv\\ - \tt{(cons} <израз$_1$>\tt{ (cons} <израз$_2$> \ldots\tt{ (cons} <израз$_n$>\tt{ '()))))} - \item \tt{(cons} <глава> <опашка>\tt) --- списък с <глава> и <опашка> - \item \tt{(car} <списък>\tt) --- главата на <списък> - \item \tt{(cdr} <списък>\tt) --- опашката на <списък> - \item \alert{\tt{()} не е наредена двойка!} - \item \evalstoerr{(car '())},\hskip 1em \evalstoerr{(cdr '())} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Съкратени форми на \tt{car} и \tt{cdr}} - - Нека $l = (a_1\,a_2\,a_3\,\ldots\,a_n)$. - \begin{itemize}[<+->] - \item \evalstos{\tt{(car l)}}{$a_1$} - \item \evalstos{\tt{(cdr l)}}{$(a_2\,a_3\,...\,a_n)$} - \item \evalstwop{(car (cdr l))}{$a_2$}{(cadr l)} - \item \evalstwop{(cdr (cdr l))}{$(a_3\,...\,a_n)$}{(cddr l)} - \item \evalstwop{(car (cdr (cdr l)))}{$a_3$}{(caddr l)} - \item имаме съкратени форми за до 4 последователни прилагания на \tt{car} и \tt{cdr} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Форми на равенство в Scheme} - - \begin{itemize}[<+->] - \item \tta{(eq?} <израз$_1$> <израз$_2$>\tta) --- връща \tt{\#t} точно тогава, когато оценките на <израз$_1$> <израз$_2$> заемат едно и също място в паметта - \item \tta{(eqv?} <израз$_1$> <израз$_2$>\tta) --- връща \tt{\#t} точно тогава, когато оценките на <израз$_1$> и <израз$_2$> заемат едно и също място в паметта или са едни и същи по стойност \textbf{атоми} (без функции), дори и да заемат различно място в паметта - \begin{itemize} - \item Ако \tt{(eq?} <израз$_1$> <израз$_2$>\tt),\\ - то със сигурност \tt{(eqv?} <израз$_1$> <израз$_2$>\tt) - \end{itemize} - \item \tta{(equal?} <израз$_1$> <израз$_2$>\tta) --- връща \tt{\#t} точно тогава, когато оценките на <израз$_1$> и <израз$_2$> са едни и същи по стойност \textbf{атоми или наредени двойки}, чиито компоненти са равни в смисъла на \tt{equal?} - \begin{itemize} - \item В частност, \tt{equal?} проверява за равенство на списъци - \item Ако \tt{(eqv?} <израз$_1$> <израз$_2$>\tt),\\ - то със сигурност \tt{(equal?} <израз$_1$> <израз$_2$>\tt) - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Вградени функции за списъци} - \small - \begin{itemize}[<+->] - \item \tta{(length} <списък>\tta) --- връща дължината на <списък> - \item \tta{(append} \{<списък>\}\tta) --- конкатенира всички <списък> - \item \tta{(reverse} <списък>\tta) --- елементите на <списък> в обратен ред - \item \tta{(list-tail} <списък> n\tta) --- елементите на <списък> без първите n - \item \tta{(list-ref} <списък> n\tta) --- n-ти елемент на <списък> (от 0) - \item \tta{(member} <елемент> <списък>\tta) --- проверява дали <елемент> се среща в <списък> - \begin{itemize} - \item По-точно, връща <списък> от първото срещане на <елемент> нататък, ако го има - \item Връща \tt{\#f}, ако <елемент> го няма в <списък> - \item Сравнението на елементи става с \tt{equal?} - \end{itemize} - \item \tta{(memv} <елемент> <списък>\tta) --- като \tt{member}, но сравнява с \tt{eqv?} - \item \tta{(memq} <елемент> <списък>\tta) --- като \tt{member}, но сравнява с \tt{eq?} - \end{itemize} -\end{frame} - -\subsection{Рекурсия над списъци} - -\begin{frame} - \frametitle{Обхождане на списъци} - - При обхождане на \tt l: - \begin{itemize} - \item Ако \tt l е празен, връщаме базова стойност \textbf{(дъно)} - \item Иначе, комбинираме главата \tt{(car l)} с резултата от рекурсивното извикване над опашката \tt{(cdr l)} \textbf{(стъпка)} - \end{itemize} - \pause - \vspace{4ex} - \textbf{Примери:} \tt{length}, \tt{list-tail}, \tt{list-ref}, \tt{member}, \tt{memqv}, \tt{memq} -\end{frame} - -\begin{frame} - \frametitle{Конструиране на списъци} - - Използваме рекурсия по даден параметър (напр. число, списък...) - \begin{itemize} - \item На дъното връщаме фиксиран списък (например \tt{()}) - \item На стъпката построяваме с \tt{cons} списък със съответната глава, а опашката строим чрез рекурсивно извикване на същата функция - \end{itemize} - \pause - \vspace{4ex} - \textbf{Примери:} \tt{from-to}, \tt{collect}, \tt{append}, \tt{reverse} -\end{frame} - -\section{Функции от по-висок ред за списъци} - -\begin{frame}[label=map,fragile] - \frametitle{Изобразяване на списък (\tt{map})} - - Да се дефинира функция \tta{(map} <функция> <списък>\tta), която връща нов списък съставен от елементите на <списък>, върху всеки от които е приложена <функция>.\\ - \pause - \begin{center} - \begin{tikzpicture} - \matrix [widearray,row sep=8ex] { - |(a1)| a_1 \& |(a2)| a_2 \& \ldots \& |(an)| a_n \\ - |(fa1)| f(a_1) \& |(fa2)| f(a_2) \& \ldots \& |(fan)| f(a_n) \\ - }; - \graph[transform] { - a1 -> fa1; - a2 -> fa2; - an -> fan; }; - \node[ellipse,draw,fill=diagramblue,below=3.5ex of a2.east,minimum width=13em] {$f$}; - \end{tikzpicture} - \end{center} - \pause -\begin{lstlisting} -(define (map f l) - (if (null? l) '() - (cons (f (car l)) (map f (cdr l))))) -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile,label=mapex] - \frametitle{Изобразяване на списък (\tt{map}) --- примери} - -\begin{lstlisting} -(define (map f l) - (if (null? l) '() - (cons (f (car l)) (map f (cdr l))))) -\end{lstlisting} - - \small - \begin{itemize}[<+->] - \item \evalstop{(map square '(1 2 3))}{(1 4 9)} - \item \evalstop{(map cadr '((a b c) (d e f) (g h i)))}{(b e h)} - \item \evalstop{(map (lambda (f) (f 2)) (list square 1+ odd?))}{(4 3 \#f)} - \ifbool{highorder}{\item \evalstop{(map (lambda (f) (f 2)) (map twice (list square 1+ boolean?)))}{(16 4 \#t)}}{} - \end{itemize} -\end{frame} - -\begin{frame}[fragile,label=filter] - \frametitle{Филтриране на списък (\tt{filter})} - - Да се дефинира функция \tta{(filter} <условие> <списък>\tta), която връща само тези от елементите на <списък>, които удовлетворяват <условие>. -\pause - \begin{center} - \begin{tikzpicture} - \matrix [widearray,row sep=7ex,nodes in empty cells=false] { - |(a1)| a_1 \& |(dots1)| \ldots \& |(ai)| a_i \& |(dots2)| \ldots \& |(aj)| a_j \& |(dots3)| \ldots \& |(ak)| a_k \& |(dots4)| \ldots \& |(an)| a_n \\ - \&\& |(pa1)| a_1 \& |(pai)| a_i \&|(pak)| a_k\& |(pdots)| \ldots \\ - }; - \graph[transform] { - a1.south -> pa1.north; - ai.south -> pai.north; - ak.south -> pak.north; - dots1.south --[shorten >=5ex] pa1.north east; - dots2.south --[shorten >=3ex] pai.north east; - aj.south --[shorten >=3ex] pak.north west; - dots3.south --[shorten >=5ex] pak.north west; - dots4.south --[shorten >=6ex] pdots.north; - an.south --[shorten >=9ex] pdots.north east; - }; - \node[trapezium, - trapezium angle=98, - trapezium stretches=true, - right, - draw, - fill=diagramblue, - below=2ex of aj, - minimum width=25em, - minimum height=3ex] {$p$}; - \end{tikzpicture} - \end{center} -\pause -\small -\begin{lstlisting} -(define (filter p? l) - (cond ((null? l) l) - ((p? (car l)) (cons (car l) (filter p? (cdr l)))) - (else (filter p? (cdr l))))) -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile,label=filterex] - \frametitle{Филтриране на списък (\tt{filter})} - \begin{fixedarea} -\begin{lstlisting} -(define (filter p? l) - (cond ((null? l) l) - ((p? (car l)) (cons (car l) (filter p? (cdr l)))) - (else (filter p? (cdr l))))) -\end{lstlisting} - \begin{itemize}[<+->] - \item \evalstop{(filter odd? '(1 2 3 4 5))}{(1 3 5)} - \item \evalstop{(filter pair? '((a b) c () d (e)))}{((a b) (e))} - \item \evalstopnl{(map (lambda (x) (filter even? x)) '((1 2 3) (4 5 6) (7 8 9)))}{((2) (4 6) (8))} - \item \evalstopnl{(map (lambda (x) (map (lambda (f) (filter f x)) (list negative? zero? positive?))) '((-2 1 0) (1 4 -1) (0 0 1)))}{(((-2) (0) (1)) ((-1) () (1 4)) (() (0 0) (1)))} - \end{itemize} - \end{fixedarea} -\end{frame} - -\begin{frame}[fragile,label=foldr] - \frametitle{Дясно свиване (\tt{foldr})} - - Да се дефинира функция, която по даден списък $l = (a_1\,a_2\,a_3\,\ldots\,a_n)$ пресмята: - \begin{equation*} - a_1 \oplus \Big(a_2 \oplus \big(\ldots \oplus (a_n \oplus \bot) \ldots\big)\Big), - \end{equation*}\\[-1ex] - \pause - \begin{columns}[T,onlytextwidth] - \begin{column}{.25\textwidth} - \begin{forest} for tree={edge=<-} - [$\oplus$ [$a_1$] - [$\oplus$ [$a_2$] - [$\vdots$ [,phantom] - [$\oplus$ [$a_n$] [$\bot$]]]]] - \end{forest} - \end{column} - \pause - \begin{column}{.75\textwidth} -\begin{lstlisting} -(define (foldr op nv l) - (if (null? l) nv - (op (car l) (foldr op nv (cdr l))))) -\end{lstlisting} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile,label=foldrex] - \frametitle{Дясно свиване (\tt{foldr}) --- примери} - -\begin{lstlisting} -(define (foldr op nv l) - (if (null? l) nv - (op (car l) (foldr op nv (cdr l))))) -\end{lstlisting} - \small - \begin{itemize}[<+->] - \item \evalstop{(foldr * 1 (from-to 1 5))}{120} - \item \evalstop{(foldr + 0 (map square (filter odd? (from-to 1 5))))}{35} - \item \evalstop{(foldr cons '() '(1 5 10))}{(1 5 10)} - \item \evalstop{(foldr list '() '(1 5 10))}{(1 (5 (10 ()))} - \item \evalstop{(foldr append '() '((a b) (c d) (e f)))}{(a b c d e f)} - \item \tt{map}, \tt{filter} и \tt{accumulate} могат да се реализират чрез \tt{foldr} - \end{itemize} -\end{frame} - -\begin{frame}[fragile,label=foldl] - \frametitle{Ляво свиване (\tt{foldl})} - - Да се дефинира функция, която по даден списък $l = (a_1\,a_2\,a_3\,\ldots\,a_n)$ пресмята: - \begin{equation*} - \Big(\ldots\big((\bot \oplus a_1) \oplus a_2\big) \oplus \ldots\Big) \oplus a_n - \end{equation*}\\[-1ex] - \pause - \begin{columns}[T,onlytextwidth] - \begin{column}{.3\textwidth} - \begin{forest} for tree={edge=<-} - [$\oplus$ - [$\vdots$ - [$\oplus$ - [$\oplus$ [$\bot$] [$a_1$]] - [$a_2$]] - [,phantom]] - [$a_n$]] - \end{forest} - \end{column} - \pause - \begin{column}{.7\textwidth} -\begin{lstlisting} -(define (foldl op nv l) - (if (null? l) nv - (foldl op (op nv (car l)) (cdr l)))) -\end{lstlisting} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile,label=foldlex] - \frametitle{Ляво свиване (\tt{foldl}) --- примери} - -\begin{lstlisting} -(define (foldl op nv l) - (if (null? l) nv - (foldl op (op nv (car l)) (cdr l)))) -\end{lstlisting} - \pause - \small - \begin{itemize}[<+->] - \item \evalstop{(foldl * 1 (from-to 1 5))}{120} - \item \evalstop{(foldl cons '() '(1 5 10))}{(((() . 1) . 5) . 10)} - \item \evalstos{\tt{(foldl }\rvl{\lst{(lambda (x y) (cons y x))}} \lst{ '() '(1 5 10))}}{\tt{(10 5 1)}} - \item \evalstop{(foldl list '() '(1 5 10))}{(((() 1) 5) 10)} - \item \evalstop{(foldl append '() '((a b) (c d) (e f)))}{(a b c d e f)} - \item \tt{foldr} генерира линеен рекурсивен процес, а \tt{foldl} --- линеен итеративен - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Функции от по-висок ред в Racket} - - В R$^5$RS е дефинирана само функцията \tt{map}.\\ - В Racket са дефинирани функциите \tt{map}, \tt{filter}, \tt{foldr}, \tt{foldl}\\[2ex] - \pause - \alert{Внимание: \tt{foldl} в Racket е дефинирана по различен начин!}\\[2ex] - \begin{columns}[T,onlytextwidth] - \small - \begin{column}{.5\textwidth} - \tt{foldl} от лекции\\[2ex] -\begin{lstlisting} -(define (foldl op nv l) - (if (null? l) nv - (foldl op @\alert{(op nv (car l))}@ - (cdr l)))) -\end{lstlisting} - \begin{equation*} - \Big(\ldots\big((\bot \oplus a_1) \oplus a_2\big) \oplus \ldots\Big) \oplus a_n - \end{equation*} - \end{column} - \begin{column}{.5\textwidth} - \tt{foldl} в Racket\\[2ex] -\begin{lstlisting} -(define (foldl op nv l) - (if (null? l) nv - (foldl op @\alert{(op (car l) nv)}@ - (cdr l)))) -\end{lstlisting} - \begin{equation*} - a_n \oplus \Big(\ldots \big(a_2 \oplus (a_1 \oplus \bot)\big)\ldots\Big), - \end{equation*} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Свиване на непразен списък (\tt{foldr1, foldl1})} - - \textbf{Задача.} Да се намери максималният елемент на списък.\\ - \pause - \lst{(define (maximum l) (foldr max}\tt{ \alt<2>?{(car l)} l))}\\[2ex] - \pause\pause - Можем ли да пропуснем нулевата стойност за непразен списък?\\[2ex] - \begin{tabular}{ll} - \pause - $a_1 \oplus \big(\ldots \oplus (a_{n-1} \oplus a_n) \ldots\big)$ - & \pause -\begin{lstlisting} -(define (foldr1 op l) - (if (null? (cdr l)) (car l) - (op (car l) - (foldr1 op (cdr l))))) -\end{lstlisting}\\[6ex] - \pause - $\big(\ldots\big((a_1 \oplus a_2) \oplus \ldots\big) \oplus a_n$ - & \pause -\begin{lstlisting} -(define (foldl1 op l) - (foldl op (car l) (cdr l))) -\end{lstlisting} - \end{tabular} -\end{frame} - -\section{Вариадични функции} - -\begin{frame}<\switch{variadic}> - \frametitle{Вариадични функции --- приемащи произволен брой аргументи} - - \begin{itemize}[<+->] - \item \tta{(lambda} <списък> <тяло>\tta) - \item създава функция с <тяло>, която получава <списък> от параметри - \item \tta{(lambda (}\{<параметър>\}$^+$ \tta. <списък>\tta) <тяло>\tta) - \item създава функция с <тяло>, която получава няколко задължителни <параметър> и <списък> от опционални параметри - \item \tta{(define (}<функция> \tta. <списък>\tta) <тяло>\tta) - \item еквивалентно на \\ - \lst{(define} <функция> \tt{(lambda }<списък> <тяло>\tt{))} - \item \tta{(define (}<функция> \{<параметър>\}$^+$ \tta. <списък>\tta) <тяло>\tta) - \item еквивалентно на \\ - \lst{(define} <функция> \lst{(lambda (}\{<параметър>\}$^+$ \tt. <списък>\tt) <тяло>\tt{))} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{variadic}> - \frametitle{Примери} - - \begin{itemize}[<+->] - \item \lst{(define (maximum x . l) (foldl1 max (cons x l)))} - \item \evalstop{(maximum 7 3 10 2)}{10} - \item \evalstop{(maximum 100)}{100} - \item \evalstoerrp{(maximum)} - \item \lst{(define (g x y . l) (append x l y l))} - \item \evalstop{(g '(1 2 3) '(4 5 6))}{(1 2 3 4 5 6)} - \item \evalstop{(g '(1 2 3) '(4 5 6) 7 8)}{(1 2 3 7 8 4 5 6 7 8)} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Прилагане на функция над списък от параметри (\tt{apply})} - - \begin{itemize}[<+->] - \item \tta{(apply} <функция> <списък>\tta) - \item прилага <функция> над <списък> от параметри - \item \textbf{Примери:} - \item \evalsto{(apply + '(1 2 3 4 5))}{15} - \item \evalstop{(apply append '((1 2) (3 4) (5 6)))}{(1 2 3 4 5 6)} - \item \evalstop{(apply list '(1 2 3 4))}{(1 2 3 4)} - \end{itemize} -\ifbool{variadic}{ -\onslide<+-> -\small -\begin{lstlisting} -(define (append . l) - (cond ((null? l) '()) - ((null? (car l)) (apply append (cdr l))) - (else (cons (caar l) - (apply append (cons (cdar l) (cdr l))))))) -\end{lstlisting} - }{} -\end{frame} - - -\begin{frame}<\switch{variadic}>[fragile] - \frametitle{Вариадичен \lst{map}} - - \begin{itemize}[<+->] - \item Функцията \lst{map} може да се използва с произволен брой списъци! - \item \tta{(map} <$n$-местна функция> $l_1 \ldots l_n$\tta) - \item Конструира нов списък, като прилага <$n$-местна функция> над съответните поредни елементи на списъците $l_1, \ldots, l_n$\\ - \onslide<+-> - \begin{tikzpicture}[comb/.style={circle,minimum size=1.5em}] - \scriptsize - \matrix [widearray,nodes in empty cells=false] { - |(a1)| a_1 \& |(a2)| a_2 \& \ldots \& |(ak)| a_k \&\& |(b1)| b_1 \& |(b2)| b_2 \& \ldots \& |(bk)| b_k\\[12ex] - \&\&|(pab1)[comb]| f \& |(pab2)[comb]| f \& \& |(pabk)[comb]| f \\[2ex] - \&\&|(fab1)| c_1 \& |(fab2)| c_2 \& \ldots \& |(fabk)| c_k\\ - }; - \graph[transform] { - pab1 -> fab1; - pab2 -> fab2; - pabk -> fabk; - a1.south ->[bl] pab1; - a2.south ->[bl] pab2; - ak.south ->[bl] pabk; - b1.south ->[br] pab1; - b2.south ->[br] pab2; - bk.south ->[br] pabk; - }; - \end{tikzpicture} - \item \evalstop{(map + '(1 2 3) '(4 5 6))}{(5 7 9)} - \item \evalstop{(map list '(1 2 3) '(4 5 6))}{((1 4) (2 5) (3 6))} - \item \small \evalstop{(map foldr (list * +) '(1 0) '((1 2 3) (4 5 6)))}{(6 15)} -\end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Оценяване на списък като комбинация (\tt{eval})} - - \begin{itemize}[<+->] - \item \tta{(eval} <среда>\tta) - \item връща оценката на в <среда> - \item \tta{(interaction-environment)} --- текущата среда, в която оценяваме - \item \lst{(define (evali x) (eval x (interaction-environment)))} - \item \textbf{Примери:} - \item \lst{(define a 2)} - \item \evalsto a2 - \item \evalsto{(evali a)}2 - \item \evalstop{(evali 'a)}2 - \item \evalstop{(evali ''a)}a - \item \evalstop{(evali (evali ''a))}2 - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Примери за \tt{eval}} - - \begin{itemize}[<+->] - \item \evalstop{(evali (list '+ 5 7 'a))}{14} - \item \evalstoerrp{(evali (list 'define b 5))} - \item \lst{(evali (list 'define 'b 5))} \eqv\ \lst{(define b 5)} - \item \evalsto{b}5 - \item {\small \evalstop{(evali (list 'if (list '< 2 5) (list 'quote 'a) 'b))}a} - \item \lst{(define (apply f l) (evali (cons f l)))} - \end{itemize} - \onslide<+-> - \alert{Програмите на Scheme могат да се разглеждат като данни!} -\end{frame} - -\end{document} diff --git a/1.5-scheme_ds.tex b/1.5-scheme_ds.tex deleted file mode 100644 index 47c1bfc..0000000 --- a/1.5-scheme_ds.tex +++ /dev/null @@ -1,1317 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -%% кои теми да се включат - -% матрици -\newboolfalse{matrices} - -% капсулация чрез функционални обекти -\newbooltrue{encapsulation} - -% алтернативна реализация на add-assoc -\newboolfalse{altaddassoc} - -% дълбоки списъци -\newbooltrue{deeplists} - -% графи -\newboolfalse{graphs} - -% допълнителни съкратени команди за дълбоките списъци -\newcommand{\hzero}{\textcolor{red}} -\newcommand{\vzero}{\textcolor{orange}} -\newcommand{\hstep}{\textcolor{green}} -\newcommand{\vstep}{\textcolor{cyan}} - -\title{Структури от данни в Scheme} -\subtitle{\ifbool{matrices}{матрици, }асоциативни списъци, дървета\ifbool{deeplists}{, дълбоки списъци}{}\ifbool{graphs}{, графи}{}} - -\date[25.10–6.11.2024 г.]{25 октомври – 6 ноември 2024 г.} - -\lstset{language=Scheme} - -\newcommand{\samplegraph}[1][1.2]{% - \begin{tikzpicture} - [>=stealth, - every node/.style=graphnode, - scale=#1] - \node (1) at (1,2) {1}; - \node (2) at (3,2.2) {2}; - \node (3) at (1.9,1.2) {3}; - \node (4) at (0.8,0.3) {4}; - \node (5) at (2.5,0) {5}; - \node (6) at (3.5,1.2) {6}; - \graph { - (1) -> {(2), (3)}; - (2) -> (3); - (3) -> {(4), (5)}; - (5) -> {(2), (4) ,(6)}; - (6) -> (2); - }; - \end{tikzpicture}} - -% изисквания към графа: -% да не е силно свързан (т.е. да има недостижим връх) -%% 1 -% да има път, който се намира само след backtracking -%% 1 -> 2 -> 3 -> 4 <- 3 -> 5 -% да има път, който минава през цикъл при първо минаване и пътят се намира едва след backtracking -%% 1 -> 2 -> 3 -> 5 -> 2 -> ... <- 5 -> 6 -% да има път, който минава през цикъл, но в цикъла се влиза чак след backtracking, при първо минаване се намира пътя -%% 1 -> 2 -> 3 -> 4 <- 3 -> 5 -> 2 -> ... - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section{Матрици} - -\subsection{Представяне} - -\begin{frame}<\switch{matrices}>[fragile] - \frametitle{Представяне на матрици} - Можем да представим матрица като списък от списък от елементи:\\ - \begin{columns}[T,onlytextwidth] - \begin{column}{0.5\textwidth} - \begin{equation*} - \left( - \begin{array}{ccc} - 1 & 2 & 3\\ - 4 & 5 & 6 - \end{array} - \right) - \end{equation*} - \end{column} - \begin{column}{0.5\textwidth} - \vspace{2ex} - \tt{((1 2 3) (4 5 6))} - \end{column} - \end{columns} - \vspace{2ex} - \pause - Проверка за коректност: - \pause -\begin{lstlisting} -(define (all? p? l) - (foldr (lambda (x y) (and x y)) #t (map p? l))) - -(define (matrix? m) - (and (list? m) - (not (null? (car m))) - (all? list? m) - (all? (lambda (row) (= (length row) - (length (car m)))) m))) -\end{lstlisting} -\end{frame} - -\subsection{Операции} - -\begin{frame}<\switch{matrices}>[fragile] - \frametitle{Базови операции} - - Брой редове и стълбове - \pause - \onslide<+-> -\begin{lstlisting} -(define @\alt<+->{get-rows length)}{(get-rows m) (length m))}@ -(define (get-columns m) (length (car m))) -\end{lstlisting} - \onslide<+-> - Намиране на първи ред и стълб - \onslide<+-> -\begin{lstlisting} -(define @\alt<+->{get-first-row car)}{(get-first-row m) (car m))}@ -(define (get-first-column m) (map car m)) -\end{lstlisting} - \onslide<+-> - Изтриване на първи ред и стълб - \onslide<+-> -\begin{lstlisting} -(define @\alt<+->{del-first-row cdr)}{(del-first-row m) (cdr m))}@ -(define (del-first-column m) (map cdr m)) -\end{lstlisting} -\end{frame} - -\begin{frame}<\switch{matrices}>[fragile] - \frametitle{Разширени операции} - - Намиране на ред и стълб по индекс - \pause - \onslide<+-> -\begin{lstlisting} -(define @\alt<+->{get-row list-ref)}{(get-row m i) (list-ref m i))}@ -(define (get-column m i) - (map (lambda (row) (list-ref row i)) m)) -\end{lstlisting} - \pause - Транспониране\\ - \pause - \onslide<+-> - \textbf{Вариант 1 (директна рекурсия):} -\begin{lstlisting} -(define (transpose m) - (if (null? (get-first-row m)) '() - (cons (get-first-column m) - (transpose (del-first-column m))))) -\end{lstlisting} - \onslide<+-> - - \textbf{Вариант 2 (\tt{accumulate}):} - \begin{overprint} -\begin{lstlisting} -(define (transpose m) - (accumulate @\rvl{cons} \rvl{'()} \rvl0 \rvl{(- (get-columns m) 1)}@ @\rvl{(lambda (i) (get-column m i))} \rvl{1+}@)) -\end{lstlisting} - \end{overprint} -\end{frame} - -\begin{frame}<\switch{matrices}>[fragile] - \frametitle{Аритметични операции} - - Събиране на матрици - \pause -\begin{lstlisting} -(define (+vectors v1 v2) (map + v1 v2)) -(define (+matrices m1 m2) (map +vectors m1 m2)) -\end{lstlisting} - \pause - \vspace{2ex} - Умножение на матрици \pause - ($c_{i,j} = \vec a_i\cdot \vec b^T_j = \sum_{k=0}^n A_{i,k}B_{k,j}$) - \pause - \small -\begin{lstlisting} -(define (*vectors v1 v2) (apply + (map * v1 v2)))@\pause@ -(define (*matrices m1 m2) - (let ((m2t (transpose m2))) - (map (lambda (row) - (map (lambda (column) (*vectors row column)) - m2t)) - m1))) -\end{lstlisting} -\end{frame} - -\section{Абстракция със структури от данни} - -\subsection{Нива на абстракция} - -\begin{frame}[<+->] - \frametitle{Абстракция със структури от данни} - - \begin{definition}[Абстракция] - Принцип за разделянето („абстрахирането“) на \emph{представянето} на дадена структура от данни (СД) от нейното \emph{използване}. - \end{definition} - \begin{itemize} - \item основен принцип на обектно-ориентираното програмиране - \item позволява използването на СД преди представянето ѝ да е уточнено - \item предимства: - \begin{itemize} - \item програмите работят на по-високо концептуално ниво със СД - \item позволява алтернативни имплементации на дадена СД, подходящи за различни видове задачи - \item влиянието на промени по представянето е ограничено до операциите, които „знаят“ за него - \item подобрения при представянето автоматично се разпространяват до по-горните нива на абстракция - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[<+->] - \frametitle{Пример: рационално число} - - \begin{itemize} - \item Логическо описание: обикновена дроб - \item Физическо представяне: наредена двойка от цели числа - \item Базови операции: - \begin{itemize}[<.->] - \item конструиране на рационално число - \item получаване на числител - \item получаване на знаменател - \end{itemize} - \item Аритметични операции: - \begin{itemize}[<.->] - \item събиране, изваждане - \item умножение, деление - \item сравнение - \end{itemize} - \item Приложни програми - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Нива на абстракция} - - \begin{center} - \begin{tikzpicture} - \graph[nodes={ - draw, - minimum width=24em, - minimum height=5ex, - align=center}, - edges={thick,>=stealth}, - grow up sep=4ex] { - a[as={физическо представяне\\(наредена двойка от цели числа)}] -> - b[as={базови операции\\(конструктор, селектори за числител и знаменател)}] -> - c[as={аритметични операции\\(\tt{+}, \tt{-}, \tt{*}, \tt{/}, \tt{=}, \tt{<}, \tt{>}, \tt{<=}, \tt{>=})}] -> - d[as={приложни програми}] - }; - \end{tikzpicture} - \end{center} -\end{frame} - -\subsection{Абстракция с наредени двойки} - -\begin{frame}[fragile] - \frametitle{Рационални числа} - - Физическо представяне\\[2ex] - \begin{center} - \small - \begin{tikzpicture} - \pointcellxx[nodes={minimum width=8em}] a{\text{числител}}{\text{знаменател}} - \end{tikzpicture} - \end{center} - \pause - Базови операции - \begin{itemize}[<+->] - \item \alt<+->{\lst{(define make-rat cons)}}{\lst{(define (make-rat n d) (cons n d))}} - \item \alt<+->{\lst{(define get-numer car)}}{\lst{(define (get-numer r) (car r))}} - \item \alt<+->{\lst{(define get-denom cdr)}}{\lst{(define (get-denom r) (cdr r))}} - \end{itemize} - \onslide<+-> - \vspace{2ex} - По-добре: -\begin{lstlisting} -(define (make-rat n d) - (if (= d 0) (cons n 1) (cons n d))) -\end{lstlisting} -\end{frame} - -\begin{frame}<1-3>[label=ratarith,fragile] - \frametitle{Аритметични операции} - - \sizeboth\footnotesize - \begin{columns}[T,onlytextwidth] - \begin{column}{0.34\textwidth} - \vspace{4ex} - \begin{equation*} - \frac{n_1}{d_1}\frac{n_2}{d_2} = \frac{n_1n_2}{d_1d_2} - \end{equation*} - \vspace{8ex} - \begin{uncoverenv}<2-> - \begin{equation*} - \frac{n_1}{d_1} + \frac{n_2}{d_2} = \frac{n_1d_2 + n_2d_1}{d_1d_2} - \end{equation*} - \end{uncoverenv} - \vspace{8ex} - \begin{uncoverenv}<3-> - \begin{equation*} - \frac{n_1}{d_1} < \frac{n_2}{d_2} \alt<3>{\leftrightarrow}{\alert{\nleftrightarrow}} n_1d_2 < n_2d_1 - \end{equation*} - \end{uncoverenv} - \end{column} - - \begin{column}{0.66\textwidth} -\begin{lstlisting} -(define (*rat p q) - (make-rat - (* (get-numer p) (get-numer q)) - (* (get-denom p) (get-denom q)))) -\end{lstlisting} - \begin{uncoverenv}<2-> -\begin{lstlisting} -(define (+rat p q) - (make-rat - (+ (* (get-numer p) - (get-denom q)) - (* (get-denom p) - (get-numer q))) - (* (get-denom p) (get-denom q)))) -\end{lstlisting} - \end{uncoverenv} - \begin{uncoverenv}<3-> -\begin{lstlisting} -(define ( - - \begin{overprint} -\begin{semiverbatim} -(define (my-exp x n) - (accumulate - \rvl{+rat} \rvl{(make-rat 0 1)} 0 n - \rvl{(lambda (i) (make-rat (pow x i) (fact i)))} 1+)) -\end{semiverbatim} - \end{overprint} -\end{frame} - -\begin{frame}<1-2>[label=ratnorm,fragile] - \frametitle{Нормализация} - - \textbf{Проблем:} Числителят и знаменателят стават много големи!\\[2ex] - \pause - \textbf{Проблем:} \evalsto{( dg 0) (cons ng dg) - (cons (- ng) (- dg)))))) -\end{lstlisting} - \pause - \alert{Не е нужно да правим каквито и да е други промени!} -\end{frame} - -\againframe<4>{ratarith} - -\againframe<3->{ratnorm} - -\subsection{Абстракция със сигнатура} - -\begin{frame}[fragile] - \frametitle{Сигнатура} - - \sizeboth\footnotesize - \textbf{Проблем:} Не можем да различим СД с еднакви представяния! (рационално число, комплексно число, точка в равнината)\\ - \pause - \textbf{Идея:} Да добавим „етикет“ на обекта - \begin{center} - \begin{tikzpicture} - \pointcellx a{\texttt{rat}} - \nextcellxx[nodes={minimum width=8em}] b{\text{числител}}{\text{знаменател}}a - \end{tikzpicture} - \end{center} - \pause - \vspace{-.5ex} -\begin{lstlisting} -(define (make-rat n d) - @\alert{(cons 'rat}@ - (if (or (= d 0) (= n 0)) (cons 0 1) - (let* ((g (gcd n d)) - (ng (quotient n g)) - (dg (quotient d g))) - (if (> dg 0) (cons ng dg) - (cons (- ng) (- dg))))))) -(define get-numer @\alert{cadr}@) -(define get-denom @\alert{cddr}@) -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Проверка за коректност} - - Вече можем да проверим дали даден обект е рационално число: -\begin{lstlisting} -(define (rat? p) - (and (pair? p) (eqv? (car p) 'rat) - (pair? (cdr p)) - (integer? (cadr p)) (positive? (cddr p)) - (= (gcd (cadr p) (cddr p)) 1))) -\end{lstlisting} - \pause - Можем да добавим проверка за коректност: -\begin{lstlisting} -(define (check-rat f) - (lambda (p) - (if (rat? p) (f p) 'error))) - -(define get-numer (check-rat cadr)) -(define get-denom (check-rat cddr)) -\end{lstlisting} -\end{frame} - -\subsection{Капсулация} - -\begin{frame}<\switch{encapsulation}>[fragile] - \frametitle{Капсулация на базови операции} - - \textbf{Проблем:} операциите над СД са видими глобално\\[2ex] - \pause - \textbf{Идея:} да ги направим „private“ - \pause -\begin{lstlisting} -(define (make-rat n d) - (lambda (prop) - (case prop - ('get-numer n) - ('get-denom d) - ('print (cons n d)) - (else 'unknown-prop)))) -\end{lstlisting} - \pause - \begin{itemize} - \item \lst{(define r (make-rat 3 5))} - \item \evalsto{(r 'get-numer)}3 - \item \evalsto{(r 'get-denom)}5 - \item \evalsto{(r 'print)}{(3 . 5)} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{encapsulation}>[fragile] - \frametitle{Нормализация при капсулация} - -\sizeboth\small -\begin{lstlisting} -(define (make-rat n d) - @\alert{(let* ((d (if (= 0 d) 1 d))}@ - @\alert{(sign (if (> 0 d) 1 -1))}@ - @\alert{(g (gcd n d))}@ - @\alert{(numer (* sign (quotient n g)))}@ - @\alert{(denom (* sign (quotient d g))))}@ - (lambda (prop) - (case prop - ('get-numer numer) - ('get-denom denom) - ('print (cons numer denom)) - (else 'unknown-prop)))) -\end{lstlisting} - \pause - \begin{itemize} - \item \lst{(define r (make-rat 4 6))} - \item \evalsto{(r 'print)}{(2 . 3)} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{encapsulation}>[fragile] - \frametitle{Капсулация на операции с аргументи} - -\sizeboth\footnotesize -\begin{lstlisting} -(define (make-rat n d) - (let* ((g (gcd n d)) - (d (if (= 0 d) 1 d)) - (sign (if (> 0 d) 1 -1)) - (numer (* sign (quotient n g))) - (denom (* sign (quotient d g)))) - (lambda (prop . params) - (case prop - ('get-numer numer) - ('get-denom denom) - ('print (cons numer denom)) - @\alert{('* (let ((r (car params))) (make-rat (* numer (r 'get-numer))}@ - @\alert{(* denom (r 'get-denom)))))}@ - (else 'unknown-prop)))) -\end{lstlisting} -\vspace*{-.5ex} - \pause - \begin{itemize} - \item \lst{(define r1 (make-rat 3 5))} - \item \lst{(define r2 (make-rat 5 2))} - \item \evalsto{((r1 '* r2) 'print)}{(3 . 2)} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{encapsulation}>[fragile] - \frametitle{Извикване на собствени операции} - -\sizeboth\footnotesize -\begin{lstlisting} -(define (make-rat n d) - (let* ((g (gcd n d)) - (d (if (= 0 d) 1 d)) - (sign (if (> 0 d) 1 -1)) - (numer (* sign (quotient n g))) - (denom (* sign (quotient d g)))) - @\alert{(define (self prop . params)}@ - (case prop - ('get-numer numer) - ('get-denom denom) - ('print (cons numer denom)) - ('* (let ((r (car params))) - (make-rat (* @\alert{(self 'get-numer)}@ (r 'get-numer)) - (* @\alert{(self 'get-denom)}@ (r 'get-denom))))) - (else 'unknown-prop))) - @\alert{self}@)) -\end{lstlisting} - \pause - Извикването на метод на обект чрез препратка \tt{self} или \tt{this} се нарича \alert{отворена рекурсия}. -\end{frame} - -\section{Асоциативни списъци} - -\subsection{Дефиниция} - -\begin{frame} - \frametitle{Асоциативни списъци} - - \begin{definition} - Асоциативните списъци (още: речник, хеш, map) са списъци от наредени двойки \tt(<ключ> \tt. <стойност>\tt). <ключ> и <стойност> може да са произволни S-изрази. - \end{definition} - \vspace{2ex} - \tt{((}$K_1$ \tt. $V_1$\tt) \tt($K_1$ \tt. $V_2$\tt) \ldots \tt($K_n$ \tt. $V_n$\tt{))}\\[2ex] - \begin{tikzpicture} - \pointcell{a1} - \nextcell{a2}{a1} - \nextdots{a2} - \dotsnextcell{an} - \nullptr{annext} - - \pointcellxx[below=2ex of a1]{kv1}{K_1}{V_1} - \draw[ptr] (a1data) to (kv1data); - - \pointcellxx[below=2ex of a2]{kv2}{K_2}{V_2} - \draw[ptr] (a2data) to (kv2data); - - \pointcellxx[below=2ex of an]{kvn}{K_n}{V_n} - \draw[ptr] (andata) to (kvndata); - \end{tikzpicture} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Примери за асоциативни списъци} - - \begin{itemize}[<+->] - \item \tt{((1 . 2) (2 . 3) (3 . 4))} - \item \tt{((a . 10) (b . 12) (c . 18))} - \item \tt{((l1 1 8) (l2 10 1 2) (l3))} - \item \tt{((al1 (1 . 2) (2 . 3)) (al2 (b)) (al3 (a . b) (c . d)))} - \end{itemize} - \vspace{2ex} - \onslide<+-> - \textbf{Пример:} - Създаване на асоциативен списък по списък от ключове и функция: -\begin{lstlisting} -(define (make-alist f keys) - (map (lambda (x) (cons x (f x))) keys)) -\end{lstlisting} - \onslide<+-> - \evalsto{(make-alist square '(1 3 5))}{((1 . 1) (3 . 9) (5 . 25))} -\end{frame} - -\subsection{Операции} - -\begin{frame}[fragile] - \frametitle{Селектори за асоциативни списъци} - - \begin{itemize}[<+->] - \item \lst{(define (keys alist) (map car alist))} - \item \lst{(define (values alist) (map cdr alist))} - \item \tta{(assoc} <ключ> <асоциативен-списък>\tta) - \begin{itemize}[<.->] - \item Ако <ключ> се среща сред ключовете на <асоциативен-списък>, - връща първата двойка \tt(<ключ> \tt. <стойност>\tt) - \item Ако <ключ> не се среща сред ключовете, връща \tt{\#f} - \item Сравнението се извършва с \tt{equal?} - \end{itemize} - \item \tta{(assv} <ключ> <асоциативен-списък>\tta) - \begin{itemize}[<.->] - \item също като \tt{assoc}, но сравнява с \tt{eqv?} - \end{itemize} - \item \tta{(assq} <ключ> <асоциативен-списък>\tta) - \begin{itemize}[<.->] - \item също като \tt{assoc}, но сравнява с \tt{eq?} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Трансформации над асоциативни списъци} - - \begin{itemize}[<+->] - \item Изтриване на ключ и съответната му стойност (ако съществува):\\ - \onslide<+-> -\begin{lstlisting} -(define (del-assoc key alist) - (filter (lambda (kv) (not (equal? (car kv) key))) alist)) -\end{lstlisting} - \item Задаване на стойност за ключ (изтривайки старата, ако има такава):\\ - \onslide<+-> -\begin{lstlisting} -(define (add-assoc key value alist) - (cons (cons key value) (del-assoc key alist))) -\end{lstlisting} - \ifbool{altaddassoc}{ - \begin{itemize} - \item А ако искаме да запазим реда на ключовете? - \end{itemize}}{} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{altaddassoc}>[fragile] - \frametitle{Задаване на стойност за ключ} -\small - \textbf{Вариант №1 (грозен и по-бърз):} -\begin{lstlisting} -(define (add-assoc key value alist) - (let ((new-kv (cons key value))) - (cond ((null? alist) (list new-kv)) - ((eqv? (caar alist) key) (cons new-kv (cdr alist))) - (else (cons (car alist) - (add-assoc key value (cdr alist)))))) -\end{lstlisting} - \pause - \textbf{Вариант №2 (красив и по-бавен):} -\begin{lstlisting} -(define (add-assoc key value alist) - (let ((new-kv (cons key value))) - (if (assv key alist) - (map (lambda (kv) (if (eq? (car kv) key) - new-kv kv)) alist) - (cons new-kv alist)))) -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Задачи за съществуване} - - \textbf{Задача.} Да се намери има ли елемент на l, който удовлетворява p.\\ - \pause - \textbf{Формула:} $\exists x\in l: p(x)$\\ - \pause - \textbf{Решение:} -\begin{lstlisting} -(define (search p l) - (and (not (null? l)) - (or (p (car l)) (search p (cdr l))))) -\end{lstlisting} - \pause - \alert{Важно свойство:} Ако \tt p връща „свидетел“ на истинността на свойството $p$ (както например \tt{memv} или \tt{assv}), то \tt{search} също връща този „свидетел“.\\ - \pause - \textbf{Пример:} -\begin{lstlisting} -(define (assv key al) - (search (lambda (kv) (and (eqv? (car kv) key) kv)) al)) -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Задачи за всяко} - \textbf{Задача.} Всеки елемент на l да се трансформира по дадено правило f.\\ - \pause - \textbf{Формула:} $\{f(x)\,|\,x \in l \}$\\ - \pause - \textbf{Решение:} \lst{(map f l)}\\[2ex] - \pause - \textbf{Задача.} Да се изберат тези елементи от l, които удовлетворяват p.\\ - \pause - \textbf{Формула:} $\{x\,|\,x \in l \wedge p(x) \}$\\ - \pause - \textbf{Решение:} \lst{(filter p l)}\\[2ex] - \pause - \textbf{Задача.} Да се провери дали всички елементи на l удовлетворяват p.\\ - \pause - \textbf{Формула:} $\forall x\in l:\,p(x)$ \pause $\leftrightarrow \neg \exists x\in l:\,\neg p(x)$\\ - \pause - \textbf{Решение:} -\begin{lstlisting} -(define (all? p? l) - (not (search (lambda (x) (not (p? x))) l))) -\end{lstlisting} -\end{frame} -\section{Двоични дървета} - -\subsection{Представяне} - -\begin{frame}[fragile] - \frametitle{Представяне на двоични дървета} - - Представяме двоични дървета като вложени списъци от три елемента:\\[2ex] - \begin{columns}[t,onlytextwidth] - \begin{column}{0.5\textwidth} - \centering - \begin{forest} baseline - [корен [ляво] [дясно]] - \end{forest} - \end{column} - \begin{column}{0.5\textwidth} - \tt(<корен> <ляво> <дясно>\tt) - \end{column} - \end{columns} - \pause - \vspace{2ex} - Пример: - \begin{columns}[t,onlytextwidth] - \begin{column}{0.5\textwidth} - \centering - \begin{forest} baseline, for tree={circle,draw} - [1 [2] [3 [4] [5]]] - \end{forest} - \end{column} - \begin{column}{0.5\textwidth} -\begin{verbatim} -(1 (2 () ()) - (3 (4 () ()) - (5 () ()))) -\end{verbatim} - \end{column} - \end{columns} -\end{frame} - -\subsection{Операции} - -\begin{frame}[fragile] - \frametitle{Базови операции} - - Проверка за коректност: - \pause -\begin{lstlisting} -(define (tree? t) - (or (null? t) - (and (list t) (= (length t) 3)) - (tree? (cadr t)) - (tree? (caddr t)))) -\end{lstlisting} - \pause - Конструктори: - \pause -\begin{lstlisting} -(define empty-tree '()) -(define (make-tree root left right) (list root left right)) -\end{lstlisting} - \pause - Селектори: - \pause -\begin{lstlisting} -(define root-tree car) -(define left-tree cadr) -(define right-tree caddr) -(define empty-tree? null?) -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Разширени операции} - - Дълбочина на дърво: - \pause -\begin{lstlisting} -(define (depth-tree t) - (if (empty-tree? t) 0 - (1+ (max (depth (left-tree t)) - (depth (right-tree t)))))) -\end{lstlisting} - \pause - Намиране на поддърво: - \pause - - \begin{fixedarea}[.4] - \begin{onlyenv}<4 |trans:0> -\begin{lstlisting} -(define (memv-tree x t) - (cond ((empty-tree? t) #f) - ((eqv? x (root-tree t)) t) - (else (or (memv-tree x (left-tree t)) - (memv-tree x (right-tree t)))))) -\end{lstlisting} - \end{onlyenv} - \begin{onlyenv}<5-> -\begin{lstlisting} -(define (memv-tree x t) - (and (not (empty-tree? t)) - (or (and (eqv? x (root-tree t)) t) - (memv-tree x (left-tree t)) - (memv-tree x (right-tree t))))) -\end{lstlisting} - \end{onlyenv} - \end{fixedarea} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Търсене на път в двоично дърво} - - \textbf{Задача:} Да се намери в дървото път от корена до даден възел \tt x. - \pause - \begin{fixedarea}[.7] - \begin{onlyenv}<2 |trans:0> -\begin{lstlisting} -(define (path-tree x t) - (cond ((empty-tree? t) #f) - ((eqv? x (root-tree t)) (list x)) - (else (cons#f (root-tree t) - (or (path-tree x (left-tree t)) - (path-tree x (right-tree t))))))) - -(define (cons#f h t) (and t (cons h t))) -\end{lstlisting} - \end{onlyenv} - \begin{onlyenv}<3-> -\begin{lstlisting} -(define (path-tree x t) - (and (not (empty-tree? t)) - (or (and (eqv? x (root-tree t)) (list x)) - (cons#f (root-tree t) - (or (path-tree x (left-tree t)) - (path-tree x (right-tree t))))))) - -(define (cons#f h t) (and t (cons h t))) -\end{lstlisting} - \end{onlyenv} -\end{fixedarea} -\end{frame} - -\section{Дълбоки списъци} - -\begin{frame}<\switch{deeplists}>[fragile] - \frametitle{Работа с дълбоки списъци} - -% TODO диаграма на списъка с наредени двойки -\begin{verbatim} -((1 (2)) (((3) 4) (5 (6)) () (7)) 8) -\end{verbatim} - \textbf{Задача.} Да се преброят в атомите в дълбок списък.\\ - \textbf{Подход:} Обхождане в две посоки: хоризонтално и вертикално - \pause - \begin{itemize}[<+->] - \item \hzero{Хоризонтално дъно:} \rvl{достигане до празен списък \tt{()}} - \item \vzero{Вертикално дъно:} \rvl{достигане до друг атом} - \item \hstep{Хоризонтална стъпка:} \rvl{обхождане на опашката \tt{(cdr l)}} - \item \vstep{Вертикална стъпка:} \rvl{обхождане на главата \tt{(car l)}} - \end{itemize} - \vspace{2ex} - \onslide<+-> - За удобство можем да дефинираме функцията \tt{atom?}: -\begin{lstlisting} -(define (atom? x) (and (not (null? x)) (not (pair? x)))) -\end{lstlisting} -\end{frame} - -\begin{frame}<\switch{deeplists}>[fragile] - \frametitle{Примери} - \small - \textbf{Задача.} Да се преброят в атомите в дълбок списък.\\ - \evalsto{(count-atoms '((1 (2)) (((3) 4) (5 (6)) () (7)) 8))}8 - \pause -\begin{lstlisting} -(define (count-atoms l) - (cond ((null? l) @\hzero0@) - ((atom? l) @\vzero1@) - (else (+ @\vstep{(count-atoms (car l))} \hstep{(count-atoms (cdr l))}@)))) -\end{lstlisting} -\vspace{2ex} - \pause - \textbf{Задача.} Да се съберат всички атоми от дълбок списък.\\ - \evalsto{(flatten '((1 (2)) (((3) 4) (5 (6)) () (7)) 8))}{(1 2 3 4 5 6 7 8)} - \pause -\begin{lstlisting} -(define (flatten l) - (cond ((null? l) @\hzero{'()}@) - ((atom? l) @\vzero{(list l)}@) - (else (append @\vstep{(flatten (car l))} \hstep{(flatten (cdr l))}@)))) -\end{lstlisting} -\end{frame} - -\begin{frame}<\switch{deeplists}>[fragile] - \frametitle{Примери} - - \textbf{Задача.} Да се обърне редът на атомите в дълбок списък.\\ - \evalsto{(deep-reverse '((1 (2)) (((3) 4) (5 (6)) () (7)) 8))}{(8 ((7) () ((6) 5) (4 (3))) ((2) 1))} - \pause -\begin{lstlisting} -(define (deep-reverse l) - (cond ((null? l) @\hzero{'()}@) - ((atom? l) @\vzero{l}@) - (else (append @\hstep{(deep-reverse (cdr l))}@ - @\vstep{(list (deep-reverse (car l)))}@)))) -\end{lstlisting} -\end{frame} - -% TODO: диаграма на дълбок списък без наредени двойки -\begin{frame}<\switch{deeplists}>[fragile] - \frametitle{Свиване на дълбоки списъци} - - \tt{(deep-foldr }<х-дъно> <в-дъно> <операция> <списък>\tt)\\ - \pause - \onslide<+-> -\begin{lstlisting} -(define (deep-foldr op term nv l) - (cond ((null? l) @\hzero{nv}@) - ((atom? l) @\vzero{(term l)}@) - (else (op @\vstep{(deep-foldr op term nv (car l))}@ - @\hstep{(deep-foldr op term nv (cdr l))}@)))) -\end{lstlisting} - \onslide<+-> -\begin{lstlisting} -(define (count-atoms l) (deep-foldr @\rvl+ \rvl{(lambda (x) 1)} \rvl0@ l)) -\end{lstlisting} - \onslide<+-> -\begin{lstlisting} -(define (flatten l) (deep-foldr @\rvl{append} \rvl{list} \rvl{'()}@ l)) -\end{lstlisting} - \onslide<+-> - \begin{visibleenv}<12-> -\begin{lstlisting} -(define (snoc x l) (append l (list x)))\end{lstlisting}% - \end{visibleenv}% -\begin{lstlisting} -(define (deep-reverse l) (deep-foldr @\rvl{snoc} \rvl{id} \rvl{'()}@ l)) -\end{lstlisting} -\end{frame} - -\begin{frame}<\switch{deeplists}>[fragile] - \frametitle{Директна реализация на \tt{deep-foldr}} - - Как работи \tt{deep-foldr}? - \pause - \begin{itemize}[<+->] - \item пуска себе си рекурсивно за всеки елемент на дълбокия списък - \item при достигане на вертикално дъно (атоми) прилага \tt{term} - \item и събира резултатите с \tt{op} - \end{itemize} - \onslide<+-> - Можем да реализираме \tt{deep-foldr} чрез \tt{map} и \tt{foldr}! - \onslide<+-> -\begin{lstlisting} -(define (branch p? f g) (lambda (x) (p? x) (f x) (g x))) -(define (deep-foldr op term nv l) - (foldr @\hstep{op} \hzero{nv}@ - (map (branch atom? - @\vzero{term}@ - @\vstep{(lambda (l) (deep-foldr op term nv l))}@ - l))) -\end{lstlisting} - \onslide<+-> - \textbf{Задача.} Реализирайте функция за ляво свиване на дълбоки списъци \tt{deep-foldl}. -\end{frame} - -\section{Графи} - -\subsection{Представяне} - -\begin{frame}<\switch{graphs}>[fragile] - \frametitle{Представяне на графи чрез асоциативни списъци} - - \begin{columns}[t,onlytextwidth] - \begin{column}{0.7\textwidth} - \begin{center} - \samplegraph - \end{center} - \end{column} - \begin{column}{0.3\textwidth} -\begin{semiverbatim} -\alt<2>{((1 2 3) - (2 3) - (3 4 5) - (4) - (5 2 4 6) - (6 2))}{((1 . (2 3)) - (2 . (3)) - (3 . (4 5)) - (4 . ()) - (5 . (2 4 6)) - (6 . (2)))} - \end{semiverbatim} - \end{column} - \end{columns} - \vspace{2ex} - Асоциативен списък, в който \alert{ключовете} са върховете, а \alert{стойностите} са списъци от техните деца. -\end{frame} - -\begin{frame}<\switch{graphs}>[fragile] - \frametitle{Абстракция за граф} - -\begin{lstlisting} -(define @\alt<2>{vertices keys)}{(vertices g) (keys g))}@ - -(define (children v g) @\alert{\(\{u|u\leftarrow{}v\}\)}@ - (cdr (assv v g)))) - -(define (edge? u v g) @\alert{\(u\stackrel?\rightarrow{}v\)}@ - (memv v (children u g))) - -(define (map-children v f g) @\alert{\(\forall{}u\leftarrow{}v\)}@ - (map f (children v g))) - -(define (search-child v f g) @\alert{\(\exists{}u\leftarrow{}v\)}@ - (search f (children v g))) -\end{lstlisting} -\end{frame} - -\begin{frame}<\switch{graphs}>[fragile] - \frametitle{Абстракция за граф} - - \sizeboth\footnotesize - Абстракция чрез капсулация - \vspace{-.3ex} -\begin{lstlisting} -(define (make-graph g) - (define (self prop . params) - (case prop - ('print g) - ('vertices (keys g)) - ('children (let ((v (car params))) - (cdr (assv v g)))) @\alert{\(\{u|u\leftarrow{}v\}\)}@ - ('edge? (let ((u (car params)) (v (cadr params))) - (memv v (self 'children u)))) @\alert{\(u\stackrel?\rightarrow{}v\)}@ - ('map-children (let ((v (car params)) - (f (cadr params))) @\alert{\(\forall{}u\leftarrow{}v\)}@ - (map f (self 'children v)))) - ('search-child (let ((v (car params)) - (f (cadr params))) @\alert{\(\exists{}u\leftarrow{}v\)}@ - (search f (self 'children v)))))) - self) -\end{lstlisting} -\end{frame} - -\subsection{Задачи} - -\begin{frame}<\switch{graphs}>[fragile] - \frametitle{Локални задачи} - - \small - \textbf{Задача. }Да се намерят върховете, които нямат деца.\\ - \pause - \textbf{Решение. }\tt{childless(g)} $ = \{v\;|\;\nexists u \leftarrow v \}$ - \pause -\begin{lstlisting} -(define (childless g) - (filter (lambda (v) (null? (children v g))) (vertices g))) -\end{lstlisting} - \pause - \vspace{2ex} - \textbf{Задача. }Да се намерят родителите на даден връх.\\ - \pause - \textbf{Решение. }\tt{parents(v, g)} $ = \{u\;|\;u \rightarrow v \}$ - \pause -\begin{lstlisting} -(define (parents v g) - (filter (lambda (u) (edge? u v g)) (vertices g))) -\end{lstlisting} -\end{frame} - -\begin{frame}<\switch{graphs}>[fragile] - \frametitle{Проверка за симетричност} - \textbf{Задача. }Да се провери дали граф е симетричен.\\ - \pause - \textbf{Решение. }\tt{symmetric?(g)} $ = \forall u\forall v\leftarrow u: v\rightarrow u$ - \pause -\begin{lstlisting} -(define (symmetric? g) - (all? (lambda (u) - (all? (lambda (v) (edge? v u g)) - (children u g))) - (vertices g))) -\end{lstlisting} -\end{frame} - -\subsection{Обхождане в дълбочина} - -\begin{frame}<\switch{graphs}>[fragile] - \frametitle{Схема на обхождане в дълбочина} - - Обхождане на връх \tt u: - \begin{itemize} - \item Обходи последователно всички деца \tt v на \tt u - \end{itemize} - \pause -{\small -\begin{lstlisting} -(define (dfs u g) - (@<функция-за-обработка>@ (lambda (v) (@<действие>@ (dfs v g))) - (children u g))) -\end{lstlisting} -} - \pause - \begin{itemize}[<+->] - \item \alert{Имаме ли дъно?} - \begin{itemize} - \item Да: при празен списък от деца няма рекурсивно извикване! - \end{itemize} - \item \alert{Какво се случва ако графът е цикличен?} - \begin{itemize} - \item Програмата също зацикля! Как да се справим с този проблем? - \item Трябва да помним през кои върхове сме минали! - \item Два варианта: - \begin{enumerate} - \item да помним всички обходени до момента върхове - \item<+- | alert@+(1)> да помним текущия път - \end{enumerate} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{graphs}>[fragile] - \frametitle{Търсене на път в дълбочина} - - \sizeboth\small - \begin{columns} - \begin{column}{.75\textwidth} - \textbf{Задача.} Да се намери път от \tt u до \tt v, ако такъв има.\\ - \pause\onslide<+-> - \textbf{Решение.} Има път от \tt u до \tt v, ако:\\[-1ex] - \begin{itemize} - \setlength{\itemsep}{0pt} - \item \tt u = \tt v, или - \item има дете \tt w $\leftarrow$ \tt u, така че има път от \tt w до \tt v - \end{itemize} - \end{column} - \begin{column}{.25\textwidth} - \samplegraph[.8] - \end{column} - \end{columns} - \vspace{-4ex} - \onslide<+-> - \begin{fixedarea}[.51] - \begin{onlyenv}<6-> -\begin{lstlisting} -(define (dfs-path u v g) - (define (dfs-search path) - (let ((current (car path))) - (cond ((eqv? current v) (reverse path)) - ((memv current (cdr path)) #f) - (else (search-child current - (lambda (w) (dfs-search (cons w path))) g)))) - (dfs-search (list u))) -\end{lstlisting} - \end{onlyenv} - \begin{onlyenv}<-5 |trans:0> -\begin{lstlisting} -(define (dfs-path u v g) - (if (eqv? u v) (list u) - (search-child u (lambda (w) - (cons#f u (dfs-path w v g))) g))) -\end{lstlisting} - \end{onlyenv} - \end{fixedarea} - \onslide<+-> - \alert{Директно рекурсивно решение, работи само за ацикличен граф!}\\ - \onslide<+-> - Итеративното натрупване на пътя позволява да правим проверки за цикъл. -\end{frame} - -\subsection{Търсене в ширина} - -\begin{frame}<\switch{graphs}>[fragile] - \frametitle{Схема на обхождане в ширина} - \begin{onlyenv}<1-2| trans:1> - Обхождане, започващо от връх \tt u: - \begin{itemize} - \item Маркира се \tt u за обхождане на ниво 1 - \item За всеки връх \tt v избран за обхождане на ниво $n$: - \begin{itemize} - \item Маркират се всички деца \tt w на \tt v за обхождане на - ниво $n+1$ - \end{itemize} - \end{itemize} - \end{onlyenv}% - \begin{visibleenv}<2-| trans:1-2>% - \small% -\begin{lstlisting} -(define (bfs u g) - (define (bfs-level l) - (if (null? l) @<дъно>@ - (bfs-level - (@<функция-за-обработка>@ (lambda (v) (children v g)) - l)))) - (bfs-level (list u))) -\end{lstlisting} - \end{visibleenv} - \begin{onlyenv}<3- | trans:2-3> - \begin{fixedarea}[.45] - \begin{onlyenv}<4-8| trans:3> - \begin{center} - \samplegraph \hspace{5em} - \onslide<5-> - \scriptsize - \begin{forest} - for tree={graphnode,edge=-Stealth} - [1 - [2,visible on=<6-> - [3,visible on=<7-> - [4,visible on=<8->] - [5,visible on=<8->]]] - [3,visible on=<6-> - [4,visible on=<7->] - [5,visible on=<7-> - [2,visible on=<8->] - [4,visible on=<8->] - [6,visible on=<8->]]]] - \end{forest} - \end{center} - \end{onlyenv} - \begin{onlyenv}<9-| trans:2> - \begin{itemize}[<+(8)->] - \item \alert{Какво се случва ако графът е цикличен?} - \begin{itemize} - \item Ако има път: намира го. - \item Ако няма път: програмата зацикля! Как да се справим с този проблем? - \item Трябва да помним през кои върхове сме минали! - \item Нивото трябва да представлява \alert{списък от пътища} - \end{itemize} - \end{itemize} - \end{onlyenv} - \end{fixedarea} - \end{onlyenv} -\end{frame} - -\begin{frame}<\switch{graphs}>[fragile] - \frametitle{Разширяване на пътища} - - Удобно е пътищата да са представени като \alert{стек} - \begin{itemize} - \item последно посетеният възел е най-лесно достъпен - \end{itemize} - \pause - \begin{columns}[T] - \begin{column}{0.65\textwidth} - \evalsto{(extend '(3 1))}{((4 3 1) (5 3 1))} - \pause -\begin{lstlisting} -(define (extend path) - (map-children (car path) - (lambda (w) (cons w path)) g)) -\end{lstlisting} - \pause - Трябва да филтрираме циклите: - \pause -\begin{lstlisting} -(define (remains-acyclic? path) - (not (memv (car path) (cdr path)))) - -(define (extend-acyclic path) - (filter remains-acyclic? (extend path)) -\end{lstlisting} - \end{column} - \begin{column}{0.35\textwidth} - \onslide<2-> - \samplegraph - \end{column} - \end{columns} -\end{frame} - -\begin{frame}<\switch{graphs}>[fragile] - \frametitle{Търсене на път в ширина} - - \sizeboth\footnotesize - \textbf{Задача.} Да се намери \alert{най-краткият} път от \tt u до \tt v, ако такъв има.\\ - \pause - \textbf{Решение.} Обхождаме в ширина от \tt u докато намерим ниво, в което има път, завършващ във върха \tt v. - \pause -\begin{lstlisting} -(define (bfs-path u v g) - @\textcolor{black!20}{(define (extend path) ...)}@ - @\textcolor{black!20}{(define (extend-acyclic path) ...)}@ - (define (extend-level level)@\pause@ - (apply append (map extend-acyclic level)))@\pause@ - (define (target-path path)@\pause@ - (and (eqv? (car path) v) path))@\pause@ - - (define (bfs-level level)@\pause@ - (and (not (null? level)) - (or (search target-path level) - (bfs-level (extend-level level)))))@\pause@ - - (bfs-level (list (list u)))) -\end{lstlisting} -\end{frame} - -\end{document} diff --git a/1.6-scheme_mutation.tex b/1.6-scheme_mutation.tex deleted file mode 100644 index 7d60e25..0000000 --- a/1.6-scheme_mutation.tex +++ /dev/null @@ -1,97 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -\title{Мутиращи операции} - -\date{6 ноември 2024 г.} - -\lstset{language=Scheme} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\begin{frame} - \frametitle{Мутиращи операции в Scheme} - - Мутиращите операции в Scheme позволяват въвеждането на \alert{странични ефекти}.\\[4ex] - \pause - \textbf{Преглед:} - \begin{itemize}[<+->] - \item \lst{set!} --- промяна на оценка, свързана със символ - \item \lst{set-car!}, \lst{set-cdr!} --- промяна на компоненти на точкови двойки - \item \lst{begin} --- последователност от действия - \item \lst{open-input-file}, \lst{open-output-file} --- работа с файлове - \item \lst{read}, \lst{write}, \lst{display} --- вход и изход - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Промяна на оценка, свързана със символ (\tt{set!})} - - \begin{itemize}[<+->] - \item \tta{(set!} <символ> <израз>\tta) - \item Търси се <символ> във веригата от среди - \begin{itemize} - \item Ако бъде намерен, свързва се с оценката на <израз> - \item В противен случай --- \alert{грешка!} - \end{itemize} - \item Примери: - \begin{itemize} - \item \lst{(define a 2)}\hspace{3em}\evalsto{a}2 - \item \lst{(set! a 5)}\hspace{4em}\evalsto{a}5 - \item \lst{(define (sum x)}\only<-.>{\tt{ (begin }}\lst{ (set! a (+ a x)) a}\only<-.>{\tt)}\tt)\pause - \item \evalsto{(sum 10)}{15} - \item \evalsto{(sum 10)}{25} - \item \alert{губи се референциалната прозрачност!} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Пример: текуща сметка} - -\begin{lstlisting} -(define (make-account sum) - (lambda (amount) - (if (< (+ amount sum) 0) - (display "Insufficient funds!\n") - (set! sum (+ sum amount))) - sum)) -\end{lstlisting} - \onslide<+-> - \begin{itemize}[<+->] - \item \lst{(define account (make-account 100))} - \item \evalsto{(account 20)}{120} - \item \evalsto{(account -50)}{70} - \item \evalstos{\tt{(account -150)}}{ - \begin{tabular}[t]l - \tt{"Insufficient funds"}\\ - \tt{70} - \end{tabular}} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Промяна на компоненти (\tt{set-car!}, \tt{set-cdr!})} - - \begin{itemize}[<+->] - \item \tta{(set-car!} <двойка> <израз>\tta) - \item<.-> \tta{(set-cdr!} <двойка> <израз>\tta) - \item Съответният компонент на <двойка> се променя да сочи към оценката на <израз> - \item \textbf{Примери:} - \begin{itemize} - \item \lst{(define p (cons (cons 1 2) (cons 3 4)))} - \item \lst{(set-car! p 7)} - \item \evalstop{p}{(7 . (3 . 4))} - \item \lst{(set-cdr! p '(5 3))} - \item \evalstop{p}{(7 5 3)} - \item \tt{(set-cdr! (cdr p) p)} - \item \evalstop{p}{(7 5 7 5 7 5 ...)} - \end{itemize} - \end{itemize} -\end{frame} - -\end{document} diff --git a/1.7-scheme_streams.tex b/1.7-scheme_streams.tex deleted file mode 100644 index 076ecba..0000000 --- a/1.7-scheme_streams.tex +++ /dev/null @@ -1,344 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -% вариадични функции -\newboolfalse{variadic} - -\title{Потоци} - -\date{6 ноември 2024 г.} - -\lstset{language=Scheme} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section{Отложени операции} - -\begin{frame} - \frametitle{Отложени операции} - - \begin{itemize}[<+->] - \item Има случаи на тежки операции, които могат да отнемат много време за изпълнение - \item Удобно е да имаме механизъм да \alert{подготвяме} операциите и да ги \alert{изпълняваме} само при нужда - \end{itemize} - \onslide<+-> - \begin{definition}[Обещание] - Функция, която ще изчисли и върне някаква стойност в бъдещ момент от изпълнението на програмата. - \onslide<+-> - Нарича се още \emph{promise} и \emph{отложена операция}. - \end{definition} - \onslide<+-> - Изчислението на дадено обещание може да стане - \begin{itemize}[<+->] - \item паралелно с изпълнението на основната програма \textbf{(асинхронно)} - \item при поискване от основната програма \textbf{(синхронно)} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Примитивни операции \tt{force} и \tt{delay}} - - \begin{itemize}[<+->] - \item \tta{(delay} <израз>\tta) - \item връща \alert{обещание} за оценяването на <израз> \visible<5->{\alert{(специална форма)}} - \item \tta{(force} <обещание>\tta) - \item форсира изчислението на <обещание> и връща оценката на <израз> \visible<5->{\alert{(примитивна функция)}} - \pause - \item \textbf{Примери:} - \begin{itemize} - \item \lst{(define bigpromise (delay (fact 30000)))} - \item \lst{(force bigpromise)}$\;\xrightarrow{\hspace*{3cm}}\;$\tt{2759537246...} - \item \lst{(define error (delay (car '())))} - \item \evalstoerr{(force error)} - \item \lst{(define undefined (delay (+ a 3)))} - \item \lst{(define a 5)} - \item \evalstop{(force undefined)}8 - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{All you need is $\lambda$ --- \tt{force} и \tt{delay}} - - \begin{itemize} - \item \lst{(delay }<израз>\tt) \eqv \lst{(lambda () }<израз>\tt) - \item \lst{(force }<обещание>\tt) \eqv \tt(<обещание>\tt)\pause - \item \alert{Не съвсем!} \pause - \begin{itemize}[<.->] - \item \lst{(define bigpromise (delay (fact 30000)))} - \item \lst{(force bigpromise)}$\;\xrightarrow{\hspace*{3cm}}\;$\tt{2759537246...} - \item \lst{(force bigpromise)}$\;\rightarrow\;$\tt{2759537246...} \pause - \item Обещанията в Scheme имат страничен ефект: „мемоизират“ вече изчислената стойност - \end{itemize} - \end{itemize} -\end{frame} - -\section{Потоци} - -\begin{frame} - \frametitle{Потоци в Scheme} - - \begin{definition}[Поток] - Списък, чиито елементи се изчисляват отложено. \\ - \pause - По-точно: Поток е празен списък \tt{()} или двойка \tt{(h . t)}, където - \begin{itemize} - \item \tt h --- е произволен елемент (глава на потока) - \item \tt t --- е \alert{обещание} за поток (опашка на потока) - \end{itemize} - \end{definition} - \pause - В R$^5$RS няма вградени примитиви за работа с поток, но можем да си ги дефинираме. - \pause - \begin{itemize}[<+->] - \item \lst{(define the-empty-stream '())} - \item \lst{(define (cons-stream h t) (cons h (delay t)))} - \item \lst{(define head car)} - \item \lst{(define (tail s) (force (cdr s)))} - \item \lst{(define empty-stream? null?)} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Примери} - - \begin{itemize}[<+->] - \item \lst{(define s (cons-stream 1 (cons-stream 2 (cons-stream 3 the-empty-stream))))} - \item \evalsto{(head s)}1 - \item \evalsto{(tail s)}{(2 . \#)} - \item \evalsto{(head (tail s))}2 - \item \evalsto{(head (tail (tail s)))}3 - \item \evalstoerrs{\tt{(define s2 (cons-stream 3 (cons-stream b the-empty-stream)))}} - \item<+-| alert@+>Защо? - \item \tt{cons-stream} трябва да оценява \alert<.>{само първия си аргумент}! - \item \tt{cons-stream} трябва да е \alert<.>{специална форма} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Дефиниране на специални форми} - - \begin{itemize}[<+->] - \item \tta{(define-syntax} <символ>\\ - \hspace{2.5em}\tta{(syntax-rules ()} \{\tta(<шаблон> <тяло>\tta)\}\tta{))} - \item дефинира специална форма <символ> така, че всяко срещане на <шаблон> се замества с <тяло> - \item \tt{define-syntax} има и други, по-сложни форми - \item Повечето специални форми на Scheme могат да се дефинират с \tt{define-syntax} (за справка: R$^5$RS) - \end{itemize} - \onslide<+-> - \textbf{Примери:} - \onslide<+-> -\begin{lstlisting} -(define-syntax delay - (syntax-rules () ((delay x) (lambda () x)))) -\end{lstlisting} - \onslide<+-> -\begin{lstlisting} -(define-syntax cons-stream - (syntax-rules () ((cons-stream h t) (cons h (delay t))))) -\end{lstlisting} -\end{frame} - -\section{Операции над потоци} - -\begin{frame}[fragile] - \frametitle{Конструиране и деконструиране на потоци} - - \textbf{Задача.} Да се построи поток от целите числа в интервала $[a; b]$.\\ - \pause - \textbf{Решение:} -\begin{lstlisting} -(define (enum a b) - (if (> a b) the-empty-stream - (cons-stream a (enum (+ a 1) b)))) -\end{lstlisting} - \pause - \textbf{Задача.} Да се намерят първите n елемента на даден поток.\\ - \pause - \textbf{Решение:} -\begin{lstlisting} -(define (take n s) - (if (or (empty-stream? s) (= n 0)) '() - (cons (head s) (take (- n 1) (tail s))))) -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Приложение на потоци} - - \small - \textbf{Задача.} Да се намери първата позиция в поток, на която има елемент с дадено свойство.\\ - \pause - \textbf{Решение.} -\begin{lstlisting} -(define (find-stream p? s) - (cond ((empty-stream? s) #f) - ((p? (head s)) s) - (else (find-stream p? (tail s))))) -\end{lstlisting} - \pause - \textbf{Задача.} Да се намери второто по големина просто число след 10000 със сума на цифрите кратна на 5.\\ - \pause - \textbf{Решение.} -\begin{lstlisting} -(define (prime-5? n) (and (prime? n) - (= (remainder (sum-digits n) 5) 0))) -(define second-prime-5 - (head (find-stream prime-5? - (tail (find-stream prime-5? - (enum 10000 100000))))) -\end{lstlisting} -\end{frame} - -\section{Безкрайни потоци} - -\begin{frame}[fragile] - \frametitle{Безкрайни потоци} - - Отлагането на операции позволява създаването на \alert{безкрайни потоци}!\\[1em] - \pause - Примери: -\begin{lstlisting} -(define (from n) (cons-stream n (from (+ n 1)))) -(define nats (from 0)) -\end{lstlisting} - \pause - \textbf{Задача.} Да се генерира потокът от числата на Фибоначи.\\ - \pause - \textbf{Решение:} -\begin{lstlisting} -(define (generate-fibs a b) - (cons-stream a (generate-fibs b (+ a b)))) -(define fibs (generate-fibs 0 1)) -\end{lstlisting} - \pause - \begin{itemize} - \item Функциите \tt{from} и \tt{generate-fibs} наричаме \alert{генератори} - \item Казваме, че потоците \tt{nats} и \tt{fibs} са \alert{индиректно дефинирани} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Функции от по-висок ред за потоци} - - \textbf{Трансформиране (\tt{map})} -\begin{lstlisting} -(define (map-stream f s) (cons-stream (f (head s)) - (map-stream f (tail s)))) -\end{lstlisting} - \pause - \textbf{Филтриране (\tt{filter})} -\begin{lstlisting} -(define (filter-stream p? s) - (if (p? (head s)) - (cons-stream (head s) (filter-stream p? (tail s))) - (filter-stream p? (tail s)))) -\end{lstlisting} - \pause - \textbf{Комбиниране (\tt{zip})} -\begin{lstlisting} -(define (zip-streams op s1 s2) - (cons-stream (op (head s1) (head s2)) - (zip-streams op (tail s1) (tail s2)))) -\end{lstlisting} -\end{frame} - -\begin{frame}<\switch{variadic}>[fragile] - \frametitle{\tt{map-stream} с произволен брой параметри} - - Стандартната функция \lst{map} за списъци позволява комбиниране на произволен брой $n$ списъци с $n$-аргументна функция.\\ - \pause - Можем да реализираме \lst{map-stream} аналогично да комбинира произволен брой потоци:\\ - \pause -\begin{lstlisting} -(define (map-stream f . streams) - (cons-stream (apply f (map head streams)) - (apply map-stream f (map tail streams)))) -\end{lstlisting} - \pause - \textbf{Примери:} - \begin{itemize}[<+->] - \item \evalsto{(map-stream + nats ones)}{1 2 3 4 ...} - \begin{itemize} - \item еквивалентно на \lst{zip-streams} - \end{itemize} - \item \evalsto{(map-stream list nats (map-stream + nats nats fibs))}{(0 0) (1 3) (2 5) (3 8) ...} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Директна дефиниция на потоци} - - Можем да дефиниране на потоци с \alert{директна рекурсия}! - \pause -\begin{lstlisting} -(define ones (cons-stream 1 ones)) -\end{lstlisting} - \pause - Построяване на \tt{nats}:\hspace{8em} - \begin{tabular}{*8c} - \multirow2*+ & 0 & 1 & 2 & 3 & 4 & 5 & \ldots\\ - & 1 & 1 & 1 & 1 & 1 & 1 & \ldots\\ - \hline - & 1 & 2 & 3 & 4 & 5 & 6 & \ldots - \end{tabular}\\[-2ex]\pause - \begin{fixedarea}[.135] - \begin{onlyenv}<-4> -\begin{lstlisting} -(define nats (cons-stream 0 (map-stream 1+ nats))) -\end{lstlisting} - \end{onlyenv} - \begin{onlyenv}<5-| trans:0> -\begin{lstlisting} -(define nats (cons-stream 0 (@\ifbool{variadic}{map-stream}{zip-streams}@ + ones nats))) -\end{lstlisting} - \end{onlyenv} - \end{fixedarea} - \vspace{-1ex}\pause\pause - Построяване на \tt{fibs}:\hspace{8em} - \begin{tabular}{*8c} - \multirow2*+ & 0 & 1 & 1 & 2 & 3 & 5 & \ldots\\ - & 1 & 1 & 2 & 3 & 5 & 8 & \ldots\\ - \hline - & 1 & 2 & 3 & 5 & 8 & 13 & \ldots - \end{tabular} - \pause -\begin{lstlisting} -(define fibs (cons-stream 0 - (cons-stream 1 - (@\ifbool{variadic}{map-stream}{zip-streams}@ + fibs (tail fibs))))) -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Решето на Ератостен} - - \pause - Алгоритъм за намиране на прости числа - \pause - \begin{itemize} - \item Започваме със списък от последователни цели числа - \item Докато не стигнем до края на списъка, повтаряме: - \begin{itemize} - \item Намираме следващото незадраскано число $p$, то е просто - \item Задраскваме всички следващи числа, които се делят на $p$ - \end{itemize} - \end{itemize} - \pause - Ще реализираме решетото над потенциално безкраен поток от числа: - \pause -\begin{lstlisting} -(define (nondivisor d) (lambda (n) (> (remainder n d) 0)))@\pause@ - -(define (sieve stream) - (cons-stream (head stream) - (sieve (filter-stream (nondivisor (head stream)) (tail stream)))))@\pause@ - -(define primes (sieve (from 2))) -\end{lstlisting} -\end{frame} -\end{document} diff --git a/2.1-haskell_basics.tex b/2.1-haskell_basics.tex deleted file mode 100644 index 269d7d9..0000000 --- a/2.1-haskell_basics.tex +++ /dev/null @@ -1,374 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -\title{Основни понятия в Haskell} - -\date{13 ноември 2024 г.} - -\lstset{language=Haskell,style=Haskell} - -\hypersetup{colorlinks,urlcolor=blue,linkcolor=white} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section{Въведение в Haskell} - -\begin{frame} - \frametitle{Какво е Haskell?} - - \pause - \begin{center} - \includegraphics[height=4cm]{images/HaskellBCurry.jpg}\\ - Haskell Brooks Curry\\ - (1900--1982)\\[5ex] - \imageAttr{Photo of Haskell B. Curry}{Gleb.svechnikov}{https://commons.wikimedia.org/wiki/File:HaskellBCurry.jpg}{CC BY-SA 4.0} - \end{center} -\end{frame} - -\lstset{basicstyle=\small\ttfamily} - -\begin{frame}[fragile] - \frametitle{Какво е Haskell?} - - \pause -\begin{lstlisting} -fact 0 = 1 -fact n = n * fact (n-1) -\end{lstlisting} - \pause -\begin{lstlisting} -quickSort [] = [] -quickSort (x:xs) = quickSort less ++ [x] ++ quickSort more - where less = filter (<=x) xs - more = filter (>x ) xs -\end{lstlisting} - \pause -\begin{lstlisting} -@студенти@ = [("@Иван@", 3, 3.5), ("@Мария@", 4, 5.5), - ("@Петър@", 3, 5.0), ("@Галя@", 2, 4.75)] -@избрани@ = foldr1 (++) [ ' ':@име@ | (@име,курс,оценка@) <- @студенти@, - @оценка@ > 4.5, @курс@ <= 3 ] -\end{lstlisting} -\end{frame} - -\lstset{basicstyle=\ttfamily} - -\begin{frame} - \frametitle{Какво е Haskell?} - - \pause - \begin{itemize} - \item Чист функционален език (без странични ефекти) - \item Статично типизиран с автоматичен извод на типовете - \item Използва нестриктно (лениво) оценяване - \item Стандартизиран (Haskell 2010 Language Report) - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Помощни материали} - - \begin{enumerate} - \item S. Thompson. Haskell: The Craft of Functional Programming (2nd ed.). Addison-Wesley, 1999. - \item P. Hudak, Peterson J., Fasel J. A Gentle Introduction to Haskell 98, 1999 (Internet, 2008). - \item \href{https://wiki.haskell.org/Haskell}{Haskell Wiki} - \item \href{https://hackage.haskell.org/}{Hackage} --- централно хранилище с пакети - \item \href{https://www.haskell.org/ghcup/}{GHCup} --- инсталатор на Haskell - \begin{itemize} - \item инсталирайте препоръчаните версии на HLS, GHC, cabal и Stack - \item инсталирайте разширението \href{https://marketplace.visualstudio.com/items?itemName=haskell.haskell}{Haskell} за Visual Studio Code - \end{itemize} - \end{enumerate} -\end{frame} - -\section{Дефиниции} - -\begin{frame}[fragile] - \frametitle{Синтактични елементи} - - \begin{itemize}[<+->] - \item Идентификатори: \tt{fact}, \tt{\_myvar}, \tt{студенти} - \begin{itemize} - \item имена на обекти, започват с малка буква или \tt\_ - \end{itemize} - \item Запазени идентификатори: \lst{case}, \lst{if}, \lst{let}, \lst{where}, \ldots - \item Конструктори: \lst{Integer}, \lst{Maybe}, \lst{Just}, \ldots - \begin{itemize} - \item имена на конструкции, започват с главна буква - \end{itemize} - \item Числа: \tt{10}, \tt{-5.12}, \tt{3.2e+2}, \tt{1.2E-2}, \tt{0x2f}, \tt{0o35} - \item Операции: \tt+, \tt*, \tt{\&\%}, \tt{<==>}, \tt{$\spadesuit$} - \begin{itemize} - \item поредица от символи (без букви и цифри) - \item всички операции с изключение на унарния \tt- са инфиксни - \end{itemize} - \item Запазени операции: \tt{..} \tt: \tt{::} \tt= \tt\textbackslash \tt| \tt{<-} \tt{->} \tt@ \tt\~ \tt{=>} - \item Специални знаци: \tt( \tt) \tt, \tt; \tt[ \tt] \tt` \tt\{ \tt\} - \item Знаци: \lst{'a'}, \lst{'\n'}, \lst{'+'} - \item Низове: \lst{"Hello, world!"}, \lst{"произволен низ"} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Декларации и дефиниции} - - \begin{itemize}[<+->] - \item {}<име> \tta{::} <тип> (типова декларация) - \item декларира се, че <име> ще се свързва със стойности от <тип> - \item \alert{типовите декларации са незадължителни: в повечето случаи Haskell може сам да се ориентира за правилния тип} - \begin{itemize}[<.->] - \item<+-> \tt{x :: Int} - \item \tt{y :: Double} - \item \tt{z :: String} - \end{itemize} - \item {}<име> \tta= <израз> (дефиниция) - \item {}<име> се свърза с <израз> - \begin{itemize}[<+->] - \item \lst{x = 2} - \item \tt{y = \only<+->{fromIntegral }x\^{}2 + 7.5} - \item \lst{z = "Hello"} - \item \sta{z = x + y} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Типове} - - Типовете в Haskell обикновено се задават с конструктори. \pause - \begin{itemize}[<+->] - \item \lst{Bool} --- булев тип с константи \lst{True} и \lst{False} - \item \lst{Char} --- Unicode знаци - \item Целочислени - \begin{itemize} - \item \lst{Int} --- цели числа с фиксирана големина $[-2^{63}; 2^{63}-1]$ - \item \lst{Integer} --- цели числа с произволна големина - \end{itemize} - \item С плаваща запетая - \begin{itemize} - \item \lst{Float} --- дробни числа с единична точност - \item \lst{Double} --- дробни числа с двойна точност - \end{itemize} - \item Съставни - \begin{itemize} - \item \lst{[a]} --- тип списък с \textbf{произволна} дължина и - елементи от \textbf{фиксиран} тип \tt a - \item \lst{String = [Char]} --- низ (списък от знаци) - \item \lst{(a,b,c)} --- тип кортеж (наредена $n$-торка) с - \textbf{фиксирана} дължина и \textbf{произволни} типове на - компонентите - \end{itemize} - \end{itemize} -\end{frame} - -\section{Вградени функции и операции} - -\begin{frame}[fragile] - \frametitle{Стандартен модул \tt{Prelude}} - - \begin{itemize}[<+->] - \item програмите в Haskell се разделят на модули - \item \tta{module} <име> \tta{where} - \item дефинира модул с <име> - \item \tta{import} <модул> [\tta(<име>\{,<име>\}\tta)] - \item внася дефинициите <име> от <модул> - \item ако <име> не е указано, внася всички дефиниции - \item модулът \lst{Prelude} съдържа набор от често използвани стандартни функции - \item всички дефиниции от \lst{Prelude} се внасят автоматично във всяка програма - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Стандартни числови функции} - - Аритметични операци - - \tt{+}, \tt{-}, \tt{*}, \tt{/}, \tt{\^{}}, \tt{\^{}\^{}} - - \vspace{2ex} - Други числови функции - - \lst{div}, \lst{mod}, \lst{max}, \lst{min}, \lst{gcd}, \lst{lcm} - - \vspace{2ex} - Функции за преобразуване - - \lst{fromIntegral}, \lst{fromInteger}, \lst{toInteger}, \lst{realToFrac}, \lst{fromRational}, \lst{toRational}, \lst{round}, \lst{ceiling}, \lst{floor} - - \vspace{2ex} - Функции над дробни числа - - \lst{exp}, \lst{log}, \lst{sin}, \lst{cos}, \lst{tan}, \lst{asin}, \lst{acos}, \lst{atan}, \lst{sqrt}, \lst{**} -\end{frame} - -\begin{frame} - \frametitle{Стандартни предикати} - - Числови предикати - - \tt{<}, \tt{>}, \tt{==}, \tt{/=}, \tt{<=}, \tt{>=}, \lst{odd}, \lst{even} - - \vspace{2ex} - Булеви операции - - \tt{\&\&}, \tt{||}, \lst{not} -\end{frame} - -\section{Функции} - -\begin{frame} - \frametitle{Функции в Haskell} - - \begin{itemize}[<+->] - \item \tt{t1 -> t2} --- тип на функция, която получава параметър от тип \tt{t1} и връща резултат от тип \tt{t2} - \item {}<име> <параметър> \tta= <тяло> - \item дефиниция на функция с <име>, един <параметър> и <тяло> - \item {}<функция> <израз> - \item прилагане на <функция> над <израз> - \begin{itemize}[<.->] - \item \tt{square :: Int -> Int} - \item \tt{square x = x * x} - \item \evalsto{square x}4 - \item \evalstoerr{square 2.7} - \end{itemize} - \item \alert{Прилагането е с по-висок приоритет от другите операции!} - \item \evalsto{square 2 + 3}7 - \item \evalsto{square (2 + 3)}{25} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Функции на повече параметри} - \begin{itemize}[<+->] - \item Как можем да изразим двуаргументна функция $f(x,y)$, ако разполагаме само с едноаргументни функции? - \item Разглеждаме функция $F$ с един аргумент $x$,... - \item ...която връща като резултат едноаргументната $f_x$,... - \item ...така че $f_x(y) = f(x,y)$. - \item Така имаме $f(x,y) = F(x)(y)$. - \end{itemize} - \onslide<+-> - \begin{block}{Основна идея} - Можем да разглеждаме функция с $n+1$ аргумента, като функция с един аргумент, която връща функция с $n$ аргумента. - \end{block} - \onslide<+-> - \alert{Това представяне на функциите с повече аргументи се нарича „къринг“ („currying“).} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Currying в Haskell} - - \begin{itemize}[<+->] - \item \tt{t1 \alert{->} (t2 \alert{->} t3)} - \begin{itemize} - \item функция с параметър от тип \tt{t1}, която връща функция, която приема параметър от тип \tt{t2} и връща резултат от тип \tt{t3}; или - \item функция на два параметъра от типове \tt{t1} и \tt{t2}, която връща резултат от тип \tt{t3} - \end{itemize} - \item В общия случай: <функция> \tt{\alert{::} t1 \alert{->} (t2 \alert{->}} \ldots \tt{(tn \alert{->} t)}\ldots\tt) - \item{} <функция> ще очаква $n$ параметъра от типове \tt{t1}, \tt{t2}, \ldots, \tt{tn} и ще връща резултат от тип \tt{t} - \item{} <функция> <параметър$_1$> \ldots <параметър$_n$> \tta= <тяло> - \item дефинира <функция> с $n$ параметъра и <тяло> - \begin{itemize} - \item \lst{hypothenuse :: Double -> }\alt<+->{\lst{Double -> Double}}{\lst{(Double -> Double)}} - \item \lst{hypothenuse a b = sqrt (a**2 + b**2)} - \item \evalstos{\alt<+->{\tt{hypothenuse 3 4}}{\tt{(hypothenuse 3) 4}}}{\tt5} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}<1-5> - - \frametitle{Частично прилагане на функции} - Кърингът позволява удобно прилагане на функция към само част от параметрите. - \begin{itemize}[<+->] - \item \lst{div50 :: Int -> Int} - \item \tt{div50\temporal<4>{ x}{ $\!\!\not{\tt x}$}{} = div 50\temporal<4>{ x}{ $\!\!\not{\tt x}$}{}} - \item \evalsto{div50 4}{12} - \end{itemize} -\end{frame} - -\begin{frame}<1-19>[fragile] - \frametitle{Функции от по-висок ред} - - \alert{Внимание:} \tt{t1 -> (t2 -> t3)} $\neq$ \tt{(t1 -> t2) -> t3}!\pause - \begin{itemize}[<+->] - \item операцията \tt{->} е \textbf{дясноасоциативна} - \item \tt{t1 -> (t2 -> t3)} $\equiv$ \tt{t1 -> t2 -> t3} - \item \tt{(t1 -> t2) -> t3} --- функция, която връща резултат от тип \tt{t3}, а приема като единствен параметър функция, която приема един параметър от тип \tt{t1} и връща резултат от тип \tt{t2} - \item \alert{функция от втори ред} - \begin{itemize} - \item \lst{twice f x = f (f x)} - \item \lst{twice :: }\alt<-11>{\lst{(Int -> Int) -> Int -> Int}}{\lst{(t -> t) -> t -> t}} - \item \evalstop{twice square 3}{81} - \item \evalstop{twice (mod 13) 5}1\pause - \item \lst{diag f x = f x x} - \item \lst{diag :: }\alt<-18>{\lst{(Int -> Int -> Int) -> Int -> Int}}{\lst{(t1 -> t1 -> t) -> t1 -> t}} - \item \evalstop{diag div 5}1 - \item \evalstop{diag hypothenuse 1}{1.4142135623730951} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Функции и операции} - \begin{itemize}[<+->] - \item Функциите в Haskell са винаги с \textbf{префиксен} запис - \item Операциите в Haskell са винаги \textbf{бинарни с инфиксен} - запис. - \begin{itemize} - \item \alert{Изключение:} унарен минус: \tt{-a} - \item \evalstoerr{square -x} - \item \evalsto{square (-x)}4 - \end{itemize} - \item Преобразуване на двуаргументни функции към бинарни операции: \tta`<функция>\tta` - \begin{itemize} - \item \evalsto{13 `div` 5}3 - \item \evalstoerr{2 `square`} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Операции и функции} - \begin{itemize}[<+->] - \item Преобразуване на операции към двуаргументни функции: \tta(<операция>\tta) - \begin{itemize} - \item \evalsto{(+) 2 3}5 - \item \lst{plus1 = (+) 1} - \item \lst{square = diag (*)} - \end{itemize} - \item Преобразуване на операции към едноаргументни функции (отсичане на операции) - \begin{itemize} - \item \tta(<израз> <операция>\tta) --- ляво отсичане - \item \tta(<операция> <израз>\tta) --- дясно отсичане - \item \evalstop{(2\^) 3}8 - \item \evalstop{(\^2) 3}9 - \item \lst{square = (\^2)} - \item \evalstoerrp{(-5) 8} - \item \evalstop{twice (*2) 5}{20} - \item \lst{positive = (>0)} - \item \lst{lastDigit = (`mod` 10)} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{\tt{if} \ldots \tt{then} \ldots \tt{else}} - \begin{itemize}[<+->] - \item \tta{if} <условие> \tta{then} <израз$_1$> \tta{else} <израз$_2$> - \begin{itemize}[<.->] - \item Ако <условие> е \lst{True}, връща <израз$_1$> - \item Ако <условие> е \lst{False}, връща <израз$_2$> - \end{itemize} - \item \lst{abs x = if x < 0 then -x else x} - \item \lst{fact n = if n == 0 then 1 else n * fact (n - 1)} - \item \evalstoerr{if x > 5 then x + 2 else "Error"} - \item \alert{<израз$_1$> и <израз$_2$> трябва да са от един и същи тип!} - \item \alert{<условие> трябва да е от тип \tt{Bool}!} - \end{itemize} -\end{frame} - -\end{document} diff --git a/2.2-haskell_defs.tex b/2.2-haskell_defs.tex deleted file mode 100644 index 8f55152..0000000 --- a/2.2-haskell_defs.tex +++ /dev/null @@ -1,352 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -\title{Дефиниране на функции в Haskell} - -\date{13 ноември 2024 г.} - -\lstset{language=Haskell,style=Haskell} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section{Разглеждане на случаи} - -\begin{frame}[fragile] - \frametitle{Разглеждане на случаи} - - Можем да дефинниране на функции с разглеждане на случаи по параметрите.\\ - Условието на всеки случай се нарича \textbf{пазач}. - \begin{itemize} - \item{} <име> \{<параметър>\}\\ - \hspace{3ex} \{ \tta| <пазач> \tta= <израз> \}$^+$ - \pause - \item{} <име> <параметър$_1$> <параметър$_2$> ... <параметър$_k$>\\ - \hspace{3ex} \tta| <пазач$_1$> \tta= <израз$_1$>\\ - \hspace{3ex} \ldots\\ - \hspace{3ex} \tta| <пазач$_n$> \tta= <израз$_n$>\\ - \pause - \item ако <пазач$_1$> е \lst{True} връща <израз$_1$>, а ако е \lst{False}: - \item \ldots - \item ако <пазач$_n$> е \lst{True} връща <израз$_n$>, а ако е \lst{False}: - \item \alert{грешка!} - \pause - \item За удобство \lst{Prelude} дефинира \lst{otherwise = True} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Разглеждане на случаи --- примери} - -\begin{lstlisting} -fact n - | n == 0 = 1 - | n > 0 = n * fact (n - 1) - @\onslide<6->{| n < 0\hspace{3.7ex}= error "подадено отрицателно число"}@ -\end{lstlisting} -\onslide<+-> -\begin{itemize}[<+->] -\item \evalstoerrp{fact (-5)} -\item добра практика е да имаме изчерпателни случаи -\item можем да използваме стандартната функция \lst{error} -\end{itemize} -\onslide<+-> -\onslide<+-> -\begin{lstlisting} -grade x - | x >= 5.5 = "Отличен" - | x >= 4.5 = "Много добър" - | x >= 3.5 = "Добър" - | x >= 3 = "Среден" - | otherwise = "Слаб" -\end{lstlisting} -\end{frame} - -\section{Локални дефиниции} - -\begin{frame} - \frametitle{Локални дефиниции с \tt{let}} - - \begin{itemize} - \item \tta{let} \{ <дефиниция> \}$^+$\\ - \tta{in} <тяло> - \pause - \item - \begin{tabular}[t]{@{}ll} - \tta{let}&<дефиниция$_1$>\\ - &<дефиниция$_2$>\\ - &\ldots\\ - &<дефиниция$_n$>\\ - \multicolumn2{@{}l}{\tta{in} <тяло>} - \end{tabular} - \pause - \item{} <дефиниция$_i$> се въвеждат едновременно - \item областта на действие на дефинициите е само в рамките на \lst{let} конструкцията - \item може да са взаимно рекурсивни - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Примери за \tt{let}} - - \begin{itemize}[<+->] - \item \evalsto{let x = 5 in x + 3}8 - \item \evalstops{% - \begin{tabular}[t]{@{}l@{ }l@{}} - \lst{let}&\tt{f x = y + x}\\ - &\tt{y = 7}\\ - \lst{in}&\tt{f 2 * y} - \end{tabular}}{63} - \item \tt{% - \begin{tabular}[t]{@{}l@{ }l@{ }l@{}} - fact2 n = &\lst{let} fact n = &\lst{if} n == 0 \lst{then} 1\\ - & &\lst{else} n * fact (n-1)\\ - &\lst{in} (fact n)\^{}2& - \end{tabular}} - \item В интерактивен режим (GHCi) \lst{let} може да се използва без \lst{in} за въвеждане на нови дефиниции - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Локални дефиниции с \tt{where}} - - \begin{itemize} - \item - % TODO: може ли да се направи без таблица? - \begin{tabular}[t]{@{}l@{\hspace{5ex}}ll} - \multicolumn3{@{}l}{<дефиниция-на-функция>}\\ - &\tta{where}&\{ <дефиниция> \}$^+$ - \end{tabular} - \pause - \item - \begin{tabular}[t]{@{}l@{\hspace{5ex}}ll} - \multicolumn3{@{}l}{<дефиниция-на-функция>}\\ - &\tta{where}&<дефиниция$_1$>\\ - &&<дефиниция$_2$>\\ - &&\ldots\\ - &&<дефиниция$_n$>\\ - \end{tabular} - \pause - \item{} <дефиниция$_i$> се въвеждат едновременно - \item областта на действие на дефинициите е само в рамките на дефиницията на <функция> - \item може да са взаимно рекурсивни - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Примери за \tt{where}} - -\begin{lstlisting} -sumLastDigits n = lastDigit n + lastDigit (stripDigit n) - where lastDigit = (`mod` 10) - stripDigit = (`div` 10) -\end{lstlisting} -\pause -\begin{lstlisting} -quadratic a b c - | a == 0 = "линейно уравнение" - | d > 0 = "две реални решения" - | d == 0 = "едно реално решение" - | otherwise = "няма реални решения" - where d = b^2 - 4*a*c -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Пример за комбиниране на \tt{let} и \tt{where}} - -\begin{lstlisting} -area x1 y1 x2 y2 x3 y3 = - let a = dist x1 y1 x2 y2 - b = dist x2 y2 x3 y3 - c = dist x3 y3 x1 y1 - p = (a + b + c) / 2 - in sqrt (p * (p - a) * (p - b) * (p - c)) - where dist u1 v1 u2 v2 = sqrt (du^2 + dv^2) - where du = u2 - u1 - dv = v2 - v1 -\end{lstlisting} -\end{frame} - -\begin{frame} - \frametitle{Сравнение на \tt{let} и \tt{where}} - - \begin{itemize}[<+->] - \item \lst{let} е израз, който може да участва във всеки израз - \item \lst{where} може да се използва само в рамките на дефиниция - \item \lst{where} дефинициите са видими при всички случаи с пазачи - \item \lst{let} са удобни когато има само едно <тяло> - \item стилистична разлика: - \begin{itemize} - \item с \lst{let} помощните дефиниции се дават първи - \item с \lst{where} акцентът пада върху основната дефиниция - \end{itemize} - \end{itemize} -\end{frame} - -\section{Двумерен синтаксис} - -\begin{frame}[fragile] - \frametitle{Подравняване на дефинициите} - - \begin{columns}[onlytextwidth] - \begin{column}{0.35\textwidth} -\begin{lstlisting} -let h = f + g - b x = 2 -in b h -\end{lstlisting} - \end{column} - \pause - \begin{column}{0.3\textwidth} - а защо не: - \end{column} - \begin{column}{0.35\textwidth} -\begin{lstlisting} -let h = f + g b - x = 2 -in b h -\end{lstlisting} - \end{column} - \end{columns} - \vspace{1em} -\onslide<+-> -\begin{itemize}[<+->] -\item \alert{Подравняването в Haskell има значение!} -\item Обхватът на блок от дефиниции се определя от това как са подравнени. -\item Дефинициите \textbf{точно подравнени} по първата са в същия блок -\item Дефинициите \textbf{вдясно} от първата са в нов вътрешен блок -\item Дефинициите \textbf{вляво} от първата са във външния блок -\end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Двумерен синтаксис --- пример} - % TODO: може ли да стане по-лесно с TikZ? -{\ttfamily -\begin{tabular}{|lllll|} -\hline -\multicolumn 5{|l|}{area x1 y1 x2 y2 x3 y3 =}\\[0.5em] -\cline{3-4} - &let &\multicolumn 2{|l|}{a = dist x1 y1 x2 y2}&\\ - &&\multicolumn 2{|l|}{b = dist x2 y2 x3 y3}&\\ - &&\multicolumn 2{|l|}{c = dist x3 y3 x1 y1}&\\ - &&\multicolumn 2{|l|}{p = (a + b + c) / 2}&\\ -\cline{3-4}&&&&\\ - &\multicolumn 4{l|}{in sqrt (p * (p - a) * (p - b) * (p - c))}\\[0.5em] -\cline{3-5} - &where &\multicolumn 3{|l|}{dist u1 v1 u2 v2 = sqrt (du\^{}2 + dv\^{}2)}\\ -\cline{4-4} - &&\multicolumn 1{|l}{where} &\multicolumn 1{|l|}{du = u2 - u1}&\\ - &&\multicolumn 1{|l}{}&\multicolumn 1{|l|}{dv = v2 - v1}&\\ -\cline{4-4} -&&\multicolumn 3{|l|}{}\\ -\cline{3-5}&&&&\\ -\hline -\end{tabular}} -\end{frame} - -\begin{frame} - \frametitle{Алтернативен синтаксис за блокове} - \begin{itemize}[<+->] - \item Всъщност подравняването е синтактична захар за блок в Haskell - \item \tta\{ \{ <дефиниция> \tta; \} \tta\} - \item \tta\{ <дефиниция$_1$> \tta; \ldots <дефиниция$_n$> [\tta;] \tta\} - \item Интуитивни правила: - \begin{itemize} - \item при първия символ на дефиниция --- запомни позицията и сложи \tta\{ - \item новият ред е подравнен по първия --- сложи \tta; - \item новият ред е по-наляво --- сложи \tta\} - \item новият ред е по-надясно --- не слагай нищо, счита се за продължение на предния ред - \end{itemize} - \item Пазачите не използват синтаксис за блокове, можем безопасно да ги пишем и на един ред: - \item \tt{fact n | n == 0 = 1 | otherwise = n * fact (n-1)} - \end{itemize} -\end{frame} - -\section{Образци} - -\begin{frame}[fragile] - \frametitle{Поредица от равенства} - - \sizeboth\small - Можем да дефинираме функция с поредица от равенства: -\begin{lstlisting} -fact 0 = 1 -fact n = n * fact (n-1) -\end{lstlisting} - \pause - Можем да имаме произволен брой равенства... -\begin{lstlisting} -fib 0 = 0 -fib 1 = 1 -fib n = fib (n-1) + fib (n-2) -\end{lstlisting} - \pause - \ldots или варианти за различните параметри -\begin{lstlisting} -gcd 0 0 = error "@няма най-голям общ делител@" -gcd x 0 = x -gcd 0 y = y -gcd x y - | x > y = gcd (x-y) y - | otherwise = gcd x (y-x) -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Образци} - - \begin{itemize}[<+->] - \item Как се разбира кое равенство да се използва? - \item Видът на формалните параметри наричаме \alert{образец} - \item Търси се на кой образец пасва фактическия параметър - \item Избира се първият образец \alert{отгоре надолу} - \item Видове образци: - \begin{itemize} - \item \textbf{литерали} --- пасват при точно съвпадение - \item \textbf{променливи} --- пасват винаги - \item \textbf{анонимен образец \tt\_} --- пасва винаги без да свързва фактическата стойност с име - \end{itemize} - \item Пример: - \begin{onlyenv}<-9> -\begin{lstlisting} -False && _ = False -_ && b = b -\end{lstlisting} - \end{onlyenv} - \begin{onlyenv}<10-> -\begin{lstlisting} -(&&) False _ = False -(&&) _ b = b -\end{lstlisting} - \end{onlyenv} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Повторение на променливи} - \begin{itemize}[<+->] - \item Можем ли да напишем -\begin{lstlisting} -gcd 0 0 = error "@няма най-голям общ делител@" -gcd x 0 = x -gcd 0 y = y -@\alert{gcd x x = x}@ -gcd x y - | x > y = gcd (x-y) y - | otherwise = gcd x (y-x) -\end{lstlisting} - \item \alert{Не!} - \item Всички променливи в образците трябва да са уникални - \item Няма унификация, както в Пролог - \begin{itemize} - \item Има езици за функционално и логическо програмиране, в които това е позволено (напр. Curry) - \end{itemize} -\end{itemize} -\end{frame} - -\end{document} diff --git a/2.3-haskell_lists.tex b/2.3-haskell_lists.tex deleted file mode 100644 index 0dc1c31..0000000 --- a/2.3-haskell_lists.tex +++ /dev/null @@ -1,765 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -\title{Кортежи и списъци} - -\date{20--29 ноември 2024 г.} - -\lstset{language=Haskell,style=Haskell} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} -\section{Кортежи} - -\begin{frame} - \frametitle{Кортежи (tuples)} - - Кортежите са наредени $n$-торки от данни от произволен тип. - \begin{itemize}[<+->] - \item \textbf{Примери:} \lst{(1,2)}, \lst{(3.5,'A',False)}, \lst{(("square",(^2)),1.0)} - \item Тип кортеж от $n$ елемента: \tuple t - \item Стойности: наредени $n$-торки от вида \tuple x, където $x_i$ е от тип $t_i$ - \item Позволяват „пакетиране"' на няколко стойности в една - \item Операции за наредени двойки: - \begin{itemize} - \item \lst{(,) :: a -> b -> (a,b)} --- конструиране на наредена двойка - \item \lst{fst :: (a,b) -> a} --- първа компонента на наредена двойка - \item \lst{snd :: (a,b) -> b} --- втора компонента на наредена двойка - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Потребителски типове} - - \begin{itemize}[<+->] - \item Типът \lst{(String, Int)} може да означава: - \begin{itemize} - \item име и ЕГН на човек - \item продукт с описание и количество - \item сонет на Шекспир и поредният му номер - \end{itemize} - \item Удобно е да именуваме типовете, за да означаваме смисъла им - \item \tta{type} <конструктор> \tta= <тип> - \begin{itemize} - \item конструкторите са идентификатори, започващи с главна буква - \end{itemize} - \item \textbf{Примери:} - \begin{itemize} - \item \lst{type Student = (String, Int, Double)} - \item \lst{type Point = (Double, Double)} - \item \lst{type Triangle = (Point, Point, Point)} - \item \lst{type Transformation = Point -> Point} - \item \lst{type Vector = Point} - \item \lst{addVectors :: Vector -> Vector -> Vector} - \item<.-> \lst{addVectors v1 v2 = (fst v1 + fst v2, snd v1 + snd v2)} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Особености на кортежите} - - \begin{itemize}[<+->] - \item \evalstoerrp{fst (1,2,3)} - \begin{itemize} - \item \lst{fst} и \lst{snd} работят само над наредени двойки! - \end{itemize} - \item \lst{((a,b),c)} $\neq$ \lst{(a,(b,c))} $\neq$ \lst{(a,b,c)} - \item Няма специален тип кортеж от един елемент\ldots - \item \ldots но има тип „празен кортеж“ \lst{()} с единствен елемент \lst{()} - \begin{itemize} - \item в други езици такъв тип се нарича \lst{unit} - \item използва се за означаване на липса на информация - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Образци на кортежи} - - Образец на кортеж е конструкция от вида \tuple p.\\\pause - Пасва на всеки кортеж от точно $n$ елемента \tuple x, за който образецът $p_i$ пасва на елемента $x_i$. - \onslide<+-> - \begin{itemize}[<+->] - \item \lst{addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)} - \item \lst{fst (x,_) = x} - \item<.-> \lst{snd (_,y) = y} - \item \lst{getYear :: Student -> Int} - \item<.-> \lst{getYear (_, year, _) = year} - \item образците на кортежи могат да се използват за „разглобяване“ на кортежи при дефиниция - \item \lst{(x,y) = (3.5, 7.8)} - \item \lst{let (name, _, grade) = student in (name, min (grade + 1) 6)} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Именувани образци} - - \begin{itemize}[<+->] - \item намиране на студент с по-висока оценка -\begin{lstlisting} -betterStudent (name1, year1, grade1) (name2, year2, grade2) - | grade1 > grade2 = (name1, year1, grade1) - | otherwise = (name2, year2, grade2) -\end{lstlisting} - \item ами ако имахме 10 полета? - \item удобно е да използваме \alert{именувани образци} - \item{} <име>\tta@<образец> \onslide<+-> -\lstset{escapechar=!} -\begin{lstlisting} -betterStudent s1@(_, _, grade1) s2@(_, _, grade2) - | grade1 > grade2 = s1 - | otherwise = s2 -\end{lstlisting} -\lstset{escapechar=@} - \end{itemize} -\end{frame} - -\section{Списъци} - -\subsection{Дефиниция и синтаксис} - - -\begin{frame} - \frametitle{Списъци} - - \begin{definition} - \begin{enumerate} - \item Празният списък \lst{[]} е списък от тип \lst{[a]} - \item Ако \tt h е елемент от тип \tt a и \tt t е списък от тип \lst{[a]} то \lst{(h : t)} е списък от тип \lst{[a]} - \begin{itemize} - \item \tt h --- глава на списъка - \item \tt t --- опашка на списъка - \end{itemize} - \end{enumerate} - \end{definition} - \onslide<+-> - \begin{itemize}[<+->] - \item списъкът е последователност с \alert{произволна дължина} от елементи от \alert{еднакъв тип} - \item \lst{(:) :: a -> [a] -> [a]} е \alert{дясноасоциативна} двуместна операция - \item \lst{(1:(2:(3:(4:[]))))} $=$ \lst{1:2:3:4:[]} $\neq$ \tta{((((1:2):3):4):[])} - \item \hlist a e по-удобен запис за $a_1$\tt{:(}$a_2$\tt:\ldots($a_n$\tt{:[])}\ldots\tt) - \item \lst{[1,2,3,4]} $=$ \lst{1:[2,3,4]} $=$ \lst{1:2:[3,4]} $=$ \lst{1:2:3:[4]} $=$ \lst{1:2:3:4:[]}\ - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Примери} - - \begin{itemize}[<+->] - \item \typestop{[False]}{[Bool]} - \item \ntypesp{["Иван"{}, 4.5]} - \item \ntypesp{[1]:2} - \item \typestop{[[1,2],[3],[4,5,6]]}{[[Int]]} - \item \typestop{([1,2],[3],[4,5,6])}{([Int],[Int],[Int])} - \item \ntypesp{[(1,2),(3),(4,5,6)]} - \item \typestop{((1,2),(3),(4,5,6))}{((Int,Int),Int,(Int,Int,Int))} - \item \typestop{[[]]}{[[a]]} - \item \typestop{[]:[]}{[[a]]} - \item \typestop{[1]:[[]]}{[[Int]]} - \item \ntypesp{[]:[1]} - \item \typestop{[[1,2,3],[]]}{[[Int]]} - \item \ntypesp{[[1,2,3],[[]]]} - \item \typestop{[1,2,3]:[4,5,6]:[[]]}{[[Int]]} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Низове} - - \begin{itemize}[<+->] - \item В Haskell низовете са представени като списъци от символи - \item \lst{type String = [Char]} - \item Всички операции над списъци важат и над низове - \item \textbf{Примери:} - \begin{overprint} - \begin{itemize} - \item \lst!['H', 'e', 'l', 'l', 'o' ] == "Hello"! - \item \lst!'H':'e':'l':'l':'o':[] == "Hello"! - \item \lst!'H':'e':"llo" == "Hello"! - \item \lst!\ "" == [] :: [Char]! - \item \ntypesp{[[1,2,3],{}"{}"]} - \item \typestop{["12",['3'],[]]}{[String]} - \end{itemize} - \end{overprint} - \end{itemize} -\end{frame} -\subsection{Работа със списъци} - -\begin{frame} - \frametitle{Основни функции за списъци} - - % head, tail, null, length - \begin{itemize}[<+->] - \item \lst{head :: [a] -> a} --- връща главата на (непразен) списък - \begin{itemize} - \item \evalstop{head [[1,2],[3,4]]}{[1,2]} - \item \evalstoerr{head []} - \end{itemize} - \item \lst{tail :: [a] -> [a]} --- връща опашката на (непразен) списък - \begin{itemize} - \item \evalstop{tail [[1,2],[3,4]]}{[[3,4]]} - \item \evalstoerr{tail []} - \end{itemize} - \item \lst{null :: [a] -> Bool} --- проверява дали списък е празен - \item \lst{length :: [a] -> Int} --- дължина на списък - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Образци и списъци} - - Много удобно е да използваме образци на списъци: - \begin{itemize}[<+->] - \item $p_h$\tt:$p_t$ --- пасва на всеки непразен списък $l$, за който: - \begin{itemize} - \item образецът $p_h$ пасва на главата на $l$ - \item образецът $p_t$ пасва на опашката на $l$ - \end{itemize} - \item \alert{Внимание:} обикновено слагаме скоби \lst{(h:t)}, понеже операцията \tt: е с много нисък приоритет - \item \tt[$p_1$\tt, $p_2$\tt, \ldots\tt, $p_n$\tt] --- пасва на всеки списък от точно $n$ елемента \tt[$x_1$\tt, $x_2$\tt, \ldots\tt, $x_n$\tt], за който образецът $p_i$ пасва на елемента $x_i$ - \item \textbf{Примери:} - \begin{itemize} - \item \lst{head (h:_) = h} - \item \lst{tail (_:t) = t} - \item \lst{null [] = True} - \item<.-> \lst{null _ = False} - \item \lst{length [] = 0} - \item<.-> \lst{length (_:t) = 1 + length t} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Случаи по образци (\tt{case})} - \begin{itemize}[<+->] - \item \tta{case} <израз> \tta{of} \{ <образец> \tta{->} <израз> \}$^+$ - \item \begin{tabular}[t]{@{}l@{ }l} - \tta{case} <израз> \tta{of}&<образец$_1$> \tta{->} <израз$_1$>\\ - &\ldots\\ - &<образец$_n$> \tta{->} <израз$_n$> - \end{tabular} - \item ако <израз> пасва на <образец$_1$>, връща <израз$_1$>, иначе: - \item<.-> \ldots - \item<.-> ако <израз> пасва на <образец$_n$>, връща <израз$_n$>, иначе: - \item<.-> \alert{Грешка!} - \item Използването на образци в дефиниции всъщност е синтактична захар за конструкцията \tt{case}! - \item \tt{case} може да се използва навсякъде, където се очаква израз - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Генератори на списъци} - - Можем да генерираме списъци от последователни елементи - \begin{itemize} - \item \tta[$a$\tta{..}$b$\tta] $\rightarrow$ \tta[$a$\tta, $a+1$\tta, $a+2$\tta,\ldots $b$\tta] - \item \textbf{Пример:} \evalsto{[1..5]}{[1,2,3,4,5]} - \item \textbf{Пример:} \evalsto{['a'..'e']}{\ "abcde"} - \item Синтактична захар за \tt{enumFromTo from to}\\[1em] - \pause - \item \tta[$a$\tta, $a+\Delta x$ \tta{..} $b$\tta] $\rightarrow$ \tta[$a$\tta, $a+\Delta x$\tta, $a + 2\Delta x$\tta, \ldots \tta, $b'$\tta], където $b'$ е най-голямото число $\leq b$, за което $b' = a+k\Delta x$ - \item \textbf{Пример:} \evalsto{[1,4..15]}{[1,4,7,10,13]} - \item \textbf{Пример:} \evalsto{['a','e'..'z']}{\ "aeimquy"} - \item Синтактична захар за \tt{enumFromThenTo from then to} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Рекурсивни функции над списъци} - \begin{itemize}[<+->] - \item \lst{(++) :: [a] -> [a] -> [a]} --- слепва два списъка - \begin{itemize}[<.->] - \item \evalsto{[1..3] ++ [5..7]}{[1,2,3,5,6,7]} - \end{itemize} - \onslide<+-> -\begin{lstlisting} -[] ++ ys = ys -(x:xs) ++ ys = x:xs ++ ys -\end{lstlisting} - \item \lst{reverse :: [a] -> [a]} --- обръща списък - \begin{itemize}[<.->] - \item \evalsto{reverse [1..5]}{[5,4,3,2,1]} - \end{itemize} - \onslide<+-> -\begin{lstlisting} -reverse [] = [] -reverse (x:xs) = reverse xs ++ [x] -\end{lstlisting} -\item \lst{(!!) :: [a] -> Int -> a} --- елемент с пореден номер (от 0) - \begin{itemize}[<.->] - \item \evalsto{\ "Haskell" \!\! 2}{'s'} - \end{itemize} - \item \lst{elem :: }\tta{Eq a =>}\lst{ a -> [a] -> Bool} --- проверка за принадлежност на елемент към списък - \begin{itemize}[<.->] - \item \evalsto{3 `elem` [1..5]}{True} - \end{itemize} - \end{itemize} -\end{frame} - -\subsection{Полиморфизъм} - -\begin{frame} - \frametitle{Полиморфни функции} - - %++, !!, reverse, elem, notElem - Функциите \lst{head}, \lst{tail}, \lst{null}, \lst{length}, \lst{reverse} и операциите \lst{++} и \lst{!!} са \textbf{полиморфни} - \begin{itemize}[<+->] - \item работят над списъци с елементи от произволен тип \lst{[t]} - \item \tt t се нарича \textbf{типова променлива} - \item свойството се нарича \textbf{параметричен типов полиморфизъм} - \item подобно на шаблоните в C++ - \item \alert{да не се бърка с \textbf{подтипов полиморфизъм}, реализиран с виртуални функции!} - \item \lst{[]} е \textbf{полиморфна константа} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Класове от типове (typeclasses)} - - Функцията \lst{elem} има специални изисквания към типа на елементите на списъка: трябва да могат да бъдат сравнявани с \lst{==} или \lst{/=} - \begin{itemize}[<+->] - \item \lst!elem :: !\tta{Eq t =>}\lst{ t -> [t] -> Bool} - \item \lst{Eq} е \alert{клас от типове} - \item \lst{Eq} е класът на тези типове, за които има операции \lst{==} и \lst{/=} - \begin{itemize} - \item можем да си мислим за класовете от типове като за „интерфейси“ - \end{itemize} - \item \lst{Eq t} наричаме \alert{класово ограничение} за типа \tt t (class constraint) - \item множеството от всички класови ограничения наричаме \alert{контекст} - \item \alert{инстанция} на клас от типове наричаме всеки тип, за който са реализирани операциите зададени в класа - \item инстанции на \lst{Eq} са: - \begin{itemize} - \item \lst{Bool}, \lst{Char}, всички числови типове (\lst{Int}, \lst{Integer}, \lst{Float}, \lst{Double}) - \item списъчните типове \lst{[t]}, за които \tt t е инстанция на \lst{Eq} - \item кортежните типове \tt($t_1$\tt, \ldots\tt, $t_n$\tt), за които $t_i$ са инстанции на \lst{Eq} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Стандартни класове} - - Някои от по-често използваните класове на Haskell: - \begin{itemize}[<+->] - \item \lst{Eq} --- типове с равенство - \item \lst{Ord} --- типове с (линейна) наредба - \begin{itemize}[<.->] - \item операциите \lst{==}, \lst{/=}, \lst{>=}, \lst{<=}, \lst{<}, \lst{>} - \item специалната функция \lst{compare}, която сравнява два елемента и връща \lst{LT}, \lst{GT} или \lst{EQ} в зависимост от резултата - \item функциите \lst{min} и \lst{max} - \end{itemize} - \item \lst{Show} --- типове, чиито елементи могат да бъдат извеждани в низ - \begin{itemize}[<.->] - \item функция \lst{show :: a -> String} - \end{itemize} - \item \lst{Read} --- типове, чиито елементи могат да бъдат въвеждани от низ - \begin{itemize}[<.->] - \item функция \lst{read :: String -> a} - \end{itemize} - \item \lst{Num} --- числови типове - \item<.-> \lst{Integral} --- целочислени типове - \item<.-> \lst{Floating} --- типове с плаваща запетая - \item \alert{числата в Haskell са полиморфни константи!} - \end{itemize} -\end{frame} - -\subsection{Отделяне на списъци} - -\begin{frame} - \frametitle{Отделяне на списъци (list comprehension)} - - Отделянето на списъци е удобен начин за дефиниране на нови списъци чрез използване на дадени такива - \begin{itemize}[<+->] - \item \tta[ <израз> \tta| <генератор> \{\tta, <генератор> | <условие>\} \tta] - \item{} <генератор> е от вида <образец> \tta{<-} <израз>, където - \begin{itemize} - \item{} <израз> е от тип списък \lst{[a]} - \item{} <образец> пасва на елементи от тип \tt a - \end{itemize} - \item{} <условие> е произволен израз от тип \lst{Bool} - \item За всеки от елементите генериран от <генератор>, които удовлетворяват \alert{всички} <условие>, пресмята <израз> и натрупва резултатите в списък - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Примери за отделяне на списъци} - - \begin{itemize}[<+->] - \item \evalstop{[ 2 * x | x <- [1..5] ]}{[2,4,6,8,10]} - \item \evalstop{[ x^2 | x <- [1..10], odd x]}{[1,9,25,49,81]} - \item \lst{[ name | (name, \_, grade) <- students, grade >= 3 ]} - \item \lst{[ x^2 + y^2 | (x, y) <- vectors, x >= 0, y >= 0 ]} - \item Ако имаме повече от един генератор, се генерират всички възможни комбинации от елементи (декартово произведение) - \item \evalstopnl{[ x++(' ':y) | x <- ["green", "blue"], y <- ["grass", "sky"]]}{["green grass", "green sky", "blue grass", "blue sky"]} - \item \evalstopnl{[ (x,y) | x <- [1,2,3], y <- [5,6,7], x + y <= 8 ]}{[(1,5),(1,6),(1,7),(2,5),(2,6),(3,5)]} - \item \textbf{Задача.} Да се генерират всички Питагорови тройки в даден интервал. - \end{itemize} -\end{frame} - -\section{Функции над списъци} - -\begin{frame} - \frametitle{Отрязване на списъци} - - \begin{itemize}[<+->] - \item \lst{init :: [a] -> [a]} --- списъка без последния му елемент - \begin{itemize}[<.->] - \item \evalsto{init [1..5]}{[1,2,3,4]} - \end{itemize} - \item \lst{last :: [a] -> a} --- последния елемент на списъка - \begin{itemize}[<.->] - \item \evalsto{last "Haskell"}l - \end{itemize} - \item \lst{take :: Int -> [a] -> [a]} --- първите $n$ елемента на списък - \begin{itemize}[<.->] - \item \evalsto{take 4 "Hello, world\!"}{\ "Hell"} - \end{itemize} - \item \lst{drop :: Int -> [a] -> [a]} --- списъка без първите $n$ елемента - \begin{itemize}[<.->] - \item \evalsto{drop 2 [1,3..10]}{[5,7,9]} - \end{itemize} - \item \lst{splitAt :: Int -> [a] -> ([a],[a])} - \begin{itemize}[<.->] - \item \lst{splitAt n l = (take n l, drop n l)} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Агрегиращи функции} - - % maximum, minimum, product, sum, and, or, concat - \small - \begin{itemize}[<+->] - \item \lst{maximum :: Ord a => [a] -> a} --- максимален елемент - \item<.-> \lst{minimum :: Ord a => [a] -> a} --- минимален елемент - \item \lst{sum :: Num a => [a] -> a} --- сума на списък от числа - \item<.-> \lst{product :: Num a => [a] -> a} --- произведение на списък от числа - \item \lst{and :: [Bool] -> Bool} --- конюнкция на булеви стойности - \item<.-> \lst{or :: [Bool] -> Bool} --- дизюнкция на булеви стойности - \item \lst{concat :: [[a]] -> [a]} --- конкатенация на списък от списъци - \item \textbf{Примери:} - \begin{itemize}[<+->] - \item \lst{[(sum l, product l)| l <- ll, maximum l == 2*minimum l]} - \item \lst{and [ or [ mod x k == 0 | x <- row] | row <- matrix]} - \end{itemize} - \end{itemize} - % TODO: таблица с агрегиращите функции -\end{frame} - -\subsection{Функции от по-висок ред} - -\begin{frame} - \frametitle{$\lambda$-функции} - \begin{itemize}[<+->] - \item \tta{\textbackslash}\{ <параметър> \}$^+$ \tta{->} <тяло> - \item \tta{\textbackslash} <параметър$_1$> \ldots <параметър$_n$> \tta{->} <тяло> - \item анонимна функция с $n$ параметъра - \item всеки <параметър$_i$> всъщност е образец - \item параметрите са видими само в рамките на <тяло> - \item \textbf{Примери:} - \begin{itemize} - \item \lst{id = \\x -> x} - \item \lst{const = \\x y -> x} - \item \evalsto{(\\x -> 2 * x + 1) 3}{7} - \item \evalsto{(\\x l -> l ++ [x]) 4 [1..3]}{[1,2,3,4]} - \item \evalsto{(\\(x,y) -> x^2 + y) (3,5)}{14} - \item \evalsto{(\\f x -> f (f x)) (*3) 4}{36} - \end{itemize} - \item отсичането на операции може да се изрази чрез $\lambda$-функции: - \begin{itemize} - \item \tt(<операция> <израз>\tt) = \lst{\\x -> x} <операция> <израз> - \item \tt(<израз> <операция>\tt) = \lst{\\x ->} <израз> <операция> \tt x - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Свойства на $\lambda$-функциите} - - \begin{itemize}[<+->] - \item - \begin{tabular}[t]{ll} - &\tt\textbackslash $x_1\;x_2\;\ldots\;x_n$ \tt{->} <тяло>\\ - \eqv &\tt\textbackslash $x_1$ \tt{-> \textbackslash}$x_2$ \tt{->} \ldots \tt\textbackslash $x_n$ \tt{->} - <тяло> - \end{tabular} - \item - \begin{tabular}[t]{ll} - &\lst{f x =} <тяло>\\ - \eqv&\lst!f = \\x ->! <тяло> - \end{tabular} - \item - \begin{tabular}[t]{ll} - &\lst{f x y =} <тяло>\\ - \eqv& \lst!f x = \\y ->! <тяло>\\ - \eqv& \lst!f = \\x y ->! <тяло> - \end{tabular} - \item - \begin{tabular}[t]{ll} - &\tt f $x_1 \ldots x_n$ \tt= <тяло>\\ - \eqv& \tt f $x_1 \ldots x_{n-1}$ \tt= \tt\textbackslash $x_n$ \tt{->} <тяло>\\ - \eqv& \ldots\\ - \eqv& \lst{f = \\}$x_1 \ldots x_n$\tt{ -> }<тяло> - \end{tabular} - \item - \begin{tabular}[t]{ll} - &\lst{\\x y -> f x y}\\ - \eqv& \lst{\\x -> f x}\\ - \eqv& \tt f - \end{tabular} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Трансформация (\tt{map})} - - \begin{itemize}[<+->] - \item \lst{map :: (a -> b) -> [a] -> [b]} - \item \lst{map f l = [ f x | x <- l ]} - \item \lst{map \_ [] = []} - \item<.-> \lst{map f (x:xs) = f x : map f xs} - \item \textbf{Примери:} - \begin{itemize} - \item \evalstop{map (^2) [1,2,3]}{[1,4,9]} - \item \evalstop{map (\!\!1) [[1,2,3],[4,5,6],[7,8,9]]}{[2,5,8]} - \item \evalstop{map sum [[1,2,3],[4,5,6],[7,8,9]]}{[6,15,24]} - \item \evalstop{map ("a "++) ["cat", "dog", "pig"]}{["a cat", "a dog", "a pig"]} - \item \evalstop{map (\\f -> f 2) [(^2),(1+),(*3)]}{[4,3,6]} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Филтриране (\tt{filter})} - - \begin{itemize}[<+->] - \item \lst{filter :: (a -> Bool) -> [a] -> [a]} - \item \lst{filter p l = [ x | x <- l, p x ]} - \item -\begin{lstlisting} -filter _ [] = [] -filter p (x:xs) - | p x = x : rest - | otherwise = rest - where rest = filter p xs -\end{lstlisting} - \item \textbf{Примери:} - \begin{itemize} - \item \evalstop{filter odd [1..5]}{[1,3,5]} - \item \evalstop{filter (\\f -> f 2 > 3) [(^2),(+1),(*3)]}{[(^2),(*3)]} - \item \evalstop{map (filter even) [[1,2,3],[4,5,6],[7,8,9]]}{[[2],[4,6],[8]]} - \item \evalstops{\lst{map (\\x -> map (\\f -> filter f x) [(<0),(==0),(>0)])} \tt{[[-2,1,0],[1,4,-1],[0,0,1]]}\\\phantom{[,]}}{\tt{[[[-2],[0],[1]],[[-1],[],[1,4]],[[],[0,0],[1]]]}} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}<1-6> - \frametitle{Отделяне на списъци с \tt{map} и \tt{filter}} - - Отделянето на списъци е синтактична захар за \lst{map} и \lst{filter}\pause - \small - \begin{itemize}[<+->] - \item \begin{tabular}[t]{l} - \tt[<израз> \tt| <образец> \tt{<-} <списък>\tt, <условие>\tt]\\ - $\longleftrightarrow$\\ - \lst{map (\\}<образец> \tt{->} <израз>\tt)\\ - \hspace{5ex}\lst{(filter (\\}<образец> \tt{->} <условие>\tt) <списък>\tt) - \end{tabular} - \item \begin{tabular}[t]{l} - \tt[<образец> \tt| <образец> \tt{<-} <списък>\tt,<условие$_1$>,<условие$_2$>\tt]\\ - $\longleftrightarrow$\\ - \lst{filter (\\}<образец> \tt{->} <условие$_2$>\tt)\\ - \hspace{5ex}\lst{(filter (\\}<образец> \tt{->} <условие$_1$>\tt) <списък>\tt) - \end{tabular} - \item \begin{tabular}[t]{l} - \tt[<израз>\tt|<образец$_1$> \tt{<-} <списък$_1$>\tt,<образец$_2$> \tt{<-} <списък$_2$>\tt]\\ - $\longleftrightarrow$\\ - \temporal<5>{\lst{concat (map (\\}}{\tta{concat}\tt{ }\lst{(map (\\}}{\lst{concatMap (\\}}<образец$_1$> \tt{->}\\ - \hspace{15ex}\lst{map (\\} <образец$_2$> \tt{->} <израз>\tt) <списък$_2$>\tt)\\ - \hspace{10ex} <списък$_1$>\only<4-5>{\tt)} - \end{tabular} - \end{itemize} -\end{frame} - -\begin{frame}<1-14>[fragile] - \frametitle{Дясно свиване (\tt{foldr})} - - \begin{itemize}[<+->] - \item \lst{foldr :: (a -> b -> b) -> b -> [a] -> b} - \item \lst{foldr op nv} \hlist x = \\ - $x_1$ \tt{`op` (}$x_2$ \tt{`op`} \ldots \tt($x_n$\tt{ `op` nv)} \ldots\tt) - \item -\begin{lstlisting} -foldr _ nv [] = nv -foldr op nv (x:xs) = x `op` foldr op nv xs -\end{lstlisting} - \item \textbf{Примери:} - \begin{itemize} - \item \lst{sum = foldr (+) 0} - \item \lst{product = foldr (*) 1} - \item \lst{concat = foldr (++) []} - \item \lst{and = foldr (&&) True} - \item \lst{or = foldr (||) False} - \item \lst{map f = foldr (\x} \tt{\only<-10>{ r} -> \alt<10>{f x : r}{(f x:)}) []} - \onslide<+-> - \item \footnotesize\lst{filter p = foldr (\x}\tt{\only<-13>{ r} -> \temporal<13>{if p x then x:r else r}{(if p x then (x:) else id) r}{if p x then (x:) else id}) []} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Ляво свиване (\tt{foldl})} - - \begin{itemize}[<+->] - \item \lst{foldl :: (b -> a -> b) -> b -> [a] -> b} - \item \lst{foldl op nv }\hlist x = \\ - \tt(\ldots\tt{((nv `op` }$x_1$\tt{) `op` }$x_2$\tt) \ldots \tt{) `op` }$x_n$ - \item -\begin{lstlisting} -foldl _ nv [] = nv -foldl op nv (x:xs) = foldl op (nv `op` x) xs -\end{lstlisting} - \item \textbf{Пример:} - \begin{itemize}[<.->] - \item \lst{flip f x y = f y x} - \item \lst{reverse = foldl (flip (:)) []} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Свиване на непразни списъци (\tt{foldr1} и \tt{foldl1})} - - \begin{itemize}[<+->] - \item \lst{foldr1 :: (a -> a -> a) -> [a] -> a} - \item \lst{foldr1 op }\hlist x = \\ - $x_1$\tt{ `op` (}$x_2$\tt{ `op` }\ldots \tt($x_{n-1}$\tt{ `op` }$x_n$\tt) \ldots\tt) - \item -\begin{lstlisting} -foldr1 _ [x] = x -foldr1 op (x:xs) = x `op` foldr1 op xs -\end{lstlisting} - \item \lst{foldl1 :: (a -> a -> a) -> [a] -> a} - \item \lst{foldl1 op }\hlist x = \\ - \tt(\ldots\tt{((}$x_1$\tt{ `op` }$x_2$\tt) \ldots \tt{) `op` }$x_n$ - \item \lst{foldl1 op (x:xs) = foldl op x xs} - \item \textbf{Примери:} - \begin{itemize} - \item \lst{maximum = foldr1 max} - \item \lst{minimum = foldr1 min} - \item \lst{last = foldl1 (\_ x -> x)} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Сканиране на списъци (\tt{scanl}, \tt{scanr})} - - \sizeboth\small - \lst{scanr} и \lst{scanl} връщат историята на пресмятането на \lst{foldr} и \lst{foldl} - \pause - \begin{itemize}[<+->] - \setlength\itemsep{.1em} - \item \lst!scanr :: (a -> b -> b) -> b -> [a] ->! \tta{[b]} - \item \lst{scanr op nv} \hlist x = \\ - \tt[$x_1$\tt{ `op` (}$x_2$\tt{ `op` }\ldots \tt($x_n$\tt{ `op` nv)} \ldots\tt{),}\\ - \tt{ }$x_2$\tt{ `op` (}\ldots \tt($x_n$\tt{ `op` nv)} \ldots\tt{),}\\ - \tt{ }\ldots\\ - \tt{ }$x_n$\tt{ `op` nv,}\\ - \tt{ nv]} - \item \lst!scanl :: (b -> a -> b) -> b -> [a] ->! \tta{[b]} - \item \lst{scanl op nv} \hlist x = \\ - \tt{[nv,}\\ - \tt{ nv `op` }$x_1$\tt,\\ - \tt{ (nv `op` }$x_1$\tt{) `op` }$x_2$\tt,\\ - \tt{ }\ldots\\ - \tt{ (\ldots((nv `op` $x_1$) `op` $x_2$) \ldots ) `op` $x_n$]} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Съшиване на списъци (\tt{zip}, \tt{zipWith})} - - \begin{itemize}[<+->] - \item \lst{zip :: [a] -> [b] -> [(a,b)]} - \begin{itemize} - \item \evalstos{\lst{zip} \hlist x \hlist y}{\tt[($x_1$\tt, $y_1$\tt{), (}$x_2$\tt, $y_2$\tt{), }\ldots\tt{, (}$x_n$\tt, $y_n$\tt{)]}} - \item ако единият списък е по-къс, спира когато свърши той - \end{itemize} - \item \lst{unzip :: [(a,b)] -> ([a],[b])} - \begin{itemize} - \item разделя списък от двойки на два списъка с равна - дължина - \item \evalstos{\lst{unzip} - \tt{[(}$x_1$\tt,$y_1$\tt{), (}$x_2$\tt,$y_2$\tt{), }\ldots\tt{, (}$x_n$,$y_n$\tt{)]}}{\tt(\hlist x\tt, \hlist y\tt)} - \end{itemize} - \item \lst{zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]} - \begin{itemize} - \item „съшива“ два списъка с дадена двуместна операция - \item \evalstos{\lst{zipWith op} \hlist x \hlist y}{\tt{[op} $x_1$ $y_1$\tt{, op} $x_2$ $y_2$\tt, \ldots\tt{, op} $x_n$ $y_n$\tt]} - \end{itemize} - \item \textbf{Примери:} - \begin{itemize} - \item \evalsto{zip [1..3] [5..10]}{[(1,5),(2,6),(3,7)]} - \item \evalsto{zipWith (*) [1..3] [5..10]}{[5,12,21]} - \item \lst{zip = zipWith (,)} - \item \lst{unzip = foldr (\\(x,y) (xs,ys) -> (x:xs,y:ys)) ([],[])} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Разбивания на списъци} - - \begin{itemize}[<+->] - \item \lst{takeWhile :: (a -> Bool) -> [a] -> [a]} - \begin{itemize} - \item връща първите елементи на списъка, за които е вярно условието - \item \lst{takeWhile p = foldr (\\x r -> if p x then x:r else []) []} - \item \evalsto{takeWhile (<0) [-3..3]}{[-3,-2,-1]} - \end{itemize} - \item \lst{dropWhile :: (a -> Bool) -> [a] -> [a]} - \begin{itemize} - \item премахва първите елементи на списъка, за които е вярно условието - \item \evalsto{dropWhile (<0) [-3..3]}{[0,1,2,3]} - \end{itemize} - \item \lst{span :: (a -> Bool) -> [a] -> ([a], [a])} - \begin{itemize} - \item \lst{span p l = (takeWhile p l, dropWhile p l)} - \item \evalsto{span (<0) [-3..3]}{([-3,-2,-1],[0,1,2,3])} - \end{itemize} - \item \lst{break :: (a -> Bool) -> [a] -> ([a],[a])} - \begin{itemize} - \item \lst{break p l = (takeWhile q l, dropWhile q l)}\\ - \hspace{15ex}\lst{where q x = not (p x)} - \item \evalsto{break (>0) [-3..3]}{([-3,-2,-1,0],[1,2,3])} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Логически квантори (\tt{any}, \tt{all})} - - \begin{itemize}[<+->] - \item \lst{any :: (a -> Bool) -> [a] -> Bool} - \begin{itemize} - \item проверява дали предикатът е изпълнен за \textbf{някой елемент} от списъка - \item \lst{any p l = or (map p l)} - \item \lst{elem x = any (==x)} - \end{itemize} - \item \lst{all :: (a -> Bool) -> [a] -> Bool} - \begin{itemize} - \item проверява дали предикатът е изпълнен за \textbf{всички елементи} на списъка - \item \lst{all p l = and (map p l)} - \item \lst{sorted l = all (\\(x,y) -> x <= y) (zip l (tail l))} - \end{itemize} - \end{itemize} -\end{frame} - -\end{document} diff --git a/2.4-haskell_lazy.tex b/2.4-haskell_lazy.tex deleted file mode 100644 index b265185..0000000 --- a/2.4-haskell_lazy.tex +++ /dev/null @@ -1,688 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -% взели ли сме вече вход/изход? -\newbooltrue{io} - -% примери за безточково програмиране -\newboolfalse{pointfree} - -\title[Лениво оценяване]{Лениво оценяване и програмиране от по-висок ред} - -\date{4--11 декември 2024 г.} - -\lstset{language=Haskell,style=Haskell} - -\newcommand{\lra}{\onslide<+->$\longrightarrow$\xspace} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section{Лениво оценяване} - -\begin{frame} - \frametitle{Щипка $\lambda$-смятане} - - \renewcommand{\lra}{\onslide<+->\longrightarrow\xspace} - \begin{itemize}[<+->] - \item $\lambda$-изрази: $E ::= x \;|\; E_1(E_2) \;|\; \lambda x\, E$ - \item Изчислително правило: $(\lambda x\,E_1)(E_2) \mapsto E_1[x := E_2]$ - \item В какъв ред прилагаме изчислителното правило? - \item Нека $f := \lambda x\; x!$, $g := \lambda z\;z^2+z$ - \item $g(f(4)) \lra \quad ?$ - \item $g(\underline{f(4)}) - \lra g(\underline{4!}) - \lra \underline{g(24)} - \lra 24^2 + 24 - \lra 600$ - \begin{itemize} - \item<16-> оценява се \alert{отвътре навън} - \item<17-> \alert{стриктно} (апликативно, лакомо) оценяване - \end{itemize} - \item $\underline{g(f(4))} - \lra (\underline{f(4)})^2 + \underline{f(4)} - \lra (\underline{4!})^2 + \underline{4!} - \lra 24^2 + 24 - \lra 600$ - \begin{itemize} - \item<16-> оценява се \alert{отвън навътре} - \item<17-> \alert{нестриктно} (нормално, лениво) оценяване - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Стриктно и нестриктно оценяване} - - Стриктното оценяване - \begin{itemize}[<+->] - \item се използва в повечето езици за програмиране - \item се нарича още „call-by-value“ (извикване по стойност) - \item позволява лесно да се контролира редът на изпълнение - \item пестеливо откъм памет, понеже „пази чисто“ - \end{itemize} - \onslide<+-> - Нестриктното оценяване - \begin{itemize}[<+->] - \item е по-рядко използвано - \item въпреки това се среща в някаква форма в повечето езици! - \begin{itemize} - \item \tt{x = p != nullptr ? p->data : 0;} - \item \tt{found = i < n \&\& a[i] == x} - \end{itemize} - \item нарича се още „call-by-name“ (извикване по име) - \item може да спести сметки, понеже „изхвърля боклуците“ - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Кога мързелът помага} - -\begin{lstlisting}[language=Scheme] -(define (f x y) (if (< x 5) x y)) -(define (g l) (f (car l) (cadr l))) -\end{lstlisting} -\pause -\begin{tabular}[t]{l@{}l} -\tt{\underline{(g '(3))}} -&\lra \tt{(f \underline{(car '(3))} (cadr '(3)))}\\ -&\lra \tt{(f 3 \underline{(cadr '(3))})} -\lra \alert{Грешка!} -\end{tabular} -\onslide<+-> -\begin{lstlisting} -f x y = if x < 5 then x else y -g l = f (head l) (head (tail l)) -\end{lstlisting} -\onslide<+-> -\begin{tabular}[t]{l@{}l} -\tt{\underline{g [3]}} -&\lra \tt{\underline{f (head [3]) (head (tail [3]))}}\\ -&\lra \tt{if} \underline{\tt{head [3]}} \tt{< 5 then head [3] else head (tail [3])}\\ -&\lra \tt{if \underline{3 < 5} then head [3] else head (tail [3])}\\ -&\lra \tt{\underline{if True then head [3] else head (tail [3])}}\\ -&\lra \tt{\underline{head [3]}} -\lra \tt 3 -\end{tabular} -\end{frame} - -\begin{frame} - \frametitle{Теорема за нормализация} - - \begin{itemize}[<+->] - \item всеки път когато апликативното оценяване дава резултат и нормалното оценяване дава резултат - \item има случаи, когато нормалното оценяване дава резултат, но апликативното не! - \item нещо повече: - \end{itemize} - \onslide<.-> - \begin{theorem}[за нормализация, Curry] - Ако има някакъв ред на оценяване на програмата, който достига до резултат, то и с нормална стратегия на оценяване ще достигнем до същия резултат. - \end{theorem} - \onslide<+-> - \begin{corollary} - Ако с нормално оценяване програмата даде грешка или не завърши, то няма да получим резултат с \alert{никоя друга стратегия на оценяване}. - \end{corollary} -\end{frame} - -\begin{frame} - \frametitle{Извикване при нужда („call-by-need“)} - -Ако $g(z) = z^2 + z$, $g(g(g(2))) = ?$ -\pause -{\small -\begin{equation*} - \begin{array}{rl} - g(g(g(2))) \pause &\mapsto g(g(2))^2 + g(g(2)) \pause\mapsto (g(2)^2+ g(2))^2 + g(2)^2 + g(2) \pause\mapsto\\ - &\mapsto ((2^2+2)^2+2^2+2)+(2^2+2)^2 + 2^2+2 \mapsto \ldots - \end{array} -\end{equation*}}\pause -Времето и паметта нарастват експоненциално!\\ -\pause -\fbox{\textbf{Идея:} $(\lambda x\,E_1)(E_2) \mapsto \lett{x = E_2}{E_1}$} -\pause -{\small -\begin{equation*} - \begin{array}{rl} - g(g(g(2))) \pause &\mapsto \lett{x = g(g(2))}{x^2 + x}\pause \mapsto\\ - &\mapsto \lett{y=g(2)}{\lett{x=y^2+y}{x^2 + x}} \pause \mapsto\\ - &\mapsto \lett{z=2}{\lett{y=z^2+z}{\lett{x=y^2+y}{x^2 + x}}} \pause \mapsto\\ - &\mapsto \lett{y=6}{\lett{x = y^2+y}{x^2 + x}} \pause \mapsto\\ - &\mapsto \lett{x=42}{x^2 + x} \mapsto 1806 - \end{array} -\end{equation*}}\pause\vspace{-1.5em} -\begin{itemize}[<+->] -\item Избягва се повторението чрез споделяне на общи подизрази -\item Заместването се извършва чак когато е \alert{абсолютно наложително} -\end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Кога се налага оценяване на израз?} - - Във всеки даден момент Haskell оценява някой израз $s$. \pause - \begin{itemize}[<+->] - \item ако $s \equiv$ \lst{if} $e$ \lst{then} $e_1$ \lst{else} $e_2$ - \begin{itemize} - \item първо се оценява $e$ - \item ако оценката е \lst{True}, се преминава към оценката на $e_1$ - \item ако оценката е \lst{False}, се преминава към оценката на $e_2$ - \end{itemize} - \item ако $s \equiv \tt f\,e_1\,e_2\,\ldots\,e_n$, за \tt f --- $n$-местна примитивна функция: - \begin{itemize} - \item оценяват се последователно $e_1,\ldots,e_n$ - \item прилага се примитивната операция над оценките им - \end{itemize} - \item нека сега да допуснем, че $s \equiv \tt f\,e$ - \item първо се оценява \tt f, за да разберем как да продължим - \item ако $\tt f\,x_1\,\ldots\,x_n$ \tt| $g_1$ \tt= $t_1$ \ldots\ \tt| $g_k$ \tt= $t_k$ е дефинирана чрез пазачи: - \begin{itemize} - \item тогава \tt f се замества с израза:\\ - \tt{\textbackslash $x_1 \ldots\ x_n$ ->} \lst{if} $g_1$ \lst{then} $t_1$ \lst{else} \ldots\ \lst{if} $g_k$ \lst{then} $t_k$ \lst{else error "..."} - \end{itemize} - \item ако \tt f е конструктор (константа), \alert{оценката остава \tt f $e$} - \item ако \tt{f = \textbackslash $p$ -> $t$}, където $p$ е образец, редът на оценяване зависи от образеца! - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Кога се оценяват изразите при използване на образци?} - - Как се оценява \tt{(\textbackslash $p$ -> $t$) $e$}?\pause - \begin{itemize}[<+->] - \item ако $p \equiv c$ е константа - \begin{itemize} - \item преминава се към оценката на аргумента $e$ - \item ако се установи че оценката тя съвпада с константата $c$, преминава се към оценката на тялото $t$ - \end{itemize} - \item ако $p \equiv \tt\_$ е анонимният образец - \begin{itemize} - \item преминава се директно към оценката на $t$ \alert{без да се оценява $e$} - \end{itemize} - \item ако $p \equiv \tt x$ е променлива - \begin{itemize} - \item преминава се към оценка на израза $t$ \alert{като се въвежда локалната дефиниция \tt{x = $e$}} - \end{itemize} - \item ако \tt{$p \equiv\,$\tuple p} - \begin{itemize} - \item преминава се към оценката на $e$ - \item като се установи, че тя е от вида \tuple e, преминава се към оценката на израза \tt{(\textbackslash $p_1\,p_2\,\ldots\,p_n$ -> $t$) $e_1\,e_2\,\ldots\,e_n$} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Кога се оценяват изразите при използване на образци?} - - Как се оценява \tt{(\textbackslash $p$ -> $t$) $e$}?\pause - \begin{itemize}[<+->] - \item ако $p \equiv \tt(p_h\tt:p_t\tt)$ - \begin{itemize} - \item преминава се към оценката на $e$ - \item ако се установи, че тя е от вида $\tt(e_h\tt:e_t\tt)$, преминава се към оценката на израза \tt{(\textbackslash $p_h\;p_t$ -> $t$) $e_h\;e_t$} - \end{itemize} - \item ако $p \equiv $\hlist p - \begin{itemize} - \item преминава се към оценката на $e$ - \item ако се установи, че тя е от вида \hlist e, преминава се към оценката на израза \tt{(\textbackslash $p_1\;p_2\;\ldots\;p_n$ -> $t$) $e_1\;e_2\;\ldots\;e_n$} - \item всъщност е еквивалентно да разгледаме $p$ като $p_1\tt:p_2\tt:\ldots\tt:p_n$\tt{:[]} - \end{itemize} - \item ако има няколко равенства за $f$ с използване на различни образци, се търси кой образец пасва отгоре надолу - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Оценяване в Haskell: пример 1} - -\begin{lstlisting} -sumHeads (x:xs) (y:ys) = x + y -\end{lstlisting} -\pause -\begin{tabular}{rl} - &\tt{\underline{sumHeads} [1..10] [5..50]}\\\pause - \lra& \tt{(\textbackslash(x:xs) -> \textbackslash(y:ys) -> x + y) \underline{[1..10]} [5..50]}\\ - \lra& \tt{\underline{(\textbackslash(x:xs) -> \textbackslash(y:ys) -> x + y) (1:[2..10])} [5..50]}\\ - \lra& \tt{\lett{x=1; xs=[2..10]}{(\textbackslash(y:ys) -> x + y) \underline{[5..50]}}}\\ - \lra& \tt{\lett{x=1; xs=[2..10]}{\underline{(\textbackslash(y:ys) -> x + y) (5:[6..50])}}}\\ - \lra& \tt{\lett{x=1; xs=[2..10]; y=5; ys=[6..50]}{\underline x + \underline y}}\\ - \lra& \tt{\underline{1 + 5}} \lra\;\tt 6 -\end{tabular} -\end{frame} - -\begin{frame} - \frametitle{Оценяване в Haskell: пример 2} - - \small - \begin{tabular}{r@{ }l@{ }l} - &\multicolumn 2l{\tt{(filter isPrime [4..1000]) \underline{!!} 1}}\\\pause - \lra&\multicolumn 2l{\tt{(\textbackslash(\_:xs) n -> xs !! (n-1)) \underline{(filter isPrime [4..1000])} 1}}\\ - \lra&\multicolumn 2l{\tt{(\textbackslash(\_:xs) n -> xs !! (n-1)) (\underline{filter} isPrime [4..1000]) 1}}\\ - \lra&\ldots\tt{\underline{(\textbackslash p (z:zs) ->}}&\underline{\tt{if p z then z:filter p zs}}\\ - &&\tt{\underline{else filter p zs) isPrime} [4..1000]}\ldots\\ - \lra&\ldots\tt{\lett{p=isPrime}{}}&\tt{(\textbackslash (z:zs) -> if p z then z:filter p zs}\\ - &&\tt{else filter p zs) \underline{[4..1000]}}\ldots\\ - \lra&\ldots\tt{\lett{p=isPrime}{}}&\underline{\tt{(\textbackslash (z:zs) -> if p z then z:filter p zs}}\\ - &&\underline{\tt{else filter p zs) (4:[5..1000]))}}\ldots\\ - \lra&\multicolumn 2{@{}l}{\ldots\tt{\lett{p=isPrime; z=4; zs=[5..1000]}{}}}\\ - &\multicolumn 2{@{}l}{\tt{if \underline{p z} then z:filter p zs else filter p zs}\ldots}\\ - \lra&\multicolumn 2{@{}l}{\ldots\tt{\lett{p=isPrime; z=4; zs=[5..1000]}{}}}\\ - &\multicolumn 2{@{}l}{\tt{if False then z:filter p zs else \underline{filter p zs}}\ldots}\\ - \end{tabular} -\end{frame} - -\begin{frame} - \frametitle{Оценяване в Haskell: пример 2} - - \small - \begin{tabular}{r@{ }l@{ }l} - \lra&\ldots\tt{\underline{(\textbackslash p (z:zs) ->}}&\underline{\tt{if p z then z:filter p zs}}\\ - &&\tt{\underline{else filter p zs) isPrime} [5..1000]}\ldots\\ - \lra&\ldots\tt{\lett{p=isPrime}{}}&\underline{\tt{(\textbackslash (z:zs) -> if p z then z:filter p zs}}\\ - &&\underline{\tt{else filter p zs) (5:[6..1000])}}\ldots\\ - \lra&\multicolumn 2{@{}l}{\tt{\ldots \lett{p=isPrime; z=5; zs=[6..1000]}{}}}\\ - &\multicolumn 2{@{}l}{\tt{if \underline{p z} then z:filter p zs else filter p zs}\ldots}\\ - \lra&\multicolumn 2{@{}l}{\tt{\ldots \lett{p=isPrime; z=5; zs=[6..1000]}{}}}\\ - &\multicolumn 2{@{}l}{\tt{if True then \underline{z:filter p zs} else filter p zs}\ldots}\\ - \lra&\multicolumn 2{@{}l}{\tt{\underline{(\textbackslash(\_:xs) n -> xs !! (n-1)) (5:filter isPrime [6..1000])} 1}}\\ - \lra&\multicolumn 2{@{}l}{\tt{\lett{xs=filter isPrime [6..1000]}{}}\underline{\tt{(\textbackslash n -> xs !! (n-1)) 1}}}\\ - \lra&\multicolumn 2{@{}l}{\tt{\lett{xs=filter isPrime [6..1000]; n=1}{xs \underline{!!} (n-1)}}}\\ - \lra&\multicolumn 2{@{}l}{\tt{\underline{(\textbackslash (y:\_) 0 -> y) (filter isPrime [6..1000])} 0}} - \end{tabular} -\end{frame} - -\begin{frame} - \frametitle{Оценяване в Haskell: пример 2} - -\small -\begin{tabular}{r@{ }l@{ }l} - \lra&\ldots\tt{\underline{(\textbackslash p (z:zs) ->}}&\underline{\tt{if p z then z:filter p zs}}\\ - &&\tt{\underline{else filter p zs) isPrime} [6..1000]}\ldots\\ - \lra&\ldots\tt{\lett{p=isPrime}{}}&\underline{\tt{(\textbackslash (z:zs) -> if p z then z:filter p zs}}\\ - &&\underline{\tt{else filter p zs) (6:[7..1000])}}\ldots\\ - \lra&\multicolumn 2{@{}l}{\ldots\tt{\lett{p=isPrime; z=6; zs=[7..1000]}{}}}\\ - &\multicolumn 2{@{}l}{\tt{if \underline{p z} then z:filter p zs else filter p zs}\ldots}\\ - \lra&\multicolumn 2{@{}l}{\ldots\tt{\lett{p=isPrime; z=6; zs=[7..1000]}{}}}\\ - &\multicolumn 2{@{}l}{\tt{if False then z:filter p zs else \underline{filter p zs}}\ldots}\\ - \lra&\ldots\tt{\underline{(\textbackslash p (z:zs) ->}}&\underline{\tt{if p z then z:filter p zs}}\\ - &&\tt{\underline{else filter p zs) isPrime} [7..1000]}\ldots\\ - \lra&\ldots\tt{\lett{p=isPrime}{}}&\underline{\tt{(\textbackslash (z:zs) -> if p z then z:filter p zs}}\\ - &&\underline{\tt{else filter p zs) (7:[8..1000])}}\ldots\\ - \lra&\multicolumn 2{@{}l}{\ldots\tt{\lett{p=isPrime; z=7; zs=[8..1000]}{}}}\\ - &\multicolumn 2{@{}l}{\tt{if \underline{p z} then z:filter p zs else filter p zs}\ldots} -\end{tabular} -\end{frame} - -\begin{frame} - \frametitle{Оценяване в Haskell: пример 2} - -\begin{tabular}{r@{ }l@{ }l} - \lra&\multicolumn 2{@{}l}{\ldots\tt{\lett{p=isPrime; z=7; zs=[8..1000]}{}}}\\ - &\multicolumn 2{@{}l}{\tt{if True then \underline{z:filter p zs} else filter p zs} \ldots}\\ - \lra&\multicolumn 2{@{}l}{\underline{\tt{(\textbackslash (y:\_) 0 -> y) (7:filter isPrime [8..1000]) 0}}}\\ - \lra&\multicolumn 2{@{}l}{\tt{\lett{y=7}y}}\\ - \lra&\tt 7 -\end{tabular} -\end{frame} - -\section{Потоци} - -\begin{frame} - \frametitle{Потоци в Haskell} - - \begin{itemize}[<+->] - \item Можем да си мислим, че аргументите в Haskell са \textbf{обещания}, които се изпълняват при нужда - \item В частност, \tt{x:xs = (:) x xs}, където - \begin{itemize} - \item \tt x е обещание за глава - \item \tt{xs} е обещание за опашка - \end{itemize} - \item \alert{списъците в Haskell всъщност са потоци!} - \item можем да работим с безкрайни списъци - \begin{itemize} - \item \tt{ones = 1 : ones} - \item \evalstoinf{length ones} - \item \evalsto{take 5 ones}{[1,1,1,1,1]} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Генериране на безкрайни списъци} - - \begin{itemize} - \item \tta[$a$\tta{..}\tta] $\rightarrow$ \tta[$a$\tta, $a+1$\tta, $a+2$\tta,\ldots\tta] - \item \textbf{Примери:} - \begin{itemize} - \item \tt{nats = [0..]} - \item \evalsto{take 5 [0..]}{[0,1,2,3,4]} - \item \evalsto{take 26 ['a'..]}{\ "abcdefghijklmnopqrstuvwxyz"} - \end{itemize} - \item Синтактична захар за \tt{enumFrom from} - \pause - \item \tta[$a$\tta, $a+\Delta x$ \tta{..}\tta] $\rightarrow$ \tta[$a$\tta, $a+\Delta x$\tta, $a + 2\Delta x$\tta, \ldots \tta] - \item \textbf{Примери:} - \begin{itemize} - \item \tt{evens = [0,2..]} - \item \evalsto{take 5 evens}{[0,2,4,6,8]} - \item \evalsto{take 7 ['a','e'..]}{\ "aeimquy"} - \end{itemize} - \item Синтактична захар за \tt{enumFromThen from then} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Генериране на безкрайни списъци} - - \begin{itemize}[<+->] - \item \lst{repeat :: a -> [a]} - \begin{itemize} - \item създава безкрайния списък \lst{[x,x,...]} - \item \lst{repeat x = [x,x..]} - \item \lst{repeat x = x : repeat x} - \item \lst{replicate n x = take n (repeat x)} - \end{itemize} - \item \lst{cycle :: [a] -> [a]} - \begin{itemize} - \item \evalsto{cycle [1,2,3]}{[1,2,3,1,2,3,...]} - \item \lst{cycle l = l ++ cycle l} - \item създава безкраен списък повтаряйки подадения (краен) списък - \end{itemize} - \item \lst{iterate :: (a -> a) -> a -> [a]} - \begin{itemize} - \item \lst{iterate f z} създава безкрайния списък \lst{[z,f(z),f(f(z)),...]} - \item \lst{iterate f z = z : iterate f (f z)} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Отделяне на безкрайни списъци} - - \begin{overlayarea}{\textwidth}{15em} - Отделянето на списъци работи и за безкрайни списъци.\pause - \begin{itemize}[<+->] - \item \tt{oddSquares = \rvl{[ x\^{}2 | x <- [1,3..] ]}} - \item {\small\tt{twins = \rvl{[ (x,x+2) | x <- [3,5..], isPrime x, isPrime - (x+2) ]}}} - \item \tt{pairs = \rvl{[ (x,y) | x <- [0..], y <- [0..x - 1] ]}} - \item \tt{pythagoreanTriples = \rvl{ - \begin{tabular}[t]{ll} - [ (a,b,c) | &c <- [1..],\\ - &b <- [1..c-1],\\ - &a <- [1..b-1],\\ - &a\^{}2 + b\^{}2 == c\^{}2,\\ - &gcd a b == 1] - \end{tabular}}} - \end{itemize} - \end{overlayarea} -\end{frame} - - - -\begin{frame} - \frametitle{Функции от по-висок ред над безкрайни списъци} - - Повечето функции от по-висок ред работят и над безкрайни списъци! - \begin{itemize}[<+->] - \item \lst{powers2 = 1 : map (*2) powers2} - \item \lst{notdiv k = filter (\\x -> x `mod` k > 0) [1..]} - \item \lst{fibs = 0:1:zipWith (+) fibs (tail fibs)} - \item \evalstop{foldr (+) 0 [1..]}{...} - \begin{itemize} - \item \alert{Внимание:} \lst{foldr} не работи над безкрайни списъци с операции, които изискват оценка на десния си аргумент! - \item \lst{triplets = iterate (map (+3)) [3,2,1]} - \item \evalsto{take 3 triplets}{[[3,2,1],[6,5,4],[9,8,7]]} - \item \evalstop{take 5 (foldr (++) [] triplets)}{[3,2,1,6,5]} - \item \evalstop{take 5 (foldl (++) [] triplets)}{...} - \item \alert{\lst{foldl} не може да работи с безкрайни списъци!} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{io}>[fragile] - \frametitle{Ленив вход и изход} - - \begin{itemize}[<+->] - \item Ленивото оценяване в Haskell ни позволява да работим с входно/изходни потоци - \item \lst{getContents :: IO String} --- връща списък от \alert{всички} символи на стандартния вход - \item списъкът се оценява лениво, т.е. прочита се при нужда - \item \textbf{Пример:} -\begin{lstlisting} -noSpaces = do text <- getContents - putStr $ filter (/=' ') text -\end{lstlisting} - \item \lst{interact :: (String -> String) -> IO ()} --- лениво прилага функция над низове над стандартния вход и извежда резултата на стандартния изход - \item \textbf{Пример:} -\begin{lstlisting} -noSpaces = interact $ filter (/=' ') -\end{lstlisting} - \end{itemize} -\end{frame} - -\section{Безточково програмиране} - -\begin{frame} - \frametitle{Апликация} - - \begin{itemize}[<+->] - \item Операцията „апликация“ се дефинира с \lst{f $ x = f x} - \item За какво може да бъде полезна? - \item Операцията \lst{$} е с най-нисък приоритет и е дясноасоциативна - \begin{itemize} - \item за разлика от прилагането на функции, което е с най-висок приоритет и лявоасоциативно - \end{itemize} - \item Може да бъде използвана за спестяване на скоби вложени надясно - \item \tt(\ldots\tt{((f} $x_1$\tt) $x_2$\tt) \ldots $x_n$\tt) = \tt f $x_1$ $x_2$ \ldots $x_n$ - \item $f_1$ \tt($f_2$ \ldots \tt($f_n$ \tt{x)}\ldots\tt) = $f_1$ \tt\$ $f_2$ \tt\$ \ldots \tt\$ $f_n$ \tt{\$ x} - \item \textbf{Примери:} - \begin{itemize} - \item \alt<+->{\lst{head $ tail $ take 5 $ drop 7 $ l}}{\lst{head (tail (take 5 (drop 7 l)))}} - \item \alt<+->{\lst{sum $ map (^2) $ filter odd $ [1..10]}}{\lst{sum (map (^2) (filter odd [1..10]))}} - \item \evalstop{map ($2) [(+2),(3^),(*5)]}{[4,9,10]} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Композиция} - - \begin{itemize}[<+->] - \item \lst{(f . g) x = f (g x)} --- операция „композиция“ - \item с най-висок приоритет, дясноасоциативна - \item Може да бъде използвана за спестяване на скоби вложени надясно - \item $f_1$ \tt($f_2$ \ldots \tt($f_n$ \tt{x)}\ldots\tt) = $f_1$ \tt. $f_2$ \tt. \ldots \tt. $f_n$ \tt{\$ x} - \item \textbf{Примери:} - \begin{itemize} - \item \alt<+->{\lst{sublist n m = take m . drop n}}{\lst{sublist n m l = take m (drop n l)}} - \item \alt<+->{\lst{sumOddSquares = sum . map (^2) . filter odd}}{\lst{sumOddSquares l = sum (map (\^2) (filter odd l))}} - \item \lst{repeated n f x = foldr (\$) x (replicate n f)} - \item \lst{repeated n f = foldr (.) id (replicate n f)} - \item \lst{repeated n f = foldr (.) id ((replicate n) f)} - \item \lst{repeated n = foldr (.) id . replicate n} - \item \lst{repeated n = (foldr (.) id .) (replicate n)} - \item \lst{repeated = (foldr (.) id .) . replicate} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{pointfree}> - \frametitle{Безточково (point-free) програмиране} - - С помощта на операциите \tt{\$} и \tt. можем да дефинираме функции чрез директно използване на други функции.\\\pause - Този стил се нарича \textbf{безточково програмиране}.\\\pause - \textbf{Пример 1:} - \begin{itemize}[<+->] - \small - \item \lst{g l = filter (\\f -> f 2 > 3) l} - \item \lst{g = filter (\\f -> (f \$ 2) > 3)} - \item \lst{g = filter (\\f -> (>3) (($2) f))} - \item \lst{g = filter $ (>3) . ($2)} - \end{itemize} - \onslide<+-> - \textbf{Пример 2:} - \begin{itemize}[<+->] - \footnotesize - \item \lst{split3 ll = map (\\x -> map (\\f -> filter f x) [(<0),(==0),(>0)]) ll} - \item \lst{split3 = map (\\x -> map (\\f -> flip filter x f) [(<0),(==0),(>0)])} - \item \lst{split3 = map (\\x -> map (flip filter x) [(<0),(==0),(>0)])} - \item \lst{split3 = map (\\x -> flip map [(<0),(==0),(>0)] (flip filter x))} - \item \lst{split3 = map (flip map [(<0),(==0),(>0)] . flip filter)} - \item \lst{split3 = map $ flip map [(<0),(==0),(>0)] . flip filter} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{pointfree}> - \frametitle{Безточково (point-free) програмиране} - \textbf{Пример 3:} - \begin{itemize}[<+->] - \small - \item \lst{checkMatrix k m = all (\\r -> any (\\x -> mod k x > 0) r) m} - \item \lst{checkMatrix k = all (\\r -> any (\\x -> mod k x > 0) r)} - \item \lst{checkMatrix k = all (any (\\x -> mod k x > 0))} - \item \lst{checkMatrix k = all (any (\\x -> (>0) ((mod k) x)))} - \item \lst{checkMatrix k = all (any ((>0) . (mod k)))} - \item \lst{checkMatrix k = all (any (((>0) .) (mod k)))} - \item \lst{checkMatrix = all . any . ((>0) .) . mod} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{pointfree}> - \frametitle{Безточково (point-free) програмиране} - - Можем да използваме още следните функции от \lst{Control.Monad}: - \begin{itemize}[<+->] - \item \lst{curry f x y = f (x,y)} - \item \lst{uncurry f (x,y) = f x y} - \item \lst{join f x = f x x} - \item \lst{ap f g x = f x (g x)} - \begin{itemize} - \item \lst{join f = ap f id} - \item \lst{join = (`ap` id)} - \end{itemize} - \item \lst{(f >>= g) x = g (f x) x} - \begin{itemize} - \item \lst{g =<< f = f >>= g} - \item \lst{f >>= g = ap (flip g) f} - \end{itemize} - \item \lst{liftM2 f g h x = f (g x) (h x)} - \begin{itemize} - \item \lst{ap f = liftM2 f id} - \item \lst{ap = (`liftM2` id)} - \end{itemize} - \end{itemize} -\end{frame} - - -\begin{frame}<\switch{pointfree}> - \frametitle{Безточково (point-free) програмиране} - \textbf{Пример 4:} - \begin{itemize}[<+->] - \item \lst{sorted l = all (\\(x,y) -> x <= y) (zip l (tail l))} - \item \lst{sorted l = all (\\(x,y) -> (<=) x y) (ap zip tail l)} - \item \lst{sorted l = all (uncurry (<=)) (ap zip tail l)} - \item \lst{sorted = all (uncurry (<=)) . ap zip tail} - \item \lst{sorted = all (uncurry (>=)) . (zip =<< tail)} - \end{itemize} - \onslide<+-> - \textbf{Пример 5:} - \begin{itemize}[<+->] - \item \lst{minsAndMaxs m = map (\\r -> (minimum r, maximum r)) m} - \item \lst{minsAndMaxs = map (\\r -> (minimum r, maximum r))} - \item \lst{minsAndMaxs = map (\\r -> (,) (minimum r) (maximum r))} - \item \lst{minsAndMaxs = map (liftM2 (,) minimum maximum)} - \item \lst{minsAndMaxs = map \$ liftM2 (,) minimum maximum} - \end{itemize} -\end{frame} - -\section{Стриктно оценяване} - -\begin{frame} - \frametitle{Разходване на памет при лениво оценяване} - - Ленивото оценяване може да доведе до голям разход на памет.\\[1em]\pause - В Scheme: - \lstset{language=Scheme} - \begin{itemize}[<+->] - \item \lst{(define (f x) (f (- 1 x)))} - \item \evalstops{\tt{(f 0)}}{\textsf{забива, но не изразходва памет}} - \item \tt f е \textbf{опашково-рекурсивна} и се реализира чрез итерация - \item \evalstos{\tt{(f 0)}}{\evalstos{\tt{(f 1)}}{\evalstos{\tt{(f 0)}}{\evalstos{\tt{(f 1)}}{...}}}} - \end{itemize} - \onslide<+-> - В Haskell: - \lstset{language=Haskell} - \begin{itemize}[<+->] - \item \lst{f x = f (1-x)} - \item \evalstops{\tt{f 0}}{\textsf{\alert{забива с изтичане на памет!}}} - \item \evalstos{\tt{f 0}}{\evalstos{\tt{f (1-0)}}{\evalstos{\tt{f (1-(1-0))}}{\evalstos{\tt{f (1-(1-(1-0)))}{...}}}}} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Стриктно оценяване в Haskell} - - \begin{itemize}[<+->] - \item в Haskell може да изискаме даден израз да се оцени веднага - \item еквивалентно на форсиране на обещание - \item \lst{seq :: a -> b -> b} - \item оценява първия си аргумент и връща втория като резултат - \item \textbf{Примери:} - \begin{itemize} - \item \lst{second _ y = y} - \item \evalsto{second (10^10^10) 2}{2} - \item \lst{seq (10^10^10) 2} $\xrightarrow{\hspace{35ex}}$ \tt2 - \item \lst{f x = seq x (f (1-x))} - \item \evalstops{\tt{f 0}}{\textsf{забива, но не изразходва памет!}} - \end{itemize} - \item \tt{f \$! x = seq x \alt<+->{\$ f x}{(f x)}} - \begin{itemize} - \item първо оценява \tt x и след това прилага \tt f над оценката на \tt x - \item прилага \tt f над \tt x със стриктно оценяване - \item \lst^f x = f \$! (1-x)^ - \item \lst^(\$!) = ap seq^ - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Изразходване на памет при \tt{foldl}} - - \begin{tabular}{rl} - &\lst{foldl (+) 0 [1..4]}\\ - \pause - \lra&\lst{foldl (+) (0 + 1) [2..4]}\\ - \lra&\lst{foldl (+) ((0 + 1) + 2) [3..4]}\\ - \lra&\lst{foldl (+) (((0 + 1) + 2) + 3) [4..4]}\\ - \lra&\lst{foldl (+) ((((0 + 1) + 2) + 3) + 4) []}\\ - \lra&\lst{((((0 + 1) + 2) + 3) + 4)}\\ - \lra&\lst{(((1 + 2) + 3) + 4)}\\ - \lra&\lst{((3 + 3) + 4)}\\ - \lra&\lst{(6 + 4)}\\ - \lra&\lst{10} - \end{tabular}\\[2em] - \onslide<+-> - \alert{Проблем:} Изразходва памет при оценяване, понеже отлага изчисления! -\end{frame} - -\begin{frame}[fragile] - \frametitle{Стриктен вариант на \tt{foldl}} - - \onslide<+-> -\begin{lstlisting} -foldl' _ nv [] = nv -foldl' op nv (x:xs) = (foldl' op $! op nv x) xs -\end{lstlisting} - \onslide<+-> - \begin{tabular}{rl} - &\tt{foldl' (+) 0 [1..4]}\\ - \lra&\tt{foldl' (+) 1 [2..4]}\\ - \lra&\tt{foldl' (+) 3 [3..4]}\\ - \lra&\tt{foldl' (+) 6 [4..4]}\\ - \lra&\tt{foldl' (+) 10 []}\\ - \lra&\tt{10} - \end{tabular} -\end{frame} - -\end{document} diff --git a/2.5-haskell_data.tex b/2.5-haskell_data.tex deleted file mode 100644 index 6101ff2..0000000 --- a/2.5-haskell_data.tex +++ /dev/null @@ -1,616 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -\title{Типове и класове в Haskell} - -\date{4 декември 2024 г.} - -\lstset{language=Haskell,style=Haskell} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section{Полиморфизъм} - -\begin{frame} - \frametitle{Видове полиморфизъм в Haskell} - - В Haskell има два основни вида полиморфизъм. - \begin{itemize}[<+->] - \item \alert{параметричен полиморфизъм} --- възможност да създаваме конструкции, които обработват елементи от различни типове по \alert{универсален} начин - \begin{itemize} - \item такива конструкции наричаме \textbf{генерични (generic)} - \item параметризират се с \textbf{типови променливи}, които могат да приемат произволен тип за стойност - \end{itemize} - \item \alert{ad hoc полиморфизъм} --- възможност да създаваме конструкции, които обработват елементи от различни типове по \alert{специфичен} начин - \begin{itemize} - \item такива конструкции наричаме \textbf{претоварени (overloaded)} - \item налагат механизъм за \textbf{разпределение (dispatch)}, който определя коя специфична реализация на конструкцията трябва да се използва в конкретен случай - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Параметричен полиморфизъм} - - Генеричните конструкции в Haskell са два вида: - \begin{itemize}[<+->] - \item \alert{генерични типове}, конструирани чрез използване на типови променливи - \begin{itemize} - \item функциите, кортежите и списъците могат да генерични - \item \lst{type UnaryFunction a = a -> a} - \item \lst{type Matrix a = [[a]]} - \item \lst{type Dictionary k v = [(k, v)]} - \end{itemize} - \item \alert{генерични функции}, при които една и съща имплементация работи за различни типове - \begin{itemize} - \item \lst{length :: [a] -> Integer} - \item \lst{map :: (a -> b) -> [a] -> [b]} - \item \lst{repeated :: Integer -> UnaryFunction a -> UnaryFunction a} - \item \lst{transpose :: Matrix a -> Matrix a} - \item \lst{keys :: Dictionary k v -> [k]} - \item \lst{[] :: [a]} - \begin{itemize} - \item константите са частен случай на функции (функции без параметри) - \end{itemize} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Ad hoc полиморфизъм} - - В Haskell имаме претоварени константи, операции и функции: - \begin{itemize}[<+->] - \item \alert{претоварени константи} - \begin{itemize} - \item \tt5 може да означава цяло, дробно или комплексно число, в зависимост от контекста - \item \tt{5.0} може да означава рационално число, число с плаваща запетая или комплексно число - \item \tt{maxBound} е максималната стойност на ограничени типове - \end{itemize} - \item \alert{претоварени операции} - \begin{itemize} - \item \tt+ може да събира цели, дробни, или комплексни числа - \item \tt/ може да дели рационални, дробни или комплексни числа - \item \tt{==} може да сравнява числа, символи, кортежи или списъци - \end{itemize} - \item \alert{претоварени функции} - \begin{itemize} - \item \tt{elem} може да търси елемент в списък от сравними елементи - \item \tt{show} може да извежда елемент, който има низово представяне - \item \tt{[from..to]} може да генерира списък от последователни елементи от тип, в който имаме операции за следващ и предишен елемент - \end{itemize} - \end{itemize} -\end{frame} - -\section{Класове от типове} - -\begin{frame} - \frametitle{Класове от типове (typeclasses)} - - \begin{definition} - \textbf{Клас от типове} наричаме множество от типове, които поддържат определен тип поведение, зададено чрез множество от имена на функции и техните типове. \pause Функциите на даден клас наричаме \textbf{методи}. - \end{definition} - \pause - Класовете от типове дават структуриран подход към ad hoc полиморфизма.\\ - \pause - \textbf{Примери:} - \begin{itemize}[<+->] - \item \lst{Eq} е класът от типове, които поддържат сравнение - \item \lst{Ord} е класът от типове, които поддържат линейна наредба - \item \lst{Show} е класът от типове, чиито елементи могат да бъдат - извеждани в низ - \item \lst{Num} е класът на всички числови типове - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Дефиниране на класове от типове} - \tta{class} <клас> <типова-променлива>\tta{ where}\\ - \hspace{1em}\{<метод>\{,<метод>\} \tta{::} <тип>\}\\ - \hspace{1em}\{<метод> \tta{=} <реализация-по-подразбиране>\}\\[3ex] - \pause - \textbf{Примери:}\\ -\begin{lstlisting} -class Eq a where - (==), (/=) :: a -> a -> Bool - x /= y = not (x == y) - x == y = not (x /= y) -\end{lstlisting} -\pause -\begin{lstlisting} -class Measurable a where - size :: a -> Integer - empty :: a -> Bool - empty x = size x == 0 -\end{lstlisting} -\end{frame} - -\begin{frame} - \frametitle{Класови ограничения} - \begin{definition} - Ако \tt{C} e клас, а \tt{t} е типова променлива, то \tt{C t} наричаме \textbf{класово ограничение}. \pause Множество от класови ограничения наричаме \textbf{контекст}. - \end{definition} - \pause - Класовите ограничения ни дават възможност да дефинираме претоварени функции.\\[2ex] - \pause - \textbf{Примери:} - \begin{itemize}[<+->] - \item \lst{elem :: Eq a => a -> [a] -> Bool} - \item \lst{maximum :: Ord a => [a] -> a} - \item \lst{(^) :: (Integral b, Num a) => a -> b -> a} - \item \lst{larger :: Measurable a => a -> a -> Bool} - \item<.-> \lst{larger x y = size x > size y} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Дефиниране на екземпляри на клас} - \begin{definition} - \textbf{Екземпляр} (инстанция) на клас е тип, за който са дефинирани методите на класа. - \end{definition} - \pause - \tta{instance} <клас> <тип> \tta{where}\\ - \hspace{1em} \{<дефиниция-на-метод>\}\\[1ex] - \pause - \textbf{Примери:}% - \vspace{-1ex} -\begin{lstlisting} -instance Eq Bool where - True == True = True - False == False = True - _ == _ = False -\end{lstlisting}\pause% -\begin{lstlisting} -instance Measurable Integer where - size 0 = 0 - size n = 1 + size (n `div` 10) -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Екземпляри с контекст} - Можем да добавяме контекст в дефиницията за екземпляри:\\ - \tta{instance} [<контекст> \tta{=>}] <клас> <тип> \tta{where}\\ - \hspace{1em} \{<дефиниция-на-метод>\}\\[2ex] - \pause - \textbf{Примери:} -\small -\begin{lstlisting} -instance (Eq a, Eq b) => Eq (a,b) where - (x,y) == (u,t) = x == u && y == t -\end{lstlisting} - \pause -\begin{lstlisting} -instance (Measurable a, Measurable b) => Measurable (a,b) where - size (x,y) = size x + size y -\end{lstlisting} - \pause -\begin{lstlisting} -instance Measurable a => Measurable [a] where - size = sum . map size -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Наследяване} - Можем да дефинираме клас \tt{B}, който допълва методите на вече съществуващ клас \tt{A}.\\ - Тогава казваме, че: - \begin{itemize}[<+->] - \item Класът \tt{B} \textbf{наследява} (разширява) класа \tt{A} - \item Класът \tt{B} е \textbf{подклас} (производен клас, subclass) на класа \tt{A} - \item Класът \tt{A} е \textbf{надклас} (родителски клас, superclass) на класа \tt{B} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Пример: Стандартен клас Ord} -\lstsmall -\begin{lstlisting} -class Eq a => Ord a where - (<), (<=), (>=), (>) :: a -> a -> Bool - max, min :: a -> a -> a - compare :: a -> a -> Ordering - compare x y - | x == y = EQ - | x < y = LT - | otherwise = GT - x < y = compare x y == LT - x > y = compare x y == GT - x == y = compare x y == EQ - x <= y = compare x y /= GT - x >= y = compare x y /= LT - max x y = if x > y then x else y - min x y = if x < y then x else y -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Множествено наследяване} - Даден клас може да наследява едновременно няколко родителски класа.\\[2ex] - \textbf{Примери:} -\begin{lstlisting} -class (Ord a, Num a) => Real a where - ... -\end{lstlisting} -\pause -\begin{lstlisting} -class (Ord a, Measurable a) => OrdMeasurable a where - sortByOrder, sortBySize :: [a] -> [a] -\end{lstlisting} -\end{frame} - -\begin{frame} - \frametitle{Сравнение на Haskell с други обектно-ориентирани езици} - \begin{itemize}[<+->] - \item Класовете в Haskell съответстват на \alert{абстрактни класове или интерфейси} - \item Методите в Haskell съответстват на \alert{чисти виртуални функции} - \item Класовете и обектите в C++ \alert{нямат директен еквивалент в Haskell} - \begin{itemize} - \item В Haskell данните винаги са разделени от методите - \item Няма ограничения на достъпа (public, private) - \item Няма понятие за разширяване на тип данни, само на интерфейс - \item Съответно, няма \alert{подтипов полиморфизъм} - \end{itemize} - \item Екземплярите съответстват на \alert{имплементиране (наследяване) на интерфейси} - \begin{itemize} - \item В C++ и Java то може да бъде и множествено - \end{itemize} - \item В Haskell претоварените функции имат \alert{еднозначно определен тип} - \begin{itemize} - \item В C++ сме свободни да пишем функции с едно и също име и различни сигнатури - \item В Haskell сме длъжни да наложим класови ограничения - \end{itemize} - \item В Haskell не можем да правим насилствено преобразуване на тип към даден клас (casting) - \end{itemize} -\end{frame} - -\section{Алгебрични типове} - -\begin{frame} - \frametitle{Потребителски дефинирани типове} - В Haskell имаме възможност да дефинираме нови типове данни.\\[2ex] - \begin{itemize}[<+->] - \item \tta{data} <тип> [<параметри>] \tta= <дефиниция> - \item{} <тип> трябва да започва с главна буква - \item{} <параметри> е списък от различни типови променливи - \item{} <дефиниция> ::= <елемент> \{ \tta| <елемент> \} - \begin{itemize} - \item{} <дефиниция> описва различните варианти за елементи на типа - \end{itemize} - \item{} <елемент> ::= <конструктор> \{ <тип-на-параметър> \} - \begin{itemize} - \item всеки вариант за елемент на типа се описва с уникален <конструктор> - \item{} <конструктор> трябва да започва с главна буква - \item{} <конструктор> може да има произволен брой параметри, чиито типове се задават в дефиницията - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Изброени типове} - Най-простият вид потребителски дефинирани типове са \alert{изброените типове}.\\[2ex] - \pause - \textbf{Примери:} - \begin{itemize}[<+->] - \item \lst{data Bool = False | True} - \item \lst{data Compare = LT | EQ | GT} - \item \lst{data Weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun} - \item \lst{today :: Weekday} - \item<.-> \lst{today = Tue} - \item \lst{isWeekend :: Weekday -> Bool} - \item<.-> \lst{isWeekend Sat = True} - \item<.-> \lst{isWeekend Sun = True} - \item<.-> \lst{isWeekend _ = False} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Записи} - Друга възможност за потребителски дефинирани типове са \alert{записите}.\\ - \pause - \begin{itemize}[<+->] - \item \lst{type Name = String} - \item<.-> \lst{type Score = Int} - \item<.-> \lst{data Player = Player Name Score} - \begin{itemize} - \item Да, името на типа може да съвпада с името на (единствения) конструктор - \end{itemize} - \item \lst{katniss :: Player} - \item<.-> \lst{katniss = Player "Katniss Everdeen" 45} - \item \lst{getName :: Player -> Name} - \item<.-> \lst{getName (Player name _) = name} - \item \lst{better :: Player -> Player -> Name} - \begin{lstlisting} -better (Player name1 score1) (Player name2 score2) - | score1 > score2 = name1 - | otherwise = name2 - \end{lstlisting} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Записи с полета} - \begin{itemize}[<+->] - \item По същество записите са еквивалентни на кортежите... - \item ...които по същество са декартово произведение на типове - \item Би било удобно, ако имахме имена на всяко от полетата - \item В Haskell има специален синтаксис: - \item<.-> \tta{\{} <поле>\{, <поле>\}\tta{::}<тип> \{, <поле>\{, <поле>\}\tta{::}<тип> \}\tta{\}} - \item за всяко от полетата автоматично се дефинира функция селектор - \item \textbf{Пример:} - \begin{itemize} - \item \lst!data Player = Player { name :: Name, score :: Score }! - \item \lst{name :: Player -> Name} - \item<.-> \lst{score :: Player -> Score} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Алтернативи} - Можем да дефинираме типове, които обединяват няколко други типа.\\ - \pause - \textbf{Примери:} - \begin{itemize}[<+->] - \item \lst!data Shape = Circle { radius :: Double } !\\ - \hspace{4em}\lst!| Rectangle { width, height :: Double }! - \item \lst{circle :: Shape} - \item<.-> \lst{circle = Circle 2.3} - \item \lst{rect :: Shape} - \item<.-> \lst{rect = Rectangle 3.5 1.8} - \item \lst{area :: Shape -> Double} - \item \lst{area (Circle r) = pi * r^2} - \item<.-> \lst{area (Rectangle w h) = w * h} - \item \lst{enlarge :: Shape -> Shape} - \item \lst{enlarge (Circle r) = Circle (2*r)} - \item<.-> \lst{enlarge (Rectangle w h) = Rectangle (2*w) (2*h)} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Автоматични екземпляри на класове} - - При работа с алгебрични типове се сблъскваме с един недостатък:\pause - \begin{itemize}[<+->] - \item \evalstoerrp{Circle 2.3 == Circle 4.5} - \item \evalstop{circle}{circle :: Shape} - \item \evalstoerrp{[Mon..Fri]} - \item \evalstoerrp{Thu < Sat} - \end{itemize} - \onslide<+-> - За използването на тези елементарни операции се налага ръчно да пишем тривиални екземпляри за класове като \lst{Eq}, \lst{Ord}, \lst{Enum}, \lst{Show}: - \onslide<+-> - \small -\begin{lstlisting} -instance Eq Shape where - Circle x == Circle y = x == y - Rectangle a b == Rectangle c d = (a,b) == (c,d) - _ == _ = False -\end{lstlisting} - \onslide<+-> -\begin{lstlisting} -instance Show Shape where - show (Circle x) = "Circle " ++ show x - show (Rectangle a b) = "Rectangle " ++ show a ++ " " ++ show b -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Автоматични екземпляри на класове} - - Haskell има възможност за автоматично извеждане на екземпляри на класовете \lst{Eq}, \lst{Ord}, \lst{Enum}, \lst{Show}, \lst{Read}.\pause - \small - \begin{itemize}[<+->] - \item \tta{data} <тип> [<параметри>] \tta= <дефиниция> \tta{deriving} <класове> - \item{} <класове> е кортеж от стандартни класове, екземпляри за които искаме автоматично да бъдат изведени - \item \lst{data Weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun}\\ - \hspace{5em}\lst{deriving (Eq, Ord, Enum, Show, Read)} - \item \lst{Eq}: два елемента се считат равни, ако имат равни конструктори с равни параметри - \item \lst{Ord}: елементите се сравняват лексикографски, като конструкторите се считат наредени в реда, в който са дефинирани - \item \lst{Enum}: позволено само за изброени типове - \item \lst{Show}, \lst{Read}: извежда се/въвежда се конструкторът и след това всеки един от параметрите му - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Параметризирани типове} - Потребителските типове могат да бъдат \alert{генерични}, т.е. да зависят от типови параметри.\\ - \pause - \textbf{Примери:} - \begin{itemize}[<+->] - \item \lst{data Maybe a = Nothing | Just a}\\ - \hspace{5em}\lst{deriving (Eq, Ord, Show, Read)} - \item \typestop{Just 5}{Maybe Int} - \item \typestop{Just "wow"}{Maybe String} - \item \typestop{Nothing}{Maybe a} - \item \typestop{Just Nothing}{Maybe (Maybe a)} - \item \lst{getAt :: Integer -> [a] -> Maybe a} - \item \lst{getAt _ [] = Nothing} - \item<.-> \lst{getAt 0 (x:_) = Just x} - \item<.-> \lst{getAt n (_:xs) = getAt (n-1) xs} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Сума на типове} - \begin{itemize}[<+->] - \item \lst{data Either a b = Left a | Right b}\\ - \hspace{5em}\lst{deriving (Eq, Ord, Show, Read)} - \item \typestop{Left 3}{Either Int b} - \item \typestop{Right 'a'}{Either a Char} - \end{itemize} - \onslide<+-> - \textbf{Задача.} Да се напише функция, която по даден списък от играчи намира най-добрия резултат, ако е постигнат от единствен играч, или списък от имената на играчите, които са постигнали най-добър резултат. - \onslide<+-> -\begin{lstlisting} -searchBest :: [Player] -> Either Score [Name]@\onslide<+->@ -searchBest players - | length bestPlayers == 1 = Left best - | otherwise = Right $ map name bestPlayers - where best = maximum $ map score players - bestPlayers = filter ((==best) . score) players -\end{lstlisting} -\end{frame} - -\section{Рекурсивни алгебрични типове} - -\begin{frame}[fragile] - \frametitle{Рекурсивни алгебрични типове} - Можем да дефинираме типове, позовавайки се на самите тях \alert{рекурсивно}.\\[2ex] - \pause - \textbf{Пример:} - \lst{data Nat = Zero | Succ Nat deriving (Eq, Ord, Show, Read)} - \begin{itemize}[<+->] - \item \lst{five = Succ $ Succ $ Succ $ Succ $ Succ Zero} - \item \lst{fromNat :: Nat -> Integer} - \item \lst{fromNat Zero = 0} - \item<.-> \lst{fromNat (Succ n) = fromNat n + 1} - \item \evalsto{fromNat five}5 - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Двоични числа} - -\begin{lstlisting} -data Bin = One | BitZero Bin | BitOne Bin - deriving (Eq, Ord, Show, Read) -\end{lstlisting} - \pause - \begin{itemize}[<+->] - \item \lst{six = BitZero $ BitOne $ One} - \item \lst{fromBin :: Bin -> Integer} - \item \lst{fromBin One = 1} - \item<.-> \lst{fromBin (BitZero b) = 2 * fromBin b} - \item<.-> \lst{fromBin (BitOne b) = 2 * fromBin b + 1} - \item \lst{succBin :: Bin -> Bin} - \item \lst{succBin One = BitZero One} - \item<.-> \lst{succBin (BitZero b) = BitOne b} - \item<.-> \lst{succBin (BitOne b) = BitZero $ succBin b} - \item \evalsto{fromBin \$ succBin \$ succBin six}8 - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Списъци} - -\begin{lstlisting} -data List a = Nil | Cons a (List a) - deriving (Eq, Ord, Show, Read) -\end{lstlisting} - \pause - \begin{itemize}[<+->] - \item \lst{l = Cons 1 $ Cons 2 $ Cons 3 $ Nil} - \item можем да използваме синтаксиса за записи:\\ - \lst!data List a = Nil | Cons { listHead :: a, listTail :: List a }!\\ - \hspace{5em}\lst{deriving (Eq, Ord, Show, Read)} - \item \evalstop{listHead l}1 - \item \lst{fromList :: List a -> [a]} - \item \lst{fromList Nil = []} - \item<.-> \lst{fromList (Cons x t) = x:fromList t} - \item \lst{(+++) :: List a -> List a -> List a} - \item \lst{Nil +++ l = l} - \item<.-> \lst{Cons h t +++ l = Cons h (t +++ l)} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Двоични дървета} -\begin{lstlisting} -data BinTree a = Empty | Node { root :: a, left, right :: BinTree a } - deriving (Eq, Ord, Show, Read) -\end{lstlisting} - \textbf{Примери:} - \begin{itemize}[<+->] - \item \lst{t = Node 3 (Node 1 Empty Empty) (Node 5 Empty Empty)} - \item \lst{depth :: BinTree a -> Integer} - \item \lst{depth Empty = 0} - \item<.-> \lst{depth (Node x l r) = max (depth l) (depth r) + 1} - \item \lst{leaves :: BinTree a -> [a]} - \item \lst{leaves Empty = []} - \item<.-> \lst{leaves (Node x Empty Empty) = [x]} - \item<.-> \lst{leaves (Node x l r) = leaves l ++ leaves r} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Функции от по-висок ред за двоични дървета} - - Трансформиране на двоично дърво (\lst{map}): - \pause -\begin{lstlisting} -mapBinTree :: (a -> b) -> BinTree a -> BinTree b -mapBinTree _ Empty = Empty -mapBinTree f (Node x l r) = Node (f x) (mapBinTree f l) (mapBinTree f r) -\end{lstlisting} - \vspace{4ex} - \pause - Свиване на двоично дърво (\lst{foldr}): -\begin{lstlisting} -foldrBinTree :: (a -> b -> b) -> b -> BinTree a -> b -foldrBinTree _ nv Empty = nv -foldrBinTree op nv (Node x l r) = - foldrBinTree op (x `op` foldrBinTree op nv r) l -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Дървета с произволен брой наследници} -\small - Можем да правим \alert{взаимнорекурсивни} дефиниции: -\begin{lstlisting} -data Tree a = Tree { rootTree :: a, subtrees :: TreeList a } -data TreeList a = None | SubTree { firstTree :: Tree a, restTrees :: TreeList a } -\end{lstlisting} -\pause -\begin{lstlisting} -leaf x = Tree x None -tree = Tree 1 $ SubTree (leaf 2) - $ SubTree (Tree 3 $ SubTree (leaf 4) $ None) - $ SubTree (leaf 5) $ None -\end{lstlisting} -\pause -\begin{lstlisting} -level :: Integer -> Tree a -> [a]@\pause@ -level 0 (Tree x _) = [x] -level k (Tree _ ts) = levelTrees (k - 1) ts -\end{lstlisting} -\pause -\begin{lstlisting} -levelTrees :: Integer -> TreeList a -> [a]@\pause@ -levelTrees _ None = [] -levelTrees k (SubTree t ts) = level k t ++ levelTrees k ts -\end{lstlisting} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Полиморфни списъци} -\small -\begin{lstlisting} -data SExpr = SBool Bool | SChar Char | SInt Int | - SDouble Double | SList { list :: [SExpr] } - deriving (Eq, Ord, Show, Read) -\end{lstlisting} - \ \pause -\begin{lstlisting} -sexpr = SList [SInt 2, SChar 'a', SList [SBool True, SDouble 1.2, SList []]] -\end{lstlisting} - \pause -\begin{lstlisting} -countAtoms :: SExpr -> Integer@\pause@ -countAtoms (SList sls) = sum $ map countAtoms sls -countAtoms _ = 1 -\end{lstlisting} - \pause -\begin{lstlisting} -flatten :: SExpr -> SExpr@\pause@ -flatten (SList sls) = SList $ concatMap (list . flatten) sls -flatten x = SList [x] -\end{lstlisting} -\end{frame} - -\end{document} diff --git a/2.6-haskell_io.tex b/2.6-haskell_io.tex deleted file mode 100644 index 34a4b62..0000000 --- a/2.6-haskell_io.tex +++ /dev/null @@ -1,414 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -% взели ли сме вече лениво оценяване? -\newboolfalse{lazy} - -% компилация по части -\newbooltrue{parts} - -% взели ли сме вече операцията ($)? -\newbooltrue{app} - -\ifbool{parts}{ - \newbool{part1} - \newbool{part2} - \IfEndWith*{\JobName}{part1}{\booltrue{part1}}{ - \IfEndWith*{\JobName}{part1-trans}{\booltrue{part1}}{ - \IfEndWith*{\JobName}{part2}{\booltrue{part2}}{ - \IfEndWith*{\JobName}{part2-trans}{\booltrue{part2}}{ - \IfEndWith*{\JobName}{-trans}{}{ - % в общия случай пускаме компилация на частите - \BeamerswitchSpawn{-part1} - \BeamerswitchSpawn{-part1-trans} - \BeamerswitchSpawn{-part2} - \BeamerswitchSpawn{-part2-trans}} - % приключваме с текущата обработка, частите вече са компилирани - \stop}}}}}{ - % включване и на двете части - \newbooltrue{part1} - \newbooltrue{part2} - } - -\title{Входно-изходни операции в Haskell\ifbool{parts}{ -- част \ifbool{part1}{1}{}\ifbool{part2}{2}{}}{}} - -\date[\ifbool{part1}{29.11--4.12.2024 г.}{}]{\ifbool{part1}{29 ноември--4 декември 2024 г.}{}} - -\lstset{language=Haskell,style=Haskell} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section{Странични ефекти в Haskell} - -\begin{frame}<\switch{part1}> - \frametitle{Странични ефекти в Haskell} - - \begin{itemize}[<+->] - \item Функциите в Haskell нямат странични ефекти - \item Но входно-изходните операции по природа са странични ефекти! - \item Как можем да се справим с този парадокс? - \item \textbf{Идея:} Можем да си мислим за входно-изходните операции като поточна обработка на данни - \end{itemize} - \onslide<+-> - \begin{center} - производител - $\longrightarrow$ - \begin{tikzpicture}[scale=.7,baseline={(0,0)}] - \filldraw[draw=black,fill=diagramblue] - (0,1) .. controls +(2,1.5) and +(-2,-1.5) .. (8,1) -- - (8,-1) .. controls +(-2,-1.5) and +(2,1.5) .. (0,-1) -- (0,1); - \path (0,0) .. controls +(2,1.5) and +(-2,-1.5) .. (8,0) - \foreach \p in {.1,.2,...,.9} { - node[circle,inner sep=0,minimum size=6,draw=black,fill=yellow!40!white,pos=\p] {} - }; - \end{tikzpicture} $\longrightarrow$ консуматор - \end{center} -\end{frame} - -\begin{frame}<\switch{part1}> - \frametitle{Поточна обработка} - \textbf{Задача.} Да се въведат \tt{n} числа и да се изведе тяхното средно аритметично.\\ - \pause - \textbf{Решение:} Дефинираме трансформация над стандартните вход и изход, която: - \begin{itemize}[<+->] - \item приема \tt{n} като параметър - \item трансформира входния поток, като \alert{консумира} от него \tt{n} числа и връща списък, който ги съдържа - \item пресмята средното аритметично \tt{avg} на числата в списъка - \item трансформира изходния поток, като \alert{произвежда} върху него низовото представяне на числото \tt{avg} - \end{itemize} - \onslide<+-> - \textbf{Трансформирането} на входно-изходните потоци несъмнено е страничен ефект, но \textbf{конструирането на трансформацията} няма нужда от странични ефекти!\\ - \onslide<+-> - \alert{Функциите, които работят с вход и изход, по същество дефинират композиция на входно-изходни трансформации.} -\end{frame} - -\section{\tt{IO}} - -\begin{frame}<\switch{part1}> - \frametitle{Типът \tt{IO a}} - - Стандартният генеричен тип \lst{IO a} задава тип на входно/изходна трансформация, резултатът от която е от тип \tt{a}.\\ - \pause - \textbf{Частен случай:} \lst{IO ()} задава трансформация, която връща празен резултат.\\[2ex] - \pause - \textbf{Входни трансформации:} - \begin{itemize} - \item \lst{getChar :: IO Char} --- връща символ, прочетен от входа - \item \lst{getLine :: IO String} --- връща ред, прочетен от входа - \end{itemize} - \pause - \textbf{Изходни трансформации:} - \begin{itemize} - \item \lst{putChar :: Char -> IO ()} --- извежда символ на изхода - \item \lst{putStr :: String -> IO ()} --- извежда низ на изхода - \item \lst{putStrLn :: String -> IO ()} --- извежда ред на изхода - \end{itemize} -\end{frame} - -\begin{frame}<\switch{part1}>[fragile] - \frametitle{Главна функция \tt{main}} - - \begin{itemize}[<+->] - \item Функцията \lst{main :: IO ()} от модула \lst{Main} в Haskell е - специална: тя е входната точка на компилираната програма. - \item По същество тя дефинира входно-изходна трансформация, която се прилага към стандартния вход и изход при изпълнение на програмата. - \item \textbf{Пример:} \lst^main = putStrLn "Hello, world!"^ - \item Можем ли да дефинираме \lst!main = putStrLn !\ifbool{app}{\lst!\$! }{\lst!(!}\lst!"Въведохте: " ++ getLine!\ifbool{app}{}{\lst!)!}? % поправка на оцветяването на синтаксис$ - \item \alert{Не!} \hspace{3em} \lst{getLine :: }\tta{IO} \lst{String} - \item Композицията на входно-изходни трансформации работи по различен начин от композицията на функции - \item Низът, който връща \lst{getLine} е „замърсен“ от входно-изходна операция - \item Как да композираме трансформации? - \end{itemize} -\end{frame} - -\section{Синтаксис за вход/изход} - -\begin{frame}<\switch{part1}>[fragile] - \frametitle{Конструкцията \lst{do}} - - В Haskell има специален \alert{двумерен} синтаксис за композиране на трансформации:\\[1ex] - \tta{do} \{ <трансформация> \}\\[1ex] - \pause - <трансформация> може да бъде: - \begin{itemize}[<+->] - \item произволен израз от тип \lst{IO a} - \item{} <име> \tta{<-} <трансформация> - \begin{itemize} - \item{} <трансформация> е от тип \lst{IO a} - \item резултатът от <трансформация> се свързва с <име> - \end{itemize} - \item \tta{return} <израз> - \begin{itemize} - \item празна трансформация, която връща <израз> като резултат - \item \lst{return :: a -> IO a} - \end{itemize} - \item резултатът от цялата конструкция \tt{do} е резултатът от последната трансформация в композицията - \end{itemize} - \onslide<+-> - \vspace{-.5ex} -\begin{lstlisting} -main = do line <- getLine - putStrLn @\ifbool{app}{\$ }{(}@"Въведохте: " ++ line@\ifbool{app}{}{)}@ -\end{lstlisting} -\end{frame} - -\begin{frame}<\switch{part1}>[fragile] - \frametitle{Локални дефиниции в \lst{do}} - \small - В някакъв смисъл \lst{<-} и \lst{return} са обратни една на друга операции: - \begin{itemize}[<+->] - \item \lst{<-} извлича „чист“ резултат от тип \tt{a} от трансформация от тип \lst{IO a} - \item \lst{return} фиктивно „замърсява“ резултат от тип \tt{a} за да стане от тип \lst{IO a} - \item Какъв е ефектът от <име> \lst{<- return} <израз> в \lst{do} конструкция? - \item Създава се локалната дефиниция <име> = <израз>! - \item Алтернативно, локални дефиниции могат да се създават и чрез: \lst{let} <име> \tta= <израз> - \item Да не се бърка с \lst{let} <име> \tt= <израз> \tta{in} <израз>! - \end{itemize} - \onslide<+-> - \textbf{Пример:} - \vspace{-.5ex} - \lstfootnotesize -\begin{lstlisting} -main = do putStrLn "Моля, въведете палиндром: " - line <- getLine - let revLine = reverse line - if revLine == line then putStrLn "Благодаря!" - else do putStrLn @\ifbool{app}{\$ }{(}@line ++ " не е палиндром!"@\ifbool{app}{}{)}@ - main -\end{lstlisting} -\end{frame} - -\begin{frame}<\switch{part1}> - \frametitle{Вход и изход на данни} - - Как можем да извеждаме и въвеждаме данни от типове различни от \lst{Char} и \tt{String}?\\[2ex] - \pause - На помощ идват класовете \lst{Show} и \lst{Read}: - \begin{itemize}[<+->] - \item \lst{show :: Show a => a -> String} - \item \lst{print :: Show a => a -> IO ()} - \item \lst{print = putStrLn . show} - \item \lst{read :: Read a => String -> a} - \item \evalstoerrp{read "1.23"} - \item Haskell не може да познае типа на резултата, понеже е генеричен! - \item \lst{getInt :: IO Int} - \item \lst{getInt = do line <- getLine}\\ - \hspace{7em}\lst!return! \ifbool{app}{\lst! \$! }{ \lst!(!}\lst!read line!\ifbool{app}{}{\lst!)!} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{part1}>[fragile] - \frametitle{Пример: средно аритметично на редица от числа} -\lstsmall -\begin{lstlisting} -findAverage :: IO Double@\pause@ -findAverage = do putStr "Моля, въведете брой: " - n <- getInt - s <- readAndSum n - return @\ifbool{app}{\$ }{(}@fromIntegral s / fromIntegral n@\ifbool{app}{}{)}@ -@\pause@ -readAndSum :: Int -> IO Int@\pause@ -readAndSum 0 = return 0 -readAndSum n = do putStr "Моля, въведете число: " - x <- getInt - s <- readAndSum @\ifbool{app}{\$ }{(}@n - 1@\ifbool{app}{}{)}@ - return @\ifbool{app}{\$ }{(}@x + s@\ifbool{app}{}{)}@ -@\pause@ -main = do avg <- findAverage - putStrLn @\ifbool{app}{\$ }{(}@"Средното аритметично е: " ++ show avg@\ifbool{app}{}{)}@ -\end{lstlisting} -\end{frame} - -\section{Управляващи структури} - - -\begin{frame}<\switch{part2}> - \frametitle{Управляващи функции} - - Можем да работим с трансформации с функции от по-висок ред: - \begin{itemize}[<+->] - \item \lst{import Control.Monad} - \item \lst{sequence :: [IO a] -> IO [a]} - \begin{itemize} - \item композира трансформации и събира резултатите им в списък - \item \alt<+->{\lst!getInts = sequence . (`replicate` getInt)!}{\lst!getInts n = sequence $ replicate n getInt!} % поправка на оцветяването $ - \end{itemize} - \item \lst{mapM :: (a -> IO b) -> [a] -> IO [b]} - \begin{itemize} - \item композира списък от трансформации по списък от стойности - \item \lst{mapM = sequence . map} - \item \lst!printRead s = do putStr $ s ++ " = "; getInt! % поправка на оцветяването $ - \item \lst{readCoordinates = mapM printRead ["x", "y", "z"]} - \end{itemize} - \item \lst{mapM_ :: (a -> IO b) -> [a] -> IO ()} - \begin{itemize} - \item Също като \lst{mapM}, но изхвърля резултата - \item \lst{printList = mapM_ print} - \end{itemize} - \item \lst{forever :: IO a -> IO b} - \begin{itemize} - \item безкрайна композиция на една и съща трансформация (както \lst{repeat} за списъци) - \item \lst{forever \$ do line <- getLine; putStrLn line} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{part2}>[fragile] - \frametitle{Средно аритметично на числа v2.0} - - \small -\begin{lstlisting} -readInt :: String -> IO Int -readInt s = do putStr $ "Моля, въведете " ++ s ++ ": " - getInt - -findAverage :: IO Double -findAverage = do n <- readInt "брой" - l <- mapM (readInt.("число #"++).show) [1..n] - let s = sum l - return $ fromIntegral s / fromIntegral n - -main = forever $ - do avg <- findAverage - putStrLn $ "Средното аритметично е: " ++ show avg - putStrLn "Хайде отново!" -\end{lstlisting} -\end{frame} - -\begin{frame}<\switchand{part1}{lazy}>[fragile] - \frametitle{Ленив вход и изход} - - \begin{itemize}[<+->] - \item Ленивото оценяване в Haskell ни позволява да работим с входно/изходни потоци - \item \lst{getContents :: IO String} --- връща списък от \alert{всички} символи на стандартния вход - \item списъкът се оценява лениво, т.е. прочита се при нужда - \item \textbf{Пример:} -\begin{lstlisting} -noSpaces = do text <- getContents - putStr $ filter (/=' ') text -\end{lstlisting} - \item \lst{interact :: (String -> String) -> IO ()} --- лениво прилага функция над низове над стандартния вход и извежда резултата на стандартния изход - \item \textbf{Пример:} -\begin{lstlisting} -noSpaces = interact $ filter (/=' ') -\end{lstlisting} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{part1}>[fragile] - \frametitle{Работа с файлове} - - \begin{itemize}[<+->] - \item \lst{IO} позволява работа с произволни файлове, не само със стандартните вход и изход - \item \lst{import System.IO} - \item \lst{openFile :: FilePath -> IOMode -> IO Handle} --- отваря файл със зададено име в зададен режим - \begin{itemize} - \footnotesize - \item \lst{type FilePath = String} - \item \lst{data IOMode = ReadMode|WriteMode|AppendMode|ReadWriteMode} - \end{itemize} - \item Има варианти на функциите за вход/изход, които работят с \lst{Handle} - \item \lst{hGetLine}, \lst{hGetChar}, \lst{hPutStr}, \lst{hPutStrLn}, \lst{hGetContents}\ldots - \item \textbf{Пример:} - \vspace{-1ex} -\begin{lstlisting} -encrypt cypher inFile outFile = - do h1 <- openFile inFile ReadMode - text <- hGetContents h1 - h2 <- openFile outFile WriteMode - hPutStr h2 @\ifbool{app}{\$ }{(}@map cypher text@\ifbool{app}{}{)}@ -\end{lstlisting} - \end{itemize} -\end{frame} - -\section{Монади} - -\begin{frame}<\switch{part2}> - \frametitle{Монади} - - \begin{itemize}[<+->] - \item \lst{IO} е пример за \alert{монада} - \item Монадите са конструкции, които „опаковат“ обекти от даден тип - \item \textbf{Примери:} - \begin{itemize} - \item \lst{IO} опакова стойност във входно/изходна трансформация - \item \lst{Maybe} опакова стойност с „флаг“ дали стойността съществува - \item \lst{[a]} опакова няколко „алтернативни“ стойности в едно - \item \lst{r -> a} опакова стойност от тип \lst{a} в „машинка“, която я пресмята при подаден параметър от тип \lst{r} - \item \lst{s -> (a,s)} опакова стойност от тип \lst{a} в „действие“, което променя дадено състояние от тип \lst{s} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{part2}> - \frametitle{Монадни операции} - - \begin{itemize}[<+->] - \item \lst{Monad} е клас от \alert{типови конструктори}, които - са монади - \item „Опаковката“ понякога е прозрачна\ldots (пример: \lst{Maybe, [a]}) - \item \ldots но често е \alert{еднопосочна}: един път опакована, не можем да извадим стойността извън опаковката\ldots (пример: \lst{IO, r -> a}) - \item \ldots но можем да я преопаковаме! - \item \lst{(>>=) :: Monad m => m a -> (a -> m b) -> m b} - \item оператор за „свързване“ на опаковани стойности - \item \lst{b = a >>= f}: - \begin{itemize} - \item поглеждаме стойността \lst{x} в опаковката \lst{a} - \item прилагаме функцията \lst{f} над \lst{x} - \item и получаваме нова опакована стойност \lst{b} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}<\switch{part2}>[fragile] - \frametitle{Императивен стил чрез монади} - - \small - \begin{fixedarea} - \begin{itemize}[<+->] - \item \lst{do} всъщност е синтактична захар за поредица от „свързвания“ - \item \textbf{Примери:} - \begin{onlyenv}<2> -\begin{lstlisting} -main = do line <- getLine - putStrLn $ "Въведохте: " ++ line -\end{lstlisting} - \end{onlyenv} - \begin{onlyenv}<3> -\begin{lstlisting} -main = getLine >>= (\line -> putStrLn $ "Въведохте " ++ line) -\end{lstlisting} - \end{onlyenv} - \begin{onlyenv}<4-> -\begin{lstlisting} -main = getLine >>= putStrLn . ("Въведохте: " ++) -\end{lstlisting} - \end{onlyenv} - \begin{onlyenv}<5> -\begin{lstlisting} -findAverage = do putStr "Моля, въведете брой: " - n <- getInt - s <- readAndSum n - return $ fromIntegral s / fromIntegral n -\end{lstlisting} - \end{onlyenv} - \begin{onlyenv}<6-> -\begin{lstlisting} -findAverage = putStr "Моля, въведете брой: " >>= - (\_ -> getInt >>= - (\n -> readAndSum n >>= - (\s -> return $ fromIntegral s / - fromIntegral n)) -\end{lstlisting} - \end{onlyenv} - \item<7-> работи за произволни монади, не само за \lst{IO}! - \item<8-> позволява абстрахиране от страничните ефекти и моделиране на поредица от инструкции - \item<9-> императивен стил във функционалното програмиране - \end{itemize} - \end{fixedarea} -\end{frame} -\end{document} diff --git a/2.7-haskell_func.tex b/2.7-haskell_func.tex deleted file mode 100644 index 7e71edc..0000000 --- a/2.7-haskell_func.tex +++ /dev/null @@ -1,338 +0,0 @@ -\documentclass[alsotrans,beameroptions={aspectratio=169}]{beamerswitch} -\usepackage{fprog} - -\title{Функтори и монади} - -\date{17 януари 2022 г.} - -\lstset{language=Haskell,style=Haskell} - -\begin{document} - -\begin{frame} - \titlepage -\end{frame} - -\section{Функтори} - -\begin{frame}[fragile] - \frametitle{Класове от по-висок ред} - - \begin{itemize}[<+->] - \item Досега разглеждахме \emph{класове} от типове, които имат - сходно поведение (\lst{Eq}, \lst{Read}, \lst{Show}, \lst{Enum}, - \lst{Measurable}, \lst{Num}, \ldots). - \item - Разглеждахме и \emph{типови конструктори}, които позволяват дефиниране на параметризирани (генерични) типове (\lst{Maybe}, \lst{[]}, \lst{BinTree}, \lst{Tree}, \lst{IO}, \ldots). - \item - Нека да разгледаме \emph{клас от типови конструктори}, които имат някаква обща характеристика. - \item - \textbf{Пример:} Има ли нещо общо, което можем да правим с \lst{[]}, \lst{BinTree} и \lst{Tree}? - \item Нещо, което не зависи от \emph{типа} на елементите в тези контейнери? - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Примери за класове от конструктори} - \begin{itemize}[<+->] - \item - \textbf{Пример:} Има ли нещо общо, което можем да правим с \lst{[]}, \lst{BinTree} и \lst{Tree}? - \item Можем да намираме брой елементи -\begin{lstlisting} -class Countable c where - count :: c a -> Integer -\end{lstlisting} - \item Можем да намерим списък от всички елементи -\begin{lstlisting} -class Listable c where - elements :: c a -> [a] -\end{lstlisting} - \item Можем да приложим функция над всеки елемент -\begin{lstlisting} -class Functor f where - fmap :: (a -> b) -> f a -> f b -\end{lstlisting} -\end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Функтори} - \small - \begin{definition} - Класът \lst{Functor} в Haskell се състои от типовите конструктори $f$, за които може да се дефинира \lst{fmap :: (a -> b) -> f a -> f b}. - \end{definition} - \pause - За удобство операцията \lst!<$>! е инфиксен вариант на \lst{fmap}.\\ % $ за поправка на оцветяването - \pause - \footnotesize - \textbf{Примери за функтори:} - \begin{itemize}[<+->] - \item \lst{Maybe} - \item \lst{(,) a} - \item \lst{Either a} - \item \lst{[]} - \item \lst{BinTree} - \item \lst{Tree} - \item \lst{(->) r} - \item \lst{IO} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Странни функторни екземпляри} - \textbf{Пример:} да разгледаме екземпляра -\begin{lstlisting} -data Pill a = BluePill a | RedPill a -instance Functor Pill where - fmap f (BluePill x) = RedPill (f x) - fmap f (RedPill x) = BluePill (f x) -\end{lstlisting} - \pause - \textbf{Проблем №1:} - \begin{itemize}[<+->] - \item \lst{fmap id (BluePill 2) = RedPill 2} - \item \lst{fmap} с „празна“ функция променя структурата на функтора! - \end{itemize} - \onslide<+-> - \textbf{Проблем №2:} - \begin{itemize}[<+->] - \item \lst{fmap (+3) (BluePill 3) = RedPill 6} - \item \lst{fmap (+1) (fmap (+2) (BluePill 3)) = BluePill 6} - \item Има значение колко поред функции ще приложим! - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Функторни закони} - \begin{definition} - \emph{Функтор} наричаме екземпляр на класа \lst{Functor} такъв, че: - \begin{enumerate} - \item \lst{fmap id} \eqv \lst{id} (запазване на идентитета) - \item \lst{fmap f . fmap g} \eqv \lst{fmap (f . g)} (дистрибутивност относно композиция) - \end{enumerate} - \end{definition} - \pause - Функторните закони ни дават гаранция, че реализацията на \lst{fmap} е „неутрална“ към функтора и променя стойностите в него само и единствено на базата на подадената функция \lst{f}.\\ - \pause - Всички примерни екземпляри (освен \lst{Pill}) удовлетворяват функторните закони.\\ - \pause - Можем да мислим, че \lst{fmap} „повдига“ функцията \lst{f} от елементи към функтори. -\end{frame} - -\section{Апликативни функтори} - -\begin{frame} - \frametitle{\tt{fmap} с двуаргументни функции} - Можем ли да използваме \tt{fmap} за „повдигане“ на двуаргументна функция?\\ - \pause - \onslide<+-> - \textbf{Пример:} \evalstoerrp{fmap (+) (Just 3) (Just 5)}\\ - \onslide<+-> - \textbf{Проблем:} \typestop{fmap (+) (Just 3)}{Maybe (Int -> Int)}\\ - \onslide<+-> - Получаваме функтор над функция, която не можем директно да приложим над функтор над стойност!\\ - \onslide<+-> - \textbf{Идея:} Да разбием \lst{fmap} на две части: - \begin{itemize}[<+->] - \item повдигане на функтор над функция към функция над функтори - \begin{itemize} - \item \lst{f (a -> b) -> f a -> f b} - \end{itemize} - \item повдигане на обикновена функция към функтор над функция - \begin{itemize} - \item \lst{(a -> b) -> f (a -> b)} - \end{itemize} - \end{itemize} - \onslide<+-> - Функторите, които поддържат такова разлагане на \lst{fmap} наричаме \emph{апликативни}. -\end{frame} - -\begin{frame}[fragile] - \frametitle{Класът \tt{Applicative}} -\begin{lstlisting} -class (Functor f) => Applicative f where - pure :: a -> f a - (<*>) :: f (a -> b) -> f a -> f b -\end{lstlisting} - \onslide<+-> - Можем да дефинираме \alt<+->{\alt<+->{\alt<+->{\lst{fmap = (<*>) . pure}}{\lst{fmap f = (<*>) (pure f)}}}{\lst{fmap f a = (<*>) (pure f) a}}}{\lst{fmap f a = pure f <*> a}}.\\ - \onslide<+-> - \textbf{Примери за апликативни функтори:} - \begin{itemize}[<+->] - \item \lst{Maybe} - \item \lst{Either a} - \item \lst{[]} - \item \lst{ZipList} - \item \lst{(->) r} - \item \lst{IO} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Функции за апликативни функтори} - \begin{itemize}[<+->] - \item \lst!liftA2 :: Applicative f => !\\ - \hspace{10ex}\lst{(a -> b -> c) -> f a -> f b -> f c} - \begin{itemize} - \item повдига двуаргументна функция над функтор - \item \lst!liftA2 f a b = f <$> a <*> b! % $ оцветяване на синтаксиса - \item \textbf{Пример:}\\\evalstop{liftA2 (+) [2,3] [10,20,30]}{[12,22,32,13,23,33]} - \end{itemize} - \item \lst{sequenceA :: Applicative f => [f a] -> f [a]} - \begin{itemize} - \item повдига списък от функтори до функтор над списък - \item \lst{sequenceA [] = pure []} - \item<.-> \lst{sequenceA (x:xs) = liftA2 (:) x (sequenceA xs)} - \item \lst{sequenceA = foldr (liftA2 (:)) (pure [])} - \item \textbf{Пример:}\\\evalstop{sequenceA [Just 2, Just 3, Just 5]}{Just [2,3,5]} - \item \textbf{Пример:} \evalstop{sequenceA [Just 2, Nothing, Just 5]}{Nothing} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Закони за апликативни функтори} - \begin{definition} - \emph{Апликативен функтор} наричаме екземпляр на класа \lst{Applicative}, за който: - \begin{enumerate}[<+->] - \item \lst{pure f <*> x} \eqv \lst{fmap f x} - \item \lst{pure id <*> v} \eqv \lst{v} - \item \lst{pure (.) <*> u <*> v <*> w} \eqv \lst{u <*> (v <*> w)} - \item \lst{pure f <*> pure x} \eqv \lst{pure (f x)} - \item \lst{u <*> pure y} \eqv \lst{pure ($ y) <*> u} % $ оцветяване на синтаксис - \end{enumerate} - \end{definition} -\end{frame} - -\section{Монади} - -\begin{frame} - \frametitle{Операцията „свързване“ (bind)} - - \begin{itemize}[<+->] - \item Функторите ни позволяваха да превърнем \emph{функция над елементи} във функция над функтори: - \begin{itemize} - \item \evalsto{(+3) <$> [1,2]}{[4,5]} % $ оцветяване на синтаксиса - \end{itemize} - \item Апликативните функтори ни позволяваха да превърнем \emph{функтор над функция} към функция над функтори - \begin{itemize} - \item \evalsto{(+) <$> [1,2] <*> [10,20]}{[11,12,21,22]} % $ оцветяване на синтаксиса - \end{itemize} - \item Но как можем да превърнем \emph{функция, връщаща функтор} във функция над функтори? - \begin{itemize} - \item \evalsto{(\\x -> [1..x]) =<< [3,4]}{[1,2,3,1,2,3,4]} % >> оцветяване на синтаксиса - \item Искаме структурата на функтора-резултат да може да зависи от стойността във функтора-параметър! - \item \lst!(=<<) :: (a -> f b) -> f a -> f b! % >> оцветяване на синтаксиса - \item По-често се използва операцията „свързване“ (bind) с разменени аргументи: - \item \lst!(>>=) :: f a -> (a -> f b) -> f b! - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Класът \tt{Monad}} -\begin{lstlisting} -class Applicative m => Monad m where - return :: a -> m a - return = pure - - (>>=) :: m a -> (a -> m b) -> m b - (>>) :: m a -> m b -> m b - x >> y = x >>= \_ -> y -\end{lstlisting} - \pause - \textbf{Примери за монади:} - \begin{itemize}[<+->] - \item \lst{Maybe} - \item \lst{[]} - \item \lst{(->) r} - \item \lst{IO} - \end{itemize} - \onslide<+-> - Синтаксисът \lst{do} работи за всички екземпляри на \lst{Monad}! -\end{frame} - -\begin{frame}[fragile] - \frametitle{Монадни функции (1)} - \begin{itemize}[<+->] - \item \lst{liftM :: Monad m => (a -> b) -> m a -> m b} - \begin{itemize} - \item \lst{fmap} за монади - \item \lst!liftM f m = m >>= (\x -> return $ f x)! % $ оцветяване на синтаксиса - \end{itemize} - \item \lst{ap :: Monad m => m (a -> b) -> m a -> m b} - \begin{itemize} - \item \lst{<*>} за монади - \item \lst!ap mf m = mf >>= (\f -> m >>= (\x -> return $ f x))! % $ оцветяване на синтаксиса - \end{itemize} - \item \lst{liftM2::Monad m => (a -> b -> c) -> m a -> m b -> m c} - \begin{itemize} - \item \lst{liftA2} за монади -\onslide<+-> -\begin{lstlisting} -liftM2 f m1 m2 = m1 <<= (\x1 -> - m2 <<= (\x2 -> - return $ f x1 x2)) -\end{lstlisting} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Монадни функции (2)} - \begin{fixedarea} - \begin{itemize}[<+->] - \item \lst{join :: Monad m => m (m a) -> m a} - \begin{itemize} - \item „слива“ двойната опаковка в единична - \item \alt<+->{\alt<+->{\lst{join = (>>= id)}}{\lst{join mm = (>>= id) mm}}}{\lst{join mm = mm >>= id}} - \item Можем да дефинираме \lst{(>>=)} чрез \lst{join} и \lst{fmap}: \lst{m >>= f = join (fmap f m)} - \end{itemize} - \item \lst{filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]} - \begin{itemize} - \item Филтрира с предикат, връщащ „опаковани“ булеви стойности - \item Резултатът е „опакованите“ елементи на списъка - \item \lst{powerset = filterM (\x -> [True,False])} - \end{itemize} - \item \lst{foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a} - \begin{itemize} - \item Натрупва елементи от списък с монадна операция - \item Натрупването е ляво (итеративен процес, подобно на \lst{foldl}) - \item - \lst!boundSum lim = foldM (\x y -> if x+y < lim then Just (x+y) else Nothing) 0! - \item \evalstop{boundSum 60 [1..10]}{Just 55} - \item \evalstop{boundSum 50 [1..10]}{Nothing} - \end{itemize} - \end{itemize} - \end{fixedarea} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Монадни закони} - \begin{definition} - \emph{Монада} наричаме инстанция на класа \lst{Monad}, за която: - \begin{enumerate}[<+->] - \item \lst{return x >>= f} \eqv \lst{f x} (ляв идентитет) - \item \lst{m >>= return} \eqv \lst{m} (десен идентитет) - \item \lst{(m >>= f) >>= g} \eqv \lst{m >>= (\x -> f x >>= g)} (асоциативност) - \end{enumerate} - \end{definition} - \onslide<+-> - Композиция на монадни функции: -\begin{lstlisting} -(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c) -f <=< g = \x -> g x >>= f -\end{lstlisting} - \onslide<+-> - \vspace{-.5ex} - Монадните закони чрез композиция: - \begin{enumerate} - \item \lst{f <=< return} \eqv \lst{f} (ляв идентитет) - \item \lst{return <=< f} \eqv \lst{f} (десен идентитет) - \item \lst{f <=< (g <=< h)} \eqv \lst{(f <=< g) <=< h} (асоциативност) - \end{enumerate} -\end{frame} -\end{document} - -% LocalWords: BinTree BluePill RedPill ZipList liftA sequenceA xs ap -% LocalWords: liftM mf filterM foldM boundSum lim