From e59dac99bf692d67a2dfeea3426aec57812e5a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20R=C3=BCmpelein?= Date: Mon, 25 Apr 2016 16:20:31 +0200 Subject: [PATCH] Finished first draft of Python-part. --- Notes.md | 20 ++-- tex/headers/listings.tex | 13 +++ tex/wtf.bib | 6 + tex/wtfunctional.tex | 233 +++++++++++++++++++++++++++------------ 4 files changed, 193 insertions(+), 79 deletions(-) diff --git a/Notes.md b/Notes.md index 2306c19..3ea8333 100644 --- a/Notes.md +++ b/Notes.md @@ -19,22 +19,22 @@ html header: just convenience + code example: Pythagoraian triangles, bubble sort * Phuncy: The pythonic way is functional! - - Not strictly functional - - recursion, fafco - - lambda syntax + + Not strictly functional + - recursion + + fafco - map, fold => example (sum of squares?) - - python lambda syntax: lambda a,b: a+b - - fold with reduce - - don't return lists, but iterators! - - Note: 2: map, filter, reduce, list comprehension + + python lambda syntax: lambda a,b: a+b + + don't return lists, but iterators! + + fold with reduce + + Note: 2: map, filter, reduce, list comprehension 3: map, filter, functools.reduce(), list comprehension - - The python2 to 3 page states: + + The python2 to 3 page states: “Removed `reduce()`. Use `functools.reduce()` if you really need it; however, 99 percent of the time an explicit `for` loop is more readable.” - - Why use it? => Multi-processing, WTF Count. + + Why use it? => Multi-processing, WTF Count. ```python a = list(range(10)) @@ -50,7 +50,7 @@ html header: a -> a -> a -> a - mysum x y z = x + y + z - -- b == 6 - b = mysum 1 2 3 - \end{haskell} +\begin{haskell} +mysum :: Num a => a -> a -> a -> a +mysum x y z = x + y + z +-- b == 6 +b = mysum 1 2 3 +\end{haskell} \pause Functions always get evaluated left to right, thus the following works (\emph{Currying}): - \begin{haskell} - mysum2 = mysum 2 - -- c == 12 - c = mysum2 4 6 - \end{haskell} +\begin{haskell} +mysum2 = mysum 2 +-- c == 12 +c = mysum2 4 6 +\end{haskell} \end{frame} \begin{frame}[fragile]{Syntax – Lists (1)} @@ -117,26 +117,26 @@ \item Two lists can be concatenated using the \haskellcmd{++} operator: \haskellcmd{[1,2,3] ++ [4..7]} \item Single objects get pushed to the front using - \enquote{\haskellcmd{:}}: \haskellcmd{1:[2..7]}. + \enquote{\haskellcmd{:}}: \haskellcmd{1:[2..7]}. \item This can also be used vice versa to extract single values from lists: - \begin{haskell} - extract (x:xs) = x - -- a = 1 - a = extract [1..5] - \end{haskell} +\begin{haskell} +extract (x:xs) = x +-- a = 1 +a = extract [1..5] +\end{haskell} \end{itemize} \end{frame} - + \begin{frame}[fragile]{Syntax – Recursion} Example: Add a value to every entry in an array - \begin{haskell} - addto :: (Num a) => [a] -> a -> [a] - addto [] _ = [] -- edge case (list empty) - addto (x:xs) y = (x+y) : addto xs y - b = [1..4] - -- c == [5,6,7,8] - c = addto b 4 - \end{haskell} +\begin{haskell} +addto :: (Num a) => [a] -> a -> [a] +addto [] _ = [] -- edge case (list empty) +addto (x:xs) y = (x+y) : addto xs y +b = [1..4] +-- c == [5,6,7,8] +c = addto b 4 +\end{haskell} \end{frame} \begin{frame}[fragile]{Lambdas} @@ -169,52 +169,147 @@ \end{frame} \begin{frame}[fragile]{Folds (2)} - \uncover<+-> Example: Self written Right fold and sum: - \begin{haskell} - mfold f z [] = z - mfold f z (x:xs) = f x (mfold f z xs) - msum = mfold (+) 0 - -- g == 5050 - g = msum [1..100] - \end{haskell} + \uncover<+-> Example: Self written Right fold and sum: +\begin{haskell} +mfold f z [] = z +mfold f z (x:xs) = f x (mfold f z xs) +msum = mfold (+) 0 +-- g == 5050 +g = msum [1..100] +\end{haskell} \uncover<+->{Note that this gets pretty resource hungry with large lists, better use left-folds for this (see~\cite{whichfold})} \end{frame} \begin{frame}[fragile]{Example: Pythagorean triangles} Get all Pythagorean triangles with a hypotenuse off length at most 15: - \begin{haskell} - > [(a,b,c) | a <- [1..15], - b <- [1..a], - c <- [1..b], - a^2 == b^2 + c^2] - [(5,4,3),(10,8,6),(13,12,5),(15,12,9)] - \end{haskell} -\end{frame} +\begin{haskell} +> [(a,b,c) | a <- [1..15], +b <- [1..a], +c <- [1..b], +a^2 == b^2 + c^2] +[(5,4,3),(10,8,6),(13,12,5),(15,12,9)] +\end{haskell} +\end{frame} \begin{frame}[fragile]{Example: Bubble-sort} Recursive, functional bubble-sort algorithm: - \begin{haskell} - bsort f [] = [] - bsort f (x:xs) = (bsort f a) ++ [x] ++ (bsort f b) - where a = [ y | y <- xs, not (f x y) ] - b = [ y | y <- xs, (f x y) ] - mbsort = bsort (\x y -> (x > y)) - \end{haskell} +\begin{haskell} +bsort f [] = [] +bsort f (x:xs) = (bsort f a) ++ [x] ++ (bsort f b) +where a = [ y | y <- xs, not (f x y) ] +b = [ y | y <- xs, (f x y) ] +mbsort = bsort (\x y -> (x > y)) +\end{haskell} \pause Result: - \begin{haskell} - λ> h = [1, 20, -10, 5] - λ> mbsort h - [-10,1,5,29] - \end{haskell} +\begin{haskell} +λ> h = [1, 20, -10, 5] +λ> mbsort h +[-10,1,5,29] +\end{haskell} +\end{frame} + +\section{Phuncy!} +\subsection{Overview} +\begin{frame}{Functional programming in Python} + \begin{itemize}[<+->] + \item Obviously, python is not strictly functional… + \item …but has functions as first class objects! + \item Some other stuff is widely used, but with another syntax… + \item …, although there are ways to get the \enquote{real} functional + style. + \item I use python3 here, python2 differs in some points. + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{Lambdas, Maps} + \begin{itemize}[<+->] + \item Lambda-syntax: \pycmd{lambda a,b: a+b} + \item Maps are done by \pycmd{map} + \item \emph{Note:} Most functional list-functions return iterators in + python, not lists! + \item Use \pycmd{list()} to cast Iterators, but this is usually not + necessary. + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{Filters} + \begin{itemize}[<+->] + \item Can be done using \pycmd{filter(func, iter)}: +\begin{pycode} +a = range(1,7) +b = filter(lambda x: x%2, a) +print(list(b)) +# [1,3,5] +\end{pycode} + \item Alternatively, use List Comprehension: +\begin{pycode} +a = range(1,7) +b = [x for x in a if x%2] +print(b) +\end{pycode} + \item Pro: Maybe easier readable, returns list + \item Con: Returns list (slower when iterating afterwards) + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{Fold} + \begin{itemize}[<+->] + \item From the python2 to python3 Changelog: + \begin{quote} + Removed `reduce()`. Use `functools.reduce()` if you really need it; + however, 99 percent of the time an explicit `for` loop is more + readable. + \end{quote} + \item I disagree – Old-style is more explicit and still available from \pycmd{functools} + \item Example – sum of squares +\begin{pycode} +from functools import reduce +a = range(10) +mapped = map(lambda x: x**2, a) +reduced = reduce(lambda x,y: x+y, mapped) +\end{pycode} + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{Currying} + \begin{itemize}[<+->] + \item No real currying, but several workarounds + \item Lambdas: \pycmd{g=lambda x: foo(2,x)} + \item \pycmd{functools.partial}: +\begin{pycode} +def foo(x,y): + return x+y +bar=partial(foo, 2) +bar(3) # 5 +\end{pycode} + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{Decorators} + \begin{itemize}[<+->] + \item Often used to modify functions in Frameworks + \item Encapsulates other functions. More infos at \cite{decorators} +\begin{pycode} +def debug(func): + def inner(*args, **kwargs): + sys.stderr.write("F: {}, args: {}, kwargs {}".format(func.__name__, args, + kwargs)) + return func(*args, **args) + return inner +@debug +def foo(x): + print(x) +\end{pycode} + \end{itemize} \end{frame} \begin{frame}[plain]{References} \printbibliography -\end{frame} +\end{frame} \end{document} %%% Local Variables: %%% mode: latex -%%% ispell-dictionary: en +%%% ispell-local-dictionary: "en_GB" %%% End: \ No newline at end of file