--- class: center, middle # Trondheim Haskell Users' Group Alexander Berntsen, plaimi, 2015 ![plaimi](logo.svg) --- # What is this group for? * Bring people together through their shared interest in the Haskell programming language * Talk and learn about Haskell * Talk and learn about anything else the members find interesting * This group is for its members — *you* tell *me* what it's about! --- # Immediate plans * This talk (the meta + a brief Haskell intro) * A series of Haskell workshoppes taking you from complete newbie to only partial newbie * That's it, folks * This talk is just meant to give you an overview and inspiration for you to do your own research, but please feel free to ask questions! * The workshoppes will go more in-depth and aim to actually teach you Haskell ---
---
--- # Network * http://haskell.no * http://www.meetup.com/Oslo-Haskell/ * \#haskell.no on irc.freenode.net # Work * http://applikativ.no/ * http://secure.plaimi.net/ * http://systorvest.no/ --- # The Haskell programming language * Non-strict semantics * Type safety * Static verification * Functional programming * Functional purity * Higher-kinded polymorphism --- # Non-strict semantics * In a strict semantics, .code[$f$ $x$] where .code[$x$] doesn't have an answer, .code[$f$ $x$] doesn't have an answer * But in a non-strict semantics, some .code[$f$]s may have an answer nonetheless * Consider the following example, where .code[$fibs$] is effectively .code[$x$], and .code[$10fibs$] is .code[$f$] ```haskell fibs = 0 : scanl (+) 1 fibs 10fibs = take 10 fibs ``` * In implementations of non-strict semantics, things are not evaluated unless they are used --- * The two main ideas are call-by-name and call-by-need evaluation * In call-by-name evaluation, arguments are substituted into the function body when the function is called, and evaluated when they appear in the function * Call-by-need is a memoised version of this — i.e. when evaluating a function argument, the value is stored for future use rather than re-evaluated when the function is called again --- * Functional programmers tend to say *lazy evaluation* when they talk about call-by-need * GHC (the de-facto standard Haskell compiler) implements lazy evaluation * So the implementation strategy is that expressions are not evaluated until their values are needed (non-strict semantics), and sharing — i.e. repeated evaluations — is avoided (lazy/call-by-need evaluation) --- * We're not going to talk a lot about the trade-offs of lazy evaluation vs. eager evaluation right now * But here's one important motivating example ```haskell take :: Int -> [a] -> [a] take _ [] = [] take 0 _ = [] take n (x:xs) = x: take (n - 1) xs sort :: Ord a => [a] -> [a] sort [] = [] sort (x:xs) = sort ys ++ [x] ++ sort zs where (ys, zs) = partition (
> x + y ``` ```haskell -- The main program used to evaluate these functions in both languages main = let a = f 4 2 in print a >> print a ```
Call-by-need
Call-by-value
$x + y$
$6$
$6$
$6$
$6$
$print$ $''Hallo'' >> x + y$
$Hallo!$
$6$
$6$
$Hallo!$
$6$
$Hallo!$
$6$
--- * $print$ $''Hallo!''$ is evaluated once in call-by-need, but twice in call-by-value * Printing stuff is a side-effect! * So a side-effect is something which has an observeable interaction with the outside world * Other side-effects in impure languages include getting controller input, drawing stuff onto the screen, talking to other computers over the network, and so on * Haskell has no side-effects! --- * Printing, drawing, networking, and input handling is unsafe, because they make it difficult to reason about your program
* Printing, drawing, networking, and input handling is very useful, because hurr durr --- * So… how does Haskell… well… *do stuff*? * Where other languages make I/O and other awkward things as simple to do as possible, Haskell makes it difficult — let's admit it, I/O *is* difficult * But I/O is very *useful*, so Haskell has a sophisticated type system that helps ensure soundness *while letting us write useful programs*! --- ```haskell let l = getLine in "Hallo, " ++ l ``` * This would be okay in most languages — but in Haskell it doesn't even pass typechecking * .code[$l$] is an .code[$IO$ $String$], but .code[$''Hallo, ''$] is just a regular .code[$String$], and .code[$++$] works with regular .code[$String$s] only * So we have something of type .code[$\alpha$], something of .code[$\phi\beta$ ], and then we have a function that's .code[$\alpha \rightarrow \alpha \rightarrow \alpha$] * What do we need to apply .code[$\alpha \rightarrow \alpha \rightarrow \alpha$] to something that's .code[$\phi\beta$]? --- ```haskell let l = getLine in fmap ("Hallo, " ++) l ``` * .code[$fmap$] lets us (amongst other things) apply a function that expects *no* computational context to something that *has* a computational context * In addition to I/O, there are several other computational contexts — .code[$fmap$] is agnostic in this regard, and works on other contexts too ```haskell fmap (+1) [1, 2, 3] -- [2, 3, 4] ``` * In the coming workshoppes we'll see how .code[$fmap$] and friends lets us write useful code that's safe! --- * Purity is arguably Haskell's main selling point * It lets us, in theory, β-reduce (substitute equals for equals) our entire program predictably Given these functions: ```haskell f x y = x + y g x = x * 2 ``` And this expression: ```haskell (\x -> f x (g x)) 42 ``` We can β-reduce it quite a bit. Let's give it a go! --- First we inline the argument to the lambda ```haskell f 42 (g 42) ``` Then we inline f ```haskell 42 + (g 42) ``` Then we inline g ```haskell 42 + 42 * 2 ``` Then we maths ```haskell 42 + 84 ``` ```haskell 126 ``` --- # Higher-kinded polymorphism * The fact that .code[$fmap$] doesn't care about the computational context is kind of a big deal * This is called higher-kinded polymorphism * With just plain old type polymorphism we could write a .code[$length$] function that works on .code[$\[\alpha\]$] — a list with elements of any type * But with higher-kinded polymorphism we can have .code[$\phi$ $\alpha$] — any type of collection, with elements of any type! --- # Other things about Haskell & GHC * Type inference — data types are often deduced automatically, so that you don't need to annotate everything all the time ```haskell λ :t 5 5 :: Num a => a λ :t 5.0 5.0 :: Fractional a => a λ let f x = x λ :t f f :: t -> t λ :t f 5.0 f 5.0 :: Fractional t => t λ :t intercalate 5.0 intercalate 5.0 :: Fractional [a] => [[a]] -> [a] ``` --- * Algebraic data types — data types may be sums (.code[$data$ $D$ $=$ $A$ $|$ $B$]) or products (.code[$data$ $D$ $a$ $b$ $=$ $D$ $A$ $B$]) * Pattern matching — deconstruct a data type to explicitly match its value(s) ```haskell lessThanSix 1 = Just 1 lessThanSix 2 = Just 2 lessThanSix x = case x of 3 -> Just 3 4 -> Just 4 _ -> fiveOrSix x where fiveOrSix 5 = Just 5 fiveOrSix 6 = Just 6 fiveOrSix _ = Nothing ``` --- * Typeclasses — a form of ad-hoc polymorphism that lets you do bounded qualification ```haskell max :: Ord a => a -> a -> a max x y | x >= y = x | otherwise = y ``` * Garbage collection — memory occupied by objects that the program no longer needs is freed, abstracting away memory management * And finally, Haskell is a *general-purpose* programming language suited for most things, and very often used to implement programming languages, compilers, parsers, domain specific languages, and other things