Why Haskell Matters

    Roman Gonzalez

  Vancouver Haskell Meetup


   October 20, 2010
So what is this language about?


          Haskell is a pure, statically typed, lazy functional
       programming language.




    → Name inspired by mathematician Haskell Brooks Curry


    → Based on a more primitive language called Lambda Calculus


    → There is no iteration or sequences of actions, everything is
      recursive
When learning Haskell is a good idea?

    → If you are a experienced developer that wants to grow
      professionally by learning completely new and different
      approaches to solve problems


    → If you need to build systems where correctness is critical
      (Banks, Safety-Critical Systems)


    → Is well suited to implement Domain Specific Languages, so it
      could work very well in systems programming


    → as Erlang, it is easy to implement parallel and concurrent
      programs safely due to the pureness of the language
Benefits of using Haskell



    → Algorithms are normally shorter and more concise than their
      iterative versions


    → Due to the use of function composability, curryfication and
      high-order functions, code can be reused in really smart ways


    → The kick-ass type system with type inference makes you
      develop code that would normally work at the first compilation
Properties of Haskell

    → Functions won’t perform sequentially, instead they will
      evaluate expressions when needed (lazily)


    → There is a controlled environment for side effect functions but
      by default functions are pure (non-side effect).


    → Management of resources is abstracted completely from the
      developer (GC and automatic allocation of data included)


    → Strong typing makes correctness happen, and most of the the
      issues regarding this type systems won’t get on the way due to
      the compiler’s type inference system
Quicksort in C

   void qsort(int a[], int lo, int hi) {
     int h, l, p, t;
     if (lo < hi) {
       l = lo;
       h = hi;
       p = a[hi];

           do {
             while ((l < h) && (a[l] <= p))
                 l = l+1;
             while ((h > l) && (a[h] >= p))
                 h = h-1;
             if (l < h) {
                 t = a[l];
                 a[l] = a[h];
                 a[h] = t;
             }
           } while (l < h);

           a[hi] = a[l];
           a[l] = p;

           qsort( a, lo, l-1 );
           qsort( a, l+1, hi );
       }
   }
Quicksort in Haskell


   qsort :: (Ord a) => [a] -> [a]
   qsort [] = []
   qsort (x:xs) = (qsort lower) ++ [x] ++ (qsort upper)
     where
       lower = filter (< x) xs
       upper = filter (>= x) xs

   --   qsort [4,5,1,6,3,2]
   --   First execution:
   --   x = 4
   --   xs = [5,1,6,3,2]
   --   lower = [1,3,2]
   --   upper = [5,6]
Simple Functions
One parameter functions




    Haskell has only one parameter functions
    inc :: Int -> Int
    inc x = x + 1

    isNotZero :: Int -> Bool
    isNotZero x = x /= 0
High Order Functions
Functions that returns functions




     add :: Int -> (Int -> Int)
     add x = y -> x + y

     compare :: (Eq a) => a -> (a -> Bool)
     compare a = b -> a == b

     -- Syntactic Sugar complements of Haskell
     add’ :: Int -> Int -> Int
     add’ x y = x + y

     compare’ :: (Eq a) => a -> a -> Bool
     compare’ x y = x == y
High Order Functions
Assign returned functions directly




     If inc is a function of type:

     Int -> Int

     and (+1) is a function of type:

     Int -> Int

     Then why don’t assign it directly? This is called curryfication
     inc’ = (1 +)
     isNotZero’ = (0 /=)
High Order Functions
Functions that receive functions as parameters



     Functions can also receive functions as parameters:
     filter :: (a -> Bool) -> [a] -> [a]
     filter fn (x:xs)
       | fn x = x : filter fn xs
       | otherwise = filter fn xs

     -- filter isNotZero [1,0,2,0,3]
     -- => [1,2,3]
     They can also be curryfied:
     removeZeros :: [Int] -> [Int]
     removeZeros = filter isNotZero
Lists
Definition of a list


      → An empty value: []

      → A cons value: Item on the left and list on the right, the whole
        thing being a new list
        [1,2,3] == (1:2:3:[]) == (1:(2:(3:[])))


     So we have two basic functions to get the two components of a
     cons:
     head :: [a] -> a
     head (x:_) = x

     tail :: [a] -> [a]
     tail (_:xs) = xs
Let’s define some functions
Simple functions with a common interface




    sum :: (Num a) => [a] -> a
    sum [] = 0
    sum (x:xs) = x + sum xs

    prod :: (Num a) => [a] -> a
    prod [] = 1
    prod (x:xs) = x * prod xs

    length :: [a] -> Int
    length [] = 0
    length (x:xs) = 1 + length xs
Folding
Basics



    foldr :: (a -> b -> b) -> b -> [a] -> b
    foldr fn zero [] = zero
    foldr fn zero (x:xs) = fn x (foldr fn zero xs)

    {-
    foldr (+) 0 [3,2,5]

    - [] is replaced by 0
    - (:) function is replaced by the (+) function

    -> 3 : (2 : (5 : []))
    -> 3 + (2 + (5 + 0))
    -}
Folding
Using foldr and partially applied functions




     -- foldr (+) 0 :: (Num a) => [a] -> a
     sum’ = foldr (+) 0

     -- foldr (*) 1 :: (Num a) => [a] -> a
     prod’ = foldr (*) 1

     -- foldr (+) 0 :: (Num a) => [a] -> a
     length’ = foldr (_ accum -> 1 + accum) 0
Folding
Insertion Sort



     insertion :: (Ord a) => a -> [a] -> [a]
     insertion a [] = [a]
     insertion a (b:bs)
       | a <= b = (a:b:bs)
       | otherwise = (b : insertion a bs)

     insertionSort :: (Ord a) => [a] -> [a]
     insertionSort = foldr insertion []

     {-
     insertionSort [3,2,4]
     -> insertion 3 (insertion 2 (insertion 4 ([])))
     -}
Function Composition
Basics



    Let’s abstract the composition of functions
    (.) :: (b -> c) -> (a -> b) -> (a -> c)
    (.) f g = x -> f (g x)



    Using the (.) function, we can compose function together to
    create new ones:
    map :: (a -> b) -> [a] -> [b]
    map fn = foldr ((:) . fn) []
    -- (x:xs) == (:) x xs
    -- (:) . fn = x -> (:) fn x
Lazy Evaluation
Infinite Lists


     Haskell is a lazy language, meaning that the language will evaluate
     expressions only one needed.
     iterate :: (a -> a) -> a -> [a]
     iterate fn a = (a : iterate fn (fn a))

     -- [a, fn a, fn (fn a), fn (fn (fn a))), ...]
     This will do an infinite recursion, it will stop when algorithms do
     not require more values from the infinite lists
     bitValues :: [Int]
     bitValues = iterate (*2) 1

     -- take 8 bitValues -> [1,2,4,8,16,32,64,128]
Algebraic Data Types
Maybe Data Type



    To handle nullable values we use an Algebraic Data Type called
    Maybe
    data Maybe a = Just a
                 | Nothing
                 deriving (Show)
    Where the a in the Maybe could be any type (Int, String, Char)

    Examples of values of type Maybe Int
     → Just 20
     → Nothing
Unfolds




   unfoldr :: (a -> Maybe (b, a)) -> a -> [b]
   unfoldr fn x =
     case fn x of
       Just (a, b) -> a : (unfoldr fn b)
       Nothing -> []
From Int to [Bit]


   type Bit = Int

   nextBit :: Int -> Maybe (Bit, Int)
   nextBit x
     | x > 0 = Just (m, d)
     | otherwise = Nothing
     where
       d = x ‘div‘ 2
       m = x ‘mod‘ 2

   toBinary :: Int -> [Bit]
   toBinary = unfoldr nextBit
Binary to Decimal
Example of high-order functions, composability and infinite lists




     zipWith    :: (a -> b -> c) -> [a] -> [b] -> [c]
     zipWith    _ _ [] = []
     zipWith    _ [] _ = []
     zipWith    fn (x:xs) (y:ys) = (fn x y) : zipWith fn xs ys

     binaryToDecimal :: [Bit] -> Int
     binaryToDecimal = sum . zipWith (*) bitValues
Why Haskell is not being used as much?

    → It’s different, people is always afraid of what is different


    → It’s difficult, mostly related to the first point


    → It’s unpopular, mostly related to the first and second point


    → It’s risky (for employers), there are not many Haskell
      developers to count on, of course this is mostly related to the
      first, second and third point


    → Libraries are broad, but there is no depth (Many incompatible
      experimental libraries that do the same thing)
Thank You!

     Get started at learnyouahaskell.com
Github: http://github.com/roman/haskell meetup
             Twitter: @romanandreg

Why Haskell Matters

  • 1.
    Why Haskell Matters Roman Gonzalez Vancouver Haskell Meetup October 20, 2010
  • 2.
    So what isthis language about? Haskell is a pure, statically typed, lazy functional programming language. → Name inspired by mathematician Haskell Brooks Curry → Based on a more primitive language called Lambda Calculus → There is no iteration or sequences of actions, everything is recursive
  • 3.
    When learning Haskellis a good idea? → If you are a experienced developer that wants to grow professionally by learning completely new and different approaches to solve problems → If you need to build systems where correctness is critical (Banks, Safety-Critical Systems) → Is well suited to implement Domain Specific Languages, so it could work very well in systems programming → as Erlang, it is easy to implement parallel and concurrent programs safely due to the pureness of the language
  • 4.
    Benefits of usingHaskell → Algorithms are normally shorter and more concise than their iterative versions → Due to the use of function composability, curryfication and high-order functions, code can be reused in really smart ways → The kick-ass type system with type inference makes you develop code that would normally work at the first compilation
  • 5.
    Properties of Haskell → Functions won’t perform sequentially, instead they will evaluate expressions when needed (lazily) → There is a controlled environment for side effect functions but by default functions are pure (non-side effect). → Management of resources is abstracted completely from the developer (GC and automatic allocation of data included) → Strong typing makes correctness happen, and most of the the issues regarding this type systems won’t get on the way due to the compiler’s type inference system
  • 6.
    Quicksort in C void qsort(int a[], int lo, int hi) { int h, l, p, t; if (lo < hi) { l = lo; h = hi; p = a[hi]; do { while ((l < h) && (a[l] <= p)) l = l+1; while ((h > l) && (a[h] >= p)) h = h-1; if (l < h) { t = a[l]; a[l] = a[h]; a[h] = t; } } while (l < h); a[hi] = a[l]; a[l] = p; qsort( a, lo, l-1 ); qsort( a, l+1, hi ); } }
  • 7.
    Quicksort in Haskell qsort :: (Ord a) => [a] -> [a] qsort [] = [] qsort (x:xs) = (qsort lower) ++ [x] ++ (qsort upper) where lower = filter (< x) xs upper = filter (>= x) xs -- qsort [4,5,1,6,3,2] -- First execution: -- x = 4 -- xs = [5,1,6,3,2] -- lower = [1,3,2] -- upper = [5,6]
  • 8.
    Simple Functions One parameterfunctions Haskell has only one parameter functions inc :: Int -> Int inc x = x + 1 isNotZero :: Int -> Bool isNotZero x = x /= 0
  • 9.
    High Order Functions Functionsthat returns functions add :: Int -> (Int -> Int) add x = y -> x + y compare :: (Eq a) => a -> (a -> Bool) compare a = b -> a == b -- Syntactic Sugar complements of Haskell add’ :: Int -> Int -> Int add’ x y = x + y compare’ :: (Eq a) => a -> a -> Bool compare’ x y = x == y
  • 10.
    High Order Functions Assignreturned functions directly If inc is a function of type: Int -> Int and (+1) is a function of type: Int -> Int Then why don’t assign it directly? This is called curryfication inc’ = (1 +) isNotZero’ = (0 /=)
  • 11.
    High Order Functions Functionsthat receive functions as parameters Functions can also receive functions as parameters: filter :: (a -> Bool) -> [a] -> [a] filter fn (x:xs) | fn x = x : filter fn xs | otherwise = filter fn xs -- filter isNotZero [1,0,2,0,3] -- => [1,2,3] They can also be curryfied: removeZeros :: [Int] -> [Int] removeZeros = filter isNotZero
  • 12.
    Lists Definition of alist → An empty value: [] → A cons value: Item on the left and list on the right, the whole thing being a new list [1,2,3] == (1:2:3:[]) == (1:(2:(3:[]))) So we have two basic functions to get the two components of a cons: head :: [a] -> a head (x:_) = x tail :: [a] -> [a] tail (_:xs) = xs
  • 13.
    Let’s define somefunctions Simple functions with a common interface sum :: (Num a) => [a] -> a sum [] = 0 sum (x:xs) = x + sum xs prod :: (Num a) => [a] -> a prod [] = 1 prod (x:xs) = x * prod xs length :: [a] -> Int length [] = 0 length (x:xs) = 1 + length xs
  • 14.
    Folding Basics foldr :: (a -> b -> b) -> b -> [a] -> b foldr fn zero [] = zero foldr fn zero (x:xs) = fn x (foldr fn zero xs) {- foldr (+) 0 [3,2,5] - [] is replaced by 0 - (:) function is replaced by the (+) function -> 3 : (2 : (5 : [])) -> 3 + (2 + (5 + 0)) -}
  • 15.
    Folding Using foldr andpartially applied functions -- foldr (+) 0 :: (Num a) => [a] -> a sum’ = foldr (+) 0 -- foldr (*) 1 :: (Num a) => [a] -> a prod’ = foldr (*) 1 -- foldr (+) 0 :: (Num a) => [a] -> a length’ = foldr (_ accum -> 1 + accum) 0
  • 16.
    Folding Insertion Sort insertion :: (Ord a) => a -> [a] -> [a] insertion a [] = [a] insertion a (b:bs) | a <= b = (a:b:bs) | otherwise = (b : insertion a bs) insertionSort :: (Ord a) => [a] -> [a] insertionSort = foldr insertion [] {- insertionSort [3,2,4] -> insertion 3 (insertion 2 (insertion 4 ([]))) -}
  • 17.
    Function Composition Basics Let’s abstract the composition of functions (.) :: (b -> c) -> (a -> b) -> (a -> c) (.) f g = x -> f (g x) Using the (.) function, we can compose function together to create new ones: map :: (a -> b) -> [a] -> [b] map fn = foldr ((:) . fn) [] -- (x:xs) == (:) x xs -- (:) . fn = x -> (:) fn x
  • 18.
    Lazy Evaluation Infinite Lists Haskell is a lazy language, meaning that the language will evaluate expressions only one needed. iterate :: (a -> a) -> a -> [a] iterate fn a = (a : iterate fn (fn a)) -- [a, fn a, fn (fn a), fn (fn (fn a))), ...] This will do an infinite recursion, it will stop when algorithms do not require more values from the infinite lists bitValues :: [Int] bitValues = iterate (*2) 1 -- take 8 bitValues -> [1,2,4,8,16,32,64,128]
  • 19.
    Algebraic Data Types MaybeData Type To handle nullable values we use an Algebraic Data Type called Maybe data Maybe a = Just a | Nothing deriving (Show) Where the a in the Maybe could be any type (Int, String, Char) Examples of values of type Maybe Int → Just 20 → Nothing
  • 20.
    Unfolds unfoldr :: (a -> Maybe (b, a)) -> a -> [b] unfoldr fn x = case fn x of Just (a, b) -> a : (unfoldr fn b) Nothing -> []
  • 21.
    From Int to[Bit] type Bit = Int nextBit :: Int -> Maybe (Bit, Int) nextBit x | x > 0 = Just (m, d) | otherwise = Nothing where d = x ‘div‘ 2 m = x ‘mod‘ 2 toBinary :: Int -> [Bit] toBinary = unfoldr nextBit
  • 22.
    Binary to Decimal Exampleof high-order functions, composability and infinite lists zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] zipWith _ _ [] = [] zipWith _ [] _ = [] zipWith fn (x:xs) (y:ys) = (fn x y) : zipWith fn xs ys binaryToDecimal :: [Bit] -> Int binaryToDecimal = sum . zipWith (*) bitValues
  • 23.
    Why Haskell isnot being used as much? → It’s different, people is always afraid of what is different → It’s difficult, mostly related to the first point → It’s unpopular, mostly related to the first and second point → It’s risky (for employers), there are not many Haskell developers to count on, of course this is mostly related to the first, second and third point → Libraries are broad, but there is no depth (Many incompatible experimental libraries that do the same thing)
  • 24.
    Thank You! Get started at learnyouahaskell.com Github: http://github.com/roman/haskell meetup Twitter: @romanandreg