Why Haskell Matters Roman Gonzalez Vancouver Haskell Meetup October 20, 2010
May 11, 2015
Why Haskell Matters
Roman Gonzalez
Vancouver Haskell Meetup
October 20, 2010
So what is this language about?
Haskell is a pure, statically typed, lazy functionalprogramming 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 isrecursive
When learning Haskell is a good idea?
→ If you are a experienced developer that wants to growprofessionally by learning completely new and differentapproaches 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 itcould work very well in systems programming
→ as Erlang, it is easy to implement parallel and concurrentprograms safely due to the pureness of the language
Benefits of using Haskell
→ Algorithms are normally shorter and more concise than theiriterative versions
→ Due to the use of function composability, curryfication andhigh-order functions, code can be reused in really smart ways
→ The kick-ass type system with type inference makes youdevelop code that would normally work at the first compilation
Properties of Haskell
→ Functions won’t perform sequentially, instead they willevaluate expressions when needed (lazily)
→ There is a controlled environment for side effect functions butby default functions are pure (non-side effect).
→ Management of resources is abstracted completely from thedeveloper (GC and automatic allocation of data included)
→ Strong typing makes correctness happen, and most of the theissues regarding this type systems won’t get on the way due tothe 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 FunctionsOne parameter functions
Haskell has only one parameter functions
inc :: Int -> Int
inc x = x + 1
isNotZero :: Int -> Bool
isNotZero x = x /= 0
High Order FunctionsFunctions 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 FunctionsAssign 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 FunctionsFunctions 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
ListsDefinition of a list
→ An empty value: []
→ A cons value: Item on the left and list on the right, the wholething 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 acons:
head :: [a] -> a
head (x:_) = x
tail :: [a] -> [a]
tail (_:xs) = xs
Let’s define some functionsSimple 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
FoldingBasics
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))
-}
FoldingUsing 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
FoldingInsertion 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 CompositionBasics
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 tocreate new ones:
map :: (a -> b) -> [a] -> [b]
map fn = foldr ((:) . fn) []
-- (x:xs) == (:) x xs
-- (:) . fn = \x -> (:) fn x
Lazy EvaluationInfinite Lists
Haskell is a lazy language, meaning that the language will evaluateexpressions 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 donot 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 TypesMaybe Data Type
To handle nullable values we use an Algebraic Data Type calledMaybe
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 DecimalExample 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 Haskelldevelopers to count on, of course this is mostly related to thefirst, second and third point
→ Libraries are broad, but there is no depth (Many incompatibleexperimental libraries that do the same thing)
Thank You!
Get started at learnyouahaskell.comGithub: http://github.com/roman/haskell meetup
Twitter: @romanandreg