Skip to content

HTTPS clone URL

Subversion checkout URL

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

Cannot retrieve contributors at this time

854 lines (802 sloc) 27.769 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>
<p class="note">Genesis: 1990</p>
</div>
<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 ghc-prof 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>
<p class="note">als User alles nach ~/.cabal</p>
</div>
<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, Int nicht</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>
<div class="slide">
<h2>Function Composition</h2>
<pre class="sh_haskell">Prelude> :i (.)
(.) :: (b -> c) -> (a -> b) -> a -> c -- Defined in `GHC.Base'
infixr 9 .
Prelude> :t (+ 5) . (* 3)
(+ 5) . (* 3) :: Num c => c -> c
Prelude> ((+ 5) . (* 3)) 23
74</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>type</h2>
<p>Typ-Alias</p>
<pre class="sh_haskell">type String = [Char]
<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>
<div class="slide">
<h2>Record-Syntax</h2>
<pre class="sh_haskell">data MeinTyp = MeinKonstruktor String Integer
Prelude> :t MeinKonstruktor
MeinKonstruktor :: String -> Integer -> MeinTyp
</pre>
<p>
Für <b>data</b> &amp; <b>newtype</b>
<span class="note">weiterhin mit nur 1 Feld</span>
</p>
<pre class="sh_haskell">data MeinTyp = MeinKonstruktor {
meinString :: String
, meinInteger :: Integer
}
<span class="note">-- Lesbare Konstruktion</span>
fnord = MeinKonstruktor {
meinString = "fnord"
, meinInteger = 23
}</pre>
<pre class="sh_haskell">Prelude> :t meinString <span class="note">Accessor</span>
meinString :: MeinTyp -> String
Prelude> :t meinInteger
meinInteger :: MeinTyp -> Integer
Prelude> meinInteger fnord
23</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>deriving</h2>
<section style="-moz-column-count: 2; -webkit-column-count: 2">
<p>Funktioniert mit grundlegenden Datentypen:</p>
<pre class="sh_haskell">class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool</pre>
<pre class="sh_haskell">class Eq a => Ord a where
compare :: a -> a -> Ordering</pre>
<pre class="sh_haskell">class Enum a where
succ :: a -> a
pred :: a -> a</pre>
<pre class="sh_haskell">class Bounded a where
minBound :: a
maxBound :: a</pre>
<pre class="sh_haskell">class Show a where
show :: a -> String</pre>
<pre class="sh_haskell">read :: Read a => String -> a</pre>
<p>Anwendungsbeispiel:</p>
<pre class="sh_haskell">Prelude> newtype Zeigbar =
Zeig String deriving Show
Prelude> putStrLn $ show $ Zeig "Hello"
Zeig "Hello"</pre>
</section>
</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>
<div class="slide">
<h2>Applicative - Motivation</h2>
<ul class="incremental">
<li>
<p>fmap <strong>liftet</strong> eine (normale) Funktion zu einer Funktion, die in einem Kontext verwendet werden kann</p>
<p>Man kann aber mit fmap keine Funktion, die selbst in einem Kontext liegt, auf Werte in einem Kontext anwenden</p>
</li>
<li>
<p>Z.B. kann man mit fmap keine Liste von Funktionen auf eine Liste von Werten anwenden</p>
</li>
<li style="list-style-type: none;">
<pre class="sh_haskell">$ ghci
Prelude> fmap [(+1), (+2)] [0,0]
<interactive>:2:6:
Couldn't match expected type `a0 -> b0' with actual type `[t0]'
In the first argument of `fmap', namely `[(+ 1), (+ 2)]'
In the expression: fmap [(+ 1), (+ 2)] [0, 0]
In an equation for `it': it = fmap [(+ 1), (+ 2)] [0, 0]
</pre>
</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 => Applicative f where
pure :: a -> f a
(<*>) :: f (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>Real World Haskell, Chapter 16: Parsec</h2>
<pre class="sh_haskell">import Text.ParserCombinators.Parsec
{- A CSV file contains 0 or more lines, each of which is terminated
by the end-of-line character (eol). -}
csvFile :: GenParser Char st [[String]]
csvFile =
do result &lt;- many line
eof
return result
-- Each line contains 1 or more cells, separated by a comma
line :: GenParser Char st [String]
line =
do result &lt;- cells
eol -- end of line
return result
-- Build up a list of cells. Try to parse the first cell, then figure out
-- what ends the cell.
cells :: GenParser Char st [String]
cells =
do first &lt;- cellContent
next &lt;- remainingCells
return (first : next)
-- The cell either ends with a comma, indicating that 1 or more cells follow,
-- or it doesn't, indicating that we're at the end of the cells for this line
remainingCells :: GenParser Char st [String]
remainingCells =
(char ',' >> cells) -- Found comma? More cells coming
&lt;|> (return []) -- No comma? Return [], no more cells
-- Each cell contains 0 or more characters, which must not be a comma or
-- EOL
cellContent :: GenParser Char st String
cellContent =
many (noneOf ",\n")
-- The end of line character is \n
eol :: GenParser Char st Char
eol = char '\n'
parseCSV :: String -> Either ParseError [[String]]
parseCSV input = parse csvFile "(unknown)" input</pre>
</div>
<div class="slide">
<h2>Real World Haskell, Chapter 16: Parsec</h2>
<pre class="sh_haskell">import Text.ParserCombinators.Parsec
csvFile = endBy line eol
line = sepBy cell (char ',')
cell = many (noneOf ",\n")
eol = char '\n'
parseCSV :: String -> Either ParseError [[String]]
parseCSV input = parse csvFile "(unknown)" input
</pre>
</div>
<!--
* Template Haskell (maloi) (20min)
-->
<div class="slide">
<h1>Profiling</h1>
<p>Beispiel aus Real World Haskell, Chapter 25:</p>
<div>
<pre class="sh_haskell">import System.Environment
import Text.Printf
main = do
[d] &lt;- map read `fmap` getArgs
printf "%f\n" (mean [1..d])
mean :: [Double] -> Double
mean xs = sum xs / fromIntegral (length xs)</pre>
</div>
<pre class="incremental">% time ./prof1 1e5
50000.5
./prof1 1e5 0.03s user 0.01s system 89% cpu 0.049 total
% time ./prof1 1e6
500000.5
./prof1 1e6 0.31s user 0.09s system 98% cpu 0.400 total
% time ./prof1 1e7
5000000.5
./prof1 1e7 2.95s user 0.60s system 97% cpu 3.626 total
% time ./prof1 1e8
zsh: killed ./prof1 1e8
./prof1 1e8 6.72s user 2.71s system 91% cpu 10.368 total</pre>
</div>
<div class="slide">
<h2>Time Profiling</h2>
<pre>% ghc --make -O2 -prof -caf-all -auto-all prof1
% ./prof1 1e7 +RTS -p <span class="note">-P, -pa</span>
5000000.5
% cat prof1.prof
Wed Aug 29 02:04 2012 Time and Allocation Profiling Report (Final)
prof1 +RTS -p -RTS 1e7
total time = 1.74 secs (1738 ticks @ 1000 us, 1 processor)
total alloc = 1,680,119,104 bytes (excludes profiling overheads)
COST CENTRE MODULE %time %alloc
main Main 86.6 100.0
mean Main 13.4 0.0
individual inherited
COST CENTRE MODULE no. entries %time %alloc %time %alloc
MAIN MAIN 55 0 0.0 0.0 100.0 100.0
main Main 111 0 86.6 100.0 100.0 100.0
mean Main 113 1 13.4 0.0 13.4 0.0
CAF:main1 Main 108 0 0.0 0.0 0.0 0.0
main Main 110 1 0.0 0.0 0.0 0.0
CAF:main3 Main 107 0 0.0 0.0 0.0 0.0
main Main 112 0 0.0 0.0 0.0 0.0
CAF GHC.Conc.Signal 101 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Encoding 100 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Handle.FD 99 0 0.0 0.0 0.0 0.0
CAF Text.Read.Lex 95 0 0.0 0.0 0.0 0.0
CAF GHC.Float 90 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Encoding.Iconv 82 0 0.0 0.0 0.0 0.0</pre>
</div>
<div class="slide">
<h2>Space Profiling</h2>
<pre>% ghc --make -rtsopts -prof -caf-all -auto-all prof1
% ./prof1 1e6 +RTS -K256M -hc -i0.01
% hp2ps -c prof1.hp</pre>
<img src="prof1-hc.svg"/>
</div>
<div class="slide">
<h2>Space Profiling</h2>
<pre>% ./prof1 1e6 +RTS -K256M -hy -i0.01
% hp2ps -c prof1.hp</pre>
<img src="prof2-hy.svg"/>
<p class="note">Auch: GHC Core output</p>
</div>
<div class="slide">
<h2>Strictness</h2>
<pre class="sh_haskell">import System.Environment
import Text.Printf
import Data.List (foldl')
main = do
[d] &lt;- map read `fmap` getArgs
printf "%f\n" (mean [1..d])
mean :: [Double] -> Double
mean xs = s / fromIntegral n
where
(n, s) = foldl' k (0, 0) xs
k (n, s) x = n `seq` s `seq` (n+1, s+x)</pre>
<pre>% ./prof2 1e8 +RTS -sstderr
50000000.5
53,600,200,824 bytes allocated in the heap
31,319,592 bytes copied during GC
62,720 bytes maximum residency (1 sample(s))
26,816 bytes maximum slop
1 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 102796 colls, 0 par 0.66s 0.66s 0.0000s 0.0003s
Gen 1 1 colls, 0 par 0.00s 0.00s 0.0006s 0.0006s
INIT time 0.00s ( 0.00s elapsed)
MUT time 32.71s ( 32.84s elapsed)
GC time 0.66s ( 0.66s elapsed)
RP time 0.00s ( 0.00s elapsed)
PROF time 0.00s ( 0.00s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 33.38s ( 33.50s elapsed)
%GC time 2.0% (2.0% elapsed)
Alloc rate 1,638,238,233 bytes per MUT second
Productivity 98.0% of total user, 97.7% of total elapsed
</pre>
<p class="note">In RWH: unboxed strict fields, fusion w/o heap alloc</p>
</div>
<!--
* 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.