/
index.html
1004 lines (944 loc) · 32.4 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?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 & 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, h1, h2, h3, h4 {
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 & Yesod</h1>
<ul class="speakers">
<li>maloi <mm@noexample.de></li>
<li>Astro <astro@spaceboyz.net></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">-> 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 -> 1
_ -> 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 <= 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 <= 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]</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>
<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> & <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 & 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 <- many line
eof
return result
-- Each line contains 1 or more cells, separated by a comma
line :: GenParser Char st [String]
line =
do result <- 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 <- cellContent
next <- 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
<|> (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 class="incremental">Beispiel aus Real World Haskell, Chapter 25:</p>
<div class="incremental">
<pre class="sh_haskell">import System.Environment
import Text.Printf
main = do
[d] <- 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="prof1-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] <- 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)
-->
<div class="slide cover">
<h1>Strictness</h1>
<p class="note">Stream processing</p>
<p class="note">Gegen unkontrollierte Lazyness</p>
</div>
<div class="slide">
<h2>ResourceT m a</h2>
<pre class="sh_haskell">Control.Monad.Trans.Resource> :i MonadResource
class (MonadThrow m, MonadUnsafeIO m,
Control.Monad.IO.Class.MonadIO m,
Control.Applicative.Applicative m) => MonadResource m where
register :: IO () -> m ReleaseKey
release :: ReleaseKey -> m ()
allocate :: IO a -> (a -> IO ()) -> m (ReleaseKey, a)
resourceMask ::
((forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b)
-> m b
-- Defined in `Control.Monad.Trans.Resource'
</pre>
</div>
<div class="slide">
<h2>Pipe Type</h2>
<pre class="sh_haskell">Data.Conduit> :i Pipe
data Pipe l i o u m r
= Data.Conduit.Internal.HaveOutput (Pipe l i o u m r) (m ()) o
| Data.Conduit.Internal.NeedInput (i -> Pipe l i o u m r)
(u -> Pipe l i o u m r)
| Data.Conduit.Internal.Done r
| Data.Conduit.Internal.PipeM (m (Pipe l i o u m r))
| Data.Conduit.Internal.Leftover (Pipe l i o u m r) l
instance Monad m => Monad (Pipe l i o u m)
instance Monad m => Functor (Pipe l i o u m)</pre>
<pre class="sh_haskell">Data.Conduit> :i Conduit
type Conduit i m o = Pipe i i o () m ()</pre>
<pre class="sh_haskell">Data.Conduit> :i Source
type Source m o = Pipe () () o () m ()</pre>
<pre class="sh_haskell">Data.Conduit> :i Sink
type Sink i m r = Pipe i i Data.Void.Void () m r</pre>
</pre>
</div>
<div class="slide">
<h2>Conduit Operators</h2>
<pre class="sh_haskell">Data.Conduit> :i ($$)
($$) :: Monad m => Source m a -> Sink a m b -> m b
infixr 0 $$</pre>
<pre class="sh_haskell">Data.Conduit> :i (=$=)
(=$=) :: Monad m => Conduit a m b -> Conduit b m c -> Conduit a m c
infixr 2 =$=</pre>
<pre class="sh_haskell">Data.Conduit> :i ($=)
($=) :: Monad m => Source m a -> Conduit a m b -> Source m b
infixl 1 $=</pre>
<pre class="sh_haskell">Data.Conduit> :i (=$)
(=$) :: Monad m => Conduit a m b -> Sink b m c -> Sink a m c
infixr 2 =$</pre>
</div>
<div class="slide">
<h2>Beispiel: cp</h2>
<pre class="sh_haskell">module Main (main) where
import Data.Conduit
import qualified Data.Conduit.Binary as CB
import System.Environment (getArgs)
copyFile :: FilePath -> FilePath -> IO ()
copyFile src dest = runResourceT $ CB.sourceFile src $$ CB.sinkFile dest
main = getArgs >>= \[src, dest] ->
copyFile src dest</pre>
</div>
<div class="slide">
<h2>Beispiel: Bytes zählen</h2>
<pre class="sh_haskell">{-# LANGUAGE BangPatterns #-}
module Main (main) where
import Data.Conduit
import qualified Data.Conduit.Binary as CB
import System.Environment (getArgs)
import Control.Monad.Trans
import qualified Data.ByteString as B
copyFile :: FilePath -> FilePath -> IO ()
copyFile src dest = runResourceT $
CB.sourceFile src $=
countBytes $$
CB.sinkFile dest
main = getArgs >>= \[src, dest] ->
copyFile src dest
countBytes :: MonadIO m => Conduit B.ByteString m B.ByteString
countBytes =
let loop !total =
do mBuf <- await
case mBuf of
Just buf ->
do yield buf
loop $ total + B.length buf
Nothing ->
do liftIO $ putStrLn $
"Transferred " ++
show total ++
" bytes"
return ()
in loop 0</pre>
</div>
<div class="slide">
<h2>WAI: Web Application Interface</h2>
<pre class="sh_haskell">Network.Wai> :i Application
type Application =
Request -> ResourceT IO Response</pre>
<pre class="sh_haskell">Network.Wai> :i Middleware
type Middleware = Application -> Application</pre>
<pre class="sh_haskell">Network.Wai.Middleware.Autohead> :t autohead
autohead :: Network.Wai.Middleware
Network.Wai.Middleware.Gzip> :t gzip
gzip :: GzipSettings -> Network.Wai.Middleware</div>
</div>
<div class="slide">
<h2>WAI Request & Response</h2>
<pre class="sh_haskell">Prelude Network.Wai> :i Request
data Request
= Request {requestMethod :: Method,
httpVersion :: HttpVersion,
rawPathInfo :: ByteString,
rawQueryString :: ByteString,
serverName :: ByteString,
serverPort :: Int,
requestHeaders :: RequestHeaders,
isSecure :: Bool,
remoteHost :: SockAddr,
pathInfo :: [Text],
queryString :: Query,
requestBody :: Source (ResourceT IO) ByteString,
vault :: Vault}</pre>
<pre class="sh_haskell">Prelude Network.Wai> :i Response
data Response
= ResponseFile Status ResponseHeaders FilePath (Maybe FilePart)
| ResponseBuilder Status ResponseHeaders Builder
| ResponseSource Status ResponseHeaders (Source (ResourceT IO) (Flush Builder))</pre>
</div>
<div class="slide">
<h2>WAI: Motivation</h2>
<img src="preliminary-warp-cross-language-benchmarks.png"/>
<p>
<a href="http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks">www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks</a>
</p>
</div>
<!--
* 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)