Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tree: f3ec08ed81
Fetching contributors…

Cannot retrieve contributors at this time

575 lines (549 sloc) 18.045 kb
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="de" xml:lang="de">
<head>
<title>Themenabend Haskell &amp; Yesod</title>
<!-- Slidy: http://www.w3.org/Talks/Tools/Slidy2/ -->
<link rel="stylesheet" type="text/css" media="screen, projection, print" href="slidy.css" />
<script src="slidy.js" charset="utf-8"
type="text/javascript"></script>
<!-- Highlighting: http://zenzike.com/posts/2010-10-14-highlighting-haskell-with-shjs -->
<link rel="stylesheet" type="text/css" href="sh_style.css" />
<script type="text/javascript" src="sh_main.js" > </script>
<script type="text/javascript" src="sh_haskell.js" > </script>
<script type="text/javascript" src="sh_init.js" > </script>
<!-- Custom style -->
<style type="text/css">
.cover {
text-align: center;
}
.speakers {
margin: 1em 0;
}
.speakers li {
list-style-type: none;
margin: 0;
padding: 0;
}
@media screen {
.note { display: none; visibility: visible }
.toolbar { display:none }
}
@media print {
.note { display: block; visibility: visible; color: red; font-size: 110%; line-height: 1.5em; }
}
</style>
</head>
<body onload="sh_highlightDocument();">
<div class="slide cover">
<h1>Themenabend Haskell &amp; Yesod</h1>
<ul class="speakers">
<li>maloi &lt;mm@noexample.de&gt;</li>
<li>Astro &lt;astro@spaceboyz.net&gt;</li>
</ul>
<p>Chaos Computer Club Dresden</p>
<p>2012-08-29</p>
</div>
<!--
Geplante Agenda, entferne was du in Folien umgesetzt hast.
* Intro: (astro) (10 min)
  * Hayoo/Hoogle
-->
<div class="slide">
<h2>Hilfe</h2>
<ul>
<li>
haskell.org
<ul>
<li>Library documentation</li>
<li>Hackage library database</li>
</ul>
</li>
<li><a href="http://book.realworldhaskell.org/read/">Real World Haskell</a></li>
<li><a href="http://www.learnyouahaskell.com/">Learn You a Haskell</a></li>
<li>
Funktionssuche:
<ul>
<li><a href="http://holumbus.fh-wedel.de/hayoo/hayoo.html">Hayoo!</a></li>
<li><a href="http://www.haskell.org/hoogle/">Hoogle</a></li>
</ul>
</li>
</ul>
</div>
<div class="slide">
<h2>Paket-Management mit Cabal</h2>
<pre>apt-get install ghc cabal-install
# Updates list of known packages
cabal update
# Installs package with library profiling
cabal install -p yesod-platform</pre>
<p class="note">Glasgow Haskell Compiler</p>
<p class="note">Mit Dependencies</p>
<p class="note">-p für Profiling</p>
</div>
<!--
* Syntax, Currying, Typen, Lazyness  (astro)  (min. 30min)
-->
<div class="slide cover">
<h1>Syntax</h1>
</div>
<div class="slide">
<h2>Funktionen</h2>
<pre class="sh_haskell">fac :: Integer -> Integer
fac 1 = 1
fac n = n * fac (n - 1)
</pre>
<p class="note">Fakultät</p>
<p class="note">-&gt; Impliziert</p>
<p class="note">Pattern matching des Parameters</p>
<p class="note">Integer is bignum</p>
<h2>case</h2>
<pre class="sh_haskell">fac' :: Integer -> Integer
fac' n =
case n of
1 -&gt; 1
_ -&gt; n * fac (n - 1)
</pre>
<p class="note">Pattern matching</p>
<p class="note">Anonyme Variable</p>
</div>
<div class="slide">
<h2>Guards</h2>
<pre class="sh_haskell">fac'' :: Integer -> Integer
fac'' n
| n &lt;= 1 = 1
| otherwise = n * fac (n - 1)
</pre>
<p class="note">Boolean expression</p>
<h2>if then else</h2>
<pre class="sh_haskell">fac''' :: Integer -> Integer
fac''' n =
if n &lt;= 1
then 1
else n * fac (n - 1)
</pre>
<p class="note">Boolean expression</p>
</div>
<div class="slide">
<h2>Listen</h2>
<pre class="sh_haskell">$ ghci <p class="note">REPL</p>
Prelude> 2 : []
[2]
Prelude> 23 : []
[23]
Prelude> 23 : 42 : []
[23,42]
Prelude> 23 : 42 : 5 : []
[23,42,5]
Prelude> :t (:)
(:) :: a -> [a] -> [a]
</pre>
<pre class="sh_haskell">Prelude> :t map
map :: (a -> b) -> [a] -> [b]
Prelude> :t filter
filter :: (a -> Bool) -> [a] -> [a]
Prelude> :t foldl
foldl :: (a -> b -> a) -> a -> [b] -> a
</pre>
<p class="note"></p>
</div>
<div class="slide">
<h2>let</h2>
<pre class="sh_haskell">fib :: Integer -> Integer
fib 0 = 0
fib 1 = 1
fib n =
let r = fib $ n - 1
r' = fib $ n - 2
in r + r'
</pre>
<h2>where</h2>
<pre class="sh_haskell">facs = 1 : go 2
where go :: Integer -> [Integer] <span class="note">“Unterfunktion”</span>
go n = n : map (* n) (go $ n + 1)
Prelude> :t facs <span class="note">Inferred type</span>
facs :: [Integer]
Prelude> facs !! 500 <span class="note">Unendlich, lazy</span>
611288549821546144419320631496946510053040745744399613938399207781308531950094880800353720198603844213369821855051249995665852739761166777440873387784823972024431693541604632490253390402221485016448489094881275898497140756808655499992463957536774753658273522343143352081610678258299859781290947510064133164625417126214683287364306533202043771696934819148200603488701298578593288295101675375228475039194518540926501811512211084741146359555616051391364512171815202852428391973770531819587555590747725222707870915089204322125602187745638954304887403405330317436980872692673627514602895425139803517823839455807896878364709108235036658336397561844224198282288969461157203049314666899393600517284430144216183492154249948251192663554129489210224225335784718743202172831724716080857069568307715110065035130707514179942202121569852186583424945734289322385681601382444331381680307765142985006245859526451817213228740320341074735777885270328149239431528071389670544598095262337701383222299067569757970109034425702794542448640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
</pre>
<p class="note">($)</p>
</div>
<div class="slide">
<h2>Lambdas</h2>
<p class="note">Num: Interface für (+), (*)</p>
<pre class="sh_haskell">Prelude> :t (\n -> n + 1)
(\n -> n + 1) :: Num a => a -> a
Prelude> (\n -> n + 1) 22
23
</pre>
<pre class="sh_haskell">Prelude> :t (\a b c -> a * b * c)
(\a b c -> a * b * c) :: Num a => a -> a -> a -> a
</pre>
<pre class="sh_haskell">Prelude> :t (\a -> \b -> \c -> a * b * c)
(\a -> \b -> \c -> a * b * c) :: Num a => a -> a -> a -> a
</pre>
<p class="note">Umkehrschluß: Currying</p>
</div>
<div class="slide">
<h2>Currying</h2>
<pre class="sh_haskell">:t map (\a -> a + 1)
map (\a -> a + 1) :: Num b => [b] -> [b]
</pre>
<h2>Sections</h2>
<pre class="sh_haskell">Prelude> :t (+ 1)
(+ 1) :: Num a => a -> a
Prelude> map (+ 1) [1..10]
[2,3,4,5,6,7,8,9,10,11]
</pre>
</div>
<!-- Types -->
<div class="slide">
<h2>data</h2>
<p class="note">Statt NULL-Pointer</p>
<pre class="sh_haskell">data Maybe a = Nothing
| Just a
</pre>
<pre class="sh_haskell">Prelude> :t Nothing <span class="note">Constructors</span>
Nothing :: Maybe a <span class="note">Passt auf alle a</span>
Prelude> :t Just
Just :: a -> Maybe a
</pre>
<pre class="sh_haskell">data [] a = []
| a : [a]</pre>
<h2>newtype</h2>
<pre class="sh_haskell">newtype Name = Name String <span class="note">Typename = Ctor</span></pre>
<ul>
<li>Darf nur 1 Feld haben</li>
<li>Billig zur Laufzeit</li>
<li>Typsicher zur Compile-Zeit</li>
</ul>
</div>
<!-- Classes, instances -->
<div class="slide">
<h2>Classes &amp; Instances</h2>
<pre class="sh_haskell">class Show a where
show :: a -> String</pre>
<pre class="sh_haskell">instance Show MeinTyp where
show (MeinDatum n) = "MeinDatum " ++ show n</pre>
<p>Wie <i>interface</i> in Java</p>
<pre class="sh_haskell">Prelude> :i Num
class Num a where
(+) :: a -> a -> a
(*) :: a -> a -> a
(-) :: a -> a -> a
negate :: a -> a
abs :: a -> a
signum :: a -> a
fromInteger :: Integer -> a
-- Defined in `GHC.Num'
instance Num Integer -- Defined in `GHC.Num'
instance Num Int -- Defined in `GHC.Num'
instance Num Float -- Defined in `GHC.Float'
instance Num Double -- Defined in `GHC.Float'</pre>
</div>
<div class="slide">
<h2>Module</h2>
<p>Am Beginn von Quellcode-Dateien:</p>
<pre class="sh_haskell">module MeinKram where</pre>
<pre class="sh_haskell" style="margin-top: 6em">module Main (main) where
import MainKram
import qualified Data.Text as T
fnord :: T.Text
fnord = T.pack "fnord"</pre>
</div>
<!--
* Monads, Functors, Applicatives (maloi) (30 min)
-->
<div class="slide cover">
<h1>Functor, Applicative, Monad</h1>
</div>
<div class="slide">
<h2>Functors - Motivation</h2>
<ul class="incremental">
<li>
<p>Eine Funktion, die jeder liebt:</p>
<pre class="sh_haskell">map :: (a -> b) -> [] a -> [] b -- map :: (a -> b) -> [a] -> [b]</pre>
</li>
<li>
<p>Wie sieht so eine Funktion z.B. fuer Baeume aus?</p>
<pre class="sh_haskell">data Tree a = Leaf a | Node a (Tree a) (Tree a)</pre>
<pre class="sh_haskell">mapTree :: (a -> b) -> Tree a -> Tree b</pre>
</li>
<li>
<p>Maybe just nothing</p>
<pre class="sh_haskell">data Maybe a = Just a | Nothing</pre>
<pre class="sh_haskell">mapMaybe :: (a -> b) -> Maybe a -> Maybe b</pre>
</li>
</ul>
</div>
<div class="slide">
<h2>Functors - Motivation (2)</h2>
<ul class="incremental">
<li style="list-style-type: none;">
<pre class="sh_haskell">map :: (a -> b) -> [] a -> [] b</pre>
<pre class="sh_haskell">mapTree :: (a -> b) -> Tree a -> Tree b</pre>
<pre class="sh_haskell">mapMaybe :: (a -> b) -> Maybe a -> Maybe b</pre>
</li>
<li>
<p>Die Funktionen haben - bis auf Umbenennung des Typ-Konstruktors - die gleiche Signatur</p>
</li>
<li>
<p><strong>Type classes to the rescue!</strong></p>
</li>
<li>
<p>Zuvor aber ein kleiner Ausflug</p>
</li>
</ul>
</div>
<div class="slide">
<h2>Kinds: Typen von Typen - WTF?</h2>
<ul class="incremental">
<li>
<p>In Haskell hat jeder Ausdruck einen Typ</p>
</li>
<li>
<p>Diese Typen haben wiederum "Typen" - <strong>Kinds</strong></p>
</li>
<li>
<!--<p>Jeder (monomorphe) Typ (nullstelliger Typ-Konstuktor) hat Kind <strong>*</strong></p>-->
<p><strong>*</strong> ist der Kind jedes Datentyps (nullstelliger Typ-Konstruktor)</p>
<p>Diese Typen beschreiben Werte</p>
</li>
<li>
<p><strong>k1->k2</strong> ist der Kind von einstelligen Typ-Konstruktoren, die Typen von Kind <strong>k1</strong> nehmen und Typen von Kind <strong>k2</strong> erzeugen</p>
</li>
</ul>
</div>
<div class="slide">
<h2>Kinds: Beispiele</h2>
<ul class="incremental">
<li>
<p>Monomorph</p>
<pre class="sh_haskell">Int :: * -- z.B. 42</pre>
<pre class="sh_haskell">Maybe Int :: * -- z.B. Just 23</pre>
<pre class="sh_haskell">Int -> Int :: * -- z.B. (+23)</pre>
</li>
<li>
<p>Polymorph</p>
<pre class="sh_haskell">Maybe :: * -> *</pre>
<pre class="sh_haskell">(->) :: * -> *</pre>
<pre class="sh_haskell">(,,) :: * -> * -> *</pre>
</li>
<li>
<p>Lustig</p>
<pre class="sh_haskell">data Funny f a = Funny a (f a)
Funny :: (* -> *) -> * -> *</pre>
</li>
</ul>
</div>
<div class="slide">
<h2>Functors redux</h2>
<ul class="incremental">
<li style="list-style-type: none;">
<pre class="sh_haskell">map :: (a -> b) -> [] a -> [] b</pre>
<pre class="sh_haskell">mapTree :: (a -> b) -> Tree a -> Tree b</pre>
<pre class="sh_haskell">mapMaybe :: (a -> b) -> Maybe a -> Maybe b</pre>
</li>
<li>
<p>Zusammengefasst ergibt sich also folgendes:</p>
<pre class="sh_haskell">map :: (a -> b) -> f a -> f b</pre>
</li>
<li>
<p><strong>f</strong> ist demnach vom Kind <strong>* -> *</strong></p>
</li>
<li>
<p>Ist es moeglich die Funktion einmalig fuer alle Typen dieses Kinds schreiben?</p>
</li>
<li>
<p><strong>Nein</strong>, natuerlich nicht!</p>
</li>
</ul>
</div>
<div class="slide">
<h2>Functor - the easy type class</h2>
<ul class="incremental">
<li style="list-style-type: none;">
<pre class="sh_haskell">class Functor f where
fmap :: (a -> b) -> f a -> f b</pre>
</li>
<li>
<h3>Intuition<h3>
</li>
<li>
<p>Ein Functor stellt eine Art <strong>Container</strong> dar, der es ermoeglicht (mit fmap) eine Funktion (uniform) auf alle Elemente in diesem Container anzuwenden</p>
</li>
<li>
<p>Alternativ dazu kann man Functor auch als einen <strong>computational context</strong> sehen und fmap wendet eine Funktion auf einen Wert in einem Kontext an ohne diesen Kontext zu aendern</p>
</li>
</ul>
</div>
<div class="slide">
<h2>Functor - Kind is kind of important</h2>
<ul class="incremental">
<li style="list-style-type: none;">
<pre class="sh_haskell">instance Functor Int where
fmap = ...</pre>
</li>
<li style="list-style-type: none;">
<pre class="sh_haskell">
[1 of 1] Compiling Main ( 2012-03-15.lhs, interpreted )
2010-10-25.lhs:145:19:
Kind mis-match
The first argument of `Functor' should have kind `* -> *',
but `Int' has kind `*'
In the instance declaration for `Functor Int'
</pre>
</li>
<li>
<p>Wie die Fehlermeldung vermuten laesst, hat Int den Kind *</p>
<p>Functor moechte aber, dass sein erstes Argument Kind * -> * hat</p>
</li>
</ul>
</div>
<div class="slide">
<h2>Functor - Listen </h2>
<ul class="incremental">
<li style="list-style-type: none;">
<pre class="sh_haskell">instance Functor [] where
fmap _ [] = []
fmap g (x:xs) = g x : fmap g xs -- oder einfach fmap = map</pre>
</li>
<li>
<p>Listen sind ein gutes Beispiel fuer einen Functor, der als Container - ueber den man mappen kann - aufgefasst werden kann</p>
</li>
<li>
<p>Kann aber auch als Berechnung mit nicht-deterministischen Ergebnis gesehen werden</p>
</li>
<li>
<p>Da fmap den Kontext nicht aendert ist das Resultat wiederum nicht-deterministisch</p>
</li>
<li style="list-style-type: none;">
<pre class="sh_haskell">$ ghci
Prelude> fmap (+1) [1,2,3]
[2,3,4]</pre>
</li>
</ul>
</div>
<div class="slide">
<h2>Functor - Maybe baby </h2>
<ul class="incremental">
<li style="list-style-type: none;">
<pre class="sh_haskell">instance Functor Maybe where
fmap _ Nothing = Nothing
fmap g (Just a) = Just (g a)</pre>
</li>
<li>
<p>Maybe kann als Container gesehen werden, der ein Element haben <strong>kann</strong></p>
</li>
<li>
<p>Oder als Berechnung mit moeglichem Fehlschlag</p>
</li>
<li style="list-style-type: none;">
<pre class="sh_haskell">$ ghci
Prelude> fmap (+23) (Just 19)
Just 42
Prelude> fmap (+23) Nothing
Nothing</pre>
</li>
</ul>
</div>
<div class="slide">
<h2>Functor - Do you read me? </h2>
<ul class="incremental">
<li style="list-style-type: none;">
<pre class="sh_haskell">instance Functor ((->) r) where
fmap f g = (.) -- (\x -> f (g x))</pre>
</li>
<li style="list-style-type: none;">
<pre class="sh_haskell">fmap :: (a -> b) -> f a -> f b
fmap :: (a -> b) -> ((->) r a) -> ((->) r b)
fmap :: (a -> b) -> (r -> a) -> (r -> b)</pre>
</li>
<li style="list-style-type: none;">
<pre class="sh_haskell">(.) :: (b -> c) -> (a -> b) -> a -> c</pre>
</li>
<li>
<p>Container, der mit Werten vom Typ r indiziert ist</p>
</li>
<li>
<p>Berechnung, die Werte in einer (read-only) Umgebung nachschlagen kann</p>
</li>
<li>
<p><strong>(->) r</strong> wird deshalb oftmals auch als <strong>reader monad</strong> bezeichnet (mehr dazu spaeter)</p>
</li>
<li style="list-style-type: none;">
<pre class="sh_haskell">$ ghci
Prelude> :m Control.Monad.Instances
Prelude Control.Monad.Instances> fmap (*3) (+10) $ 1
33
Prelude Control.Monad.Instances> (fmap (*3) (+10) $ 1) == ((*3) . (+10) $ 1)
True</pre>
</li>
</ul>
</div>
<div class="slide">
<h2>Functor - Sin is lawlessness </h2>
<ul class="incremental">
<li style="list-style-type: none;">
<pre class="sh_haskell">1. fmap id = id -- id = (\x -> x) und damit id :: a -> a
2. fmap (g . h) = (fmap g) . (fmap h)</pre>
</li>
<li>
<p>Sichern, dass fmap nur die Werte, nicht aber deren Kontext aendert</p>
</li>
<li>
<p>1. Wenn man id ueber einen Functor mapped, sollte der resultierende Functor gleich dem urspruenglichen sein</p>
</li>
<li>
<p>2. Es ist egal ob man die Komposition zweier Funktionen ueber einen Functor mapped oder erst die eine Funktion mapped und dann die andere</p>
</li>
</ul>
</div>
<div class="slide">
<h2>Functor - I break the law </h2>
<ul class="incremental">
<li style="list-style-type: none;">
<pre class="sh_haskell">instance Functor [] where
fmap _ [] = []
fmap g (x:xs) = g x : g x : fmap g xs
</pre>
</li>
<li>
<p>Gueltige Functor Instanz</p>
</li>
<li>
<p><strong>Aber:</strong> haelt sich nicht an das erste Gesetz!</p>
<pre class="sh_haskell">fmap id [1,2,3] == [1,1,2,2,3,3]
id [1,2,3] == [1,2,3]
</pre>
</li>
<li>
<p><strong>Und:</strong> haelt sich nicht an das zweite Gesetz!</p>
<pre class="sh_haskell">fmap (id . id) [1,2,3] == [1,1,2,2,3,3]
(fmap id) . (fmap id) $ [1,2,3] == [1,1,1,1,2,2,2,2,3,3,3,3]
</pre>
</li>
</ul>
</div>
<!--
* Combinatoric Parsing: Attoparsec (astro) (15 min)
* Template Haskell (maloi) (20min)
* Profiling (astro) (15min)
* Parallel Haskell (maloi) (10min)
* Foreign (astro) (5min)
* Yesod:
 * Conduits (astro) (15 min)
*
 * Wai (astro) (10 min)
* Frontend, middlewares, backend (graphic)
 * Handlers & Hamlet (astro) (25 min)
* App construction
* Routing
* RESTful content
* Hamlet, Whamlet
* I18N
 * Persistent (maloi) (10min)
-->
</body>
</html>
Jump to Line
Something went wrong with that request. Please try again.