diff --git a/Notes.md b/Notes.md index 3ea8333..de84ccc 100644 --- a/Notes.md +++ b/Notes.md @@ -52,19 +52,19 @@ html header: ` + + `std::accumulate` from `numeric`: Wants binary operation, i.e. `std::minus` diff --git a/examples/02_python.py b/examples/02_python.py new file mode 100644 index 0000000..b4ec711 --- /dev/null +++ b/examples/02_python.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +import sys + + +def debug(func): + def inner(*args, **kwargs): + sys.stderr.write("F: {}, args: {}, kwargs: {}\n" + .format(func.__name__, args, kwargs)) + return func(*args, **kwargs) + return inner + + +@debug +def foo(x): + pass + + +def mybubblesort(array, func=lambda x, y: True if x > y else False): + if (len(array) == 0): + return [] + else: + x, *xs = array + return mybubblesort([y for y in xs if func(x, y)], func) \ + + [x] \ + + mybubblesort([y for y in xs if not func(x, y)], func) + +if __name__ == "__main__": + foo(2) + a = [2,5,12,4,1,0] + print(mybubblesort(a)) + print(mybubblesort(a, lambda x, y: True if x < y else False)) diff --git a/examples/03_cpp.cpp b/examples/03_cpp.cpp new file mode 100644 index 0000000..b93537e --- /dev/null +++ b/examples/03_cpp.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +int main() { + std::vector a{1,2,3,4}; + std::vector b{5,6,7,8}; + // result vector + std::vector c(a.size(), 0); + + // double + std::for_each(a.begin(), a.end(), [](int &n){ n*=2;}); + + std::cout << "Double:" << std::endl; + for (auto const &i: a){ std::cout<()); + int mult = std::accumulate(a.begin(), a.end(), 1, + [](int a, int b)->int { return a * b; }); + std::cout << "Sum: " << sum + << "\nDiff from 15: " << diff + << "\nProd: " << mult + << std::endl; + + return 0; +} diff --git a/examples/04_cpp17.cpp b/examples/04_cpp17.cpp new file mode 100644 index 0000000..8852249 --- /dev/null +++ b/examples/04_cpp17.cpp @@ -0,0 +1,32 @@ +#include +// compile using std=c++1z-option +// tested with clang++ and g++ +// using: +// $CC -Wall -Werror -pedantic -pedantic-errors -std=c++1z -o $OUT $IN + +/* "Old" code: + * The usage of auto to implicitly get the return type is C++17, + * the main part is using C++11 variadic templates and overloading + */ +auto sum1() { return 0;} + +template +auto sum1(T t) { return t; } + +template +auto sum1(T t, Ts... ts) {return t + sum1(ts...);} + +/* New code: + * Using c++17 fold expressions, this gets way shorter and + * less error prone + */ +template +auto sum2 (T... args){ + return (... + args); +} + +int main() { + std::cout << sum1(1,2,3,4,5,6,7,8,9,10) << std::endl; + std::cout << sum2(1,2,3,4,5,6,7,8,9,10) << std::endl; + return 0; +} diff --git a/tex/headers/listings.tex b/tex/headers/listings.tex index b0095f1..a1b3161 100644 --- a/tex/headers/listings.tex +++ b/tex/headers/listings.tex @@ -3,6 +3,8 @@ \usepackage{upquote} \usepackage[section, cache=true,]{minted} +\usemintedstyle{manni} + \newminted[ccode]{c}% { linenos=true, @@ -58,5 +60,5 @@ %%% Local Variables: %%% mode: latex -%%% TeX-master: "../linux-script" +%%% TeX-master: "../wtfunctional" %%% End: diff --git a/tex/wtf.bib b/tex/wtf.bib index d79d91c..fa653c5 100644 --- a/tex/wtf.bib +++ b/tex/wtf.bib @@ -1,11 +1,29 @@ @online{whichfold, -title={Foldr Foldl Foldl' - HaskellWiki}, -urldate={2016-04-21}, -url={https://wiki.haskell.org/Foldr_Foldl_Foldl%27}, +title = {Foldr Foldl Foldl' - HaskellWiki}, +url = {wiki.haskell.org/Foldr_Foldl_Foldl}, } @online{decorators, -title={simeonfranklin.com - Understanding Python Decorators in 12 Easy Steps!}, -urldate={2016-04-25}, -url={http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/}, +title = {simeonfranklin.com - Understanding Python Decorators in 12 Easy Steps!}, +url = {simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/}, +} + +@Online{cppiter, +title = {C++ concepts: Iterator - cppreference.com}, +url = {en.cppreference.com/w/cpp/concept/Iterator}, +} + +@online{generics, +title = {Index of /~kami/2015-32C3/}, +url = {people.freebsd.org/~kami/2015-32C3/}, +} + +@online{cpp17, +title = {C++17 content prediction (pre-Jacksonville and post-Kona report) – Michael Wong's Standard}, +url = {https://wongmichael.com/2016/02/28/c17-content-predictionpre-jacksonville-and-post-kona-report/}, +} + +@online{cppfolds, +title = {Fold expressions}, +url = {www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4191.html}, } \ No newline at end of file diff --git a/tex/wtfunctional.tex b/tex/wtfunctional.tex index 27c9618..621b338 100644 --- a/tex/wtfunctional.tex +++ b/tex/wtfunctional.tex @@ -5,15 +5,17 @@ \usepackage{tabularx} \usepackage[backend=biber,]{biblatex} \bibliography{wtf} +\renewcommand{\bibfont}{\small} \usepackage{fontspec} \setsansfont{Fira Sans} \setmonofont{Inconsolata-g} \usetheme{Antibes} -%\usecolortheme{beaver} \setbeamercovered{transparent} +\newcommand{\cpp}{\texttt{C++}} + \title{WTFunctional} \author{Oliver Rümpelein} \subtitle{Using functional structures in non-functional languages} @@ -23,6 +25,17 @@ \begin{document} \frame{\titlepage} +\begin{frame}[plain]{What?} + \begin{enumerate}[<+->] + \item Dafunc? Introduction to functional paradigms using Haskell + \item PhuncY! Functional programming in Python + \item Fun\cpp{}tional: STL-hacks and usage in \cpp + \end{enumerate} + \begin{uncoverenv}<4-| invisible@1-3> + \emph{With preview to \cpp{}17/20/22!} + \end{uncoverenv} +\end{frame} + \section{Dafunc?} \subsection{Functional programming} \begin{frame}{Understanding functional paradigms} @@ -169,7 +182,7 @@ c = addto b 4 \end{frame} \begin{frame}[fragile]{Folds (2)} - \uncover<+-> Example: Self written Right fold and sum: + \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) @@ -185,9 +198,9 @@ g = msum [1..100] 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] + 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} @@ -197,8 +210,8 @@ a^2 == b^2 + c^2] \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) ] + 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: @@ -209,7 +222,7 @@ mbsort = bsort (\x y -> (x > y)) \end{haskell} \end{frame} -\section{Phuncy!} +\section{PhuncY!} \subsection{Overview} \begin{frame}{Functional programming in Python} \begin{itemize}[<+->] @@ -222,6 +235,7 @@ mbsort = bsort (\x y -> (x > y)) \end{itemize} \end{frame} +\subsection{Elements} \begin{frame}[fragile]{Lambdas, Maps} \begin{itemize}[<+->] \item Lambda-syntax: \pycmd{lambda a,b: a+b} @@ -286,27 +300,233 @@ bar(3) # 5 \end{itemize} \end{frame} -\begin{frame}[fragile]{Decorators} +\begin{frame}{Decorators (1)} \begin{itemize}[<+->] \item Often used to modify functions in Frameworks - \item Encapsulates other functions. More infos at \cite{decorators} + \item Basic pattern: Decorator is a function that itself takes a function, + and returns a wrapper + \item Step-by-step introduction to decorators at~\cite{decorators} + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{Decorators (2)} \begin{pycode} def debug(func): def inner(*args, **kwargs): - sys.stderr.write("F: {}, args: {}, kwargs {}".format(func.__name__, args, - kwargs)) - return func(*args, **args) + print("F: {}, args: {}, kwargs: {}\n" + .format(func.__name__, args, kwargs)) + return func(*args, **kwargs) return inner + @debug def foo(x): - print(x) + pass + +foo(2) # => F: foo, args: (2), kwargs: {} \end{pycode} +\end{frame} + +\subsection{Conclusion} +\begin{frame}{Quite enough…} + \begin{itemize}[<+->] + \item Python is not really functional… + \item …but is strongly influenced by functional paradigms. + \item Its functional parts are heavily used, i.e in Genomics \end{itemize} \end{frame} +\begin{frame}[fragile]{Example} +\begin{pycode} +def mybubblesort(array, + func=lambda x, y: True if x > y else False): + if (len(array) == 0): + return [] + else: + x, *xs = array + return mybubblesort([y for y in xs + if func(x,y)], func) \ + + [x] \ + + mybubblesort([y for y in xs \ + if not func(x,y)], func) +\end{pycode} +\end{frame} + +\section{Fun\cpp{}ional} +\subsection{Overview} + +\begin{frame}{Functional programming in \cpp{}} + \begin{itemize}[<+->] + \item \enquote{Classical} \cpp{} has a few functional elements… + \item …but lacks lambdas, for instance. + \item This changed with the modern standards, starting from \cpp{}11. + \end{itemize} +\end{frame} + + +\subsection{Elements} +\begin{frame}[fragile]{Lists} + \begin{itemize}[<+->] + \item In \cpp{}, \emph{Iterators} are equivalent to lists in functional languages. + \item Examples of iterators include \cppcmd{vector} and \cppcmd{array}. + \item See~\cite{cppiter} for more information about the specific iterator + types and the prerequisites they bring. + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{lambdas} + \begin{itemize}[<+->] + \item \emph{Lambdas} have been introduced with \cpp{}11 + \item Syntax: +\begin{cppcode} +[v1,&v2](int v1, int v2) + {return v1 < v2} +\end{cppcode} + \item The \cppcmd{[]} denotes the capture-list and specifies, whether + variables are used by value or by reference. If this is empty, + anything is used by value. + \item Lambdas are fully-featured \emph{functionals}, such are functions + wrapped with \cppcmd{std::function}, and objects implementing + \cppcmd{operator()}. + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{Maps (1)} + \uncover<+->{\begin{alertblock}{map ≠ map} + \cppcmd{std::map} is a data-type similar to pythons \pycmd{dict} and has no + relation to the functional concept of maps! + \end{alertblock}} + \uncover<+->{The following can be used instead (both from \cppcmd{}):} + \begin{itemize}[<+->] + \item \cppcmd{std::for_each} + \item \cppcmd{std::transform} + \end{itemize} +\uncover<+->{But they are quite different.} +\end{frame} + +\begin{frame}[fragile]{Maps (2)} + \uncover<+->{\cppcmd{std::for_each} applies a function \cppcmd{void fun(T &a)} to elements + of an iterator containing values of type \cppcmd{T} in place:} + + \begin{uncoverenv}<+-> +\begin{cppcode} +vector a{1,2,3}; +for_each(a.begin(), a.end(), + [](int &n){ n*=2; }); +\end{cppcode} + \end{uncoverenv} + + \uncover<+->{This multiplies each element in \cppcmd{a} by 2.} +\end{frame} + +\begin{frame}[fragile]{Maps (3)} + \uncover<+->{In contrast, \cppcmd{std::transform} returns a new iterator containing type +\cppcmd{U}. Thus, the function has to be \cppcmd{U func(T val)}:} + +\begin{uncoverenv}<+-> +\begin{cppcode} +vector b{1,2,3,4}; +vector c(b.size(), 0.0); +transform(b.begin(), b.end(), c.begin(), + [](int i){ return 1.0/i; }); +\end{cppcode} +\end{uncoverenv} + +\uncover<+->{This gives a vector c filled with the inverse elements of b.} +\uncover<+->{There are also forms of \cppcmd{transform} that merge two + iterators (see examples in git-repo).} +\end{frame} + +\begin{frame}[fragile]{Filters} + \begin{itemize}[<+->] + \item This is ugly + \item No syntactic sugar as with python's list comprehensions + \item Use \cppcmd{std::remove_if} or \cppcmd{std::remove_copy_if} from \cppcmd{}, + \item afterwards \cppcmd{transform}. + \item Or make use of the \cppcmd{boost::filter_iterator} library. + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{Folds} + \begin{itemize}[<+->] + \item \cppcmd{std::accumulate} is defined in \cppcmd{} + \item Takes bounds of an Iterator, and a \cppcmd{BinaryOperation} + \item Example: +\begin{cppcode} +vector a{1,2,3,4} +int b = accumulate(a.begin(), a.end(), 0); // sum +int c = accumulate(a.begin(), a.end(), 15, minus()); +\end{cppcode} + \cppcmd{std::minus} is defined in \cppcmd{} as well. + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{Generics and \texttt{D}} +\begin{itemize}[<+->] + \item These are only procedural examples of functional programming. + \item Much can be done using \emph{generic} techniques + (\enquote{templates}). + \item Many examples: \cite{generics} + \item Much more to come in \cpp{}20/22 (\cite[What will Not make it into + C+17,…]{cpp17}) + \begin{itemize}[<+->] + \item \emph{Concepts} are kind of constraints on template parameters. + \item \emph{Ranges} will replace iterators + \item All of the above and more are available in the \texttt{D} + programming language! (\url{dlang.org}) + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{Generics example: Folds} + \begin{uncoverenv}<+-> + Using \cpp{}11 with variadic templates, one has (mod \cppcmd{auto}) +\begin{cppcode} +auto sum() { return 0; } + +template +auto sum(T t) { return t; } + +template +auto sum(T t, Ts... ts) { return t + sum(ts...); } +\end{cppcode} + \end{uncoverenv} + \begin{uncoverenv}<+-> + With new folding expression (\cite{cppfolds}): +\begin{cppcode} +template +auto sum(const auto&... args) + { return (args + ...); } +\end{cppcode} + \end{uncoverenv} +\end{frame} + \begin{frame}[plain]{References} \printbibliography \end{frame} + +\section{The} +\subsection{end} + +\begin{frame}[plain]{Thanks for listening!}{Any questions?} + \href{https://git.f3l.de/pheerai/wtfunctional/}{Git-Repo with examples and + slides}: \url{git.f3l.de/pheerai/wtfunctional/} + + \begin{description} + \item[Mail:] \url{oli_r@fg4f.de} + \item[XMPP:] \url{pheerai@im.f3l.de} + \item[Github:] \href{https://github.com/pheerai/}{pheerai} + \item[Misc:] Signal, Telegram,… + \item[…or] later having some drink + \end{description} + \vfill + \tiny \raggedleft Proudly typed using Lua\LaTeX{}. Slides-theme: \emph{Antibes}\\ + Fonts used are \href{github.com/mozilla/Fira}{\emph{Fira Sans}} and + \href{leonardo-m.livejournal.com/77079.html}{\emph{Inconsolata G}}.\\ + Syntax and code highlighting with + \href{https://github.com/gpoore/minted}{\emph{minted}} and + \href{http://pygments.org}{\emph{pygments}}. +\end{frame} + \end{document} %%% Local Variables: