Date post: | 11-May-2015 |
Category: |
Technology |
Upload: | romanandreg |
View: | 2,263 times |
Download: | 0 times |
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