10 = ? f 10 = sum . take 5 . repeat $ 10 repeat x = x : repeat x take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs
take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (take 5 (repeat 10)) 5 > 0 so we take branch n > 0 of take
take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (take 5 (repeat 10)) 5 > 0 so we take branch n > 0 of take Pattern match on (x:xs) so, expand repeat first
take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (take 5 (repeat 10)) 5 > 0 so we take branch n > 0 of take Pattern match on (x:xs) so, expand repeat first
take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (take 5 (repeat 10)) 5 > 0 so we take branch n > 0 of take Pattern match on (x:xs) so, expand repeat first f 10 = sum (take 5 (10 : repeat 10))
take n (x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (take 5 (repeat 10)) 5 > 0 so we take branch n > 0 of take Pattern match on (x:xs) so, expand repeat first f 10 = sum (take 5 (10 : repeat 10)) f 10 = sum (10 : take 4 (repeat 10))
(x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (10 : take 4 (repeat 10)) Multiple possibilities to evaluate the expression
(x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (10 : take 4 (repeat 10)) Multiple possibilities to evaluate the expression lazy vs eager evaluation
(x:xs) | n > 0 = x : take (n - 1) xs | otherwise = [] sum [] = 0 sum (x:xs) = x + sum xs f 10 = sum (10 : take 4 (repeat 10)) f 10 = sum (10 : take 4 (repeat 10)) f 10 = sum (10 : 10 : take 3 (repeat 10)) f 10 = sum (10 : 10 : 10 : take 2 (repeat 10)) f 10 = sum (10 : 10 : 10 : 10 : take 1 (repeat 10)) f 10 = sum (10 : 10 : 10 : 10 : 10 : take 0 (repeat 10)) f 10 = sum [10, 10, 10, 10, 10] f 10 = 50
to do for big programs lazy evaluation vs. stack-based debugging GHCi debugger hard to use for large programs Hood: Haskell Object Observation Debugger
to do for big programs lazy evaluation vs. stack-based debugging GHCi debugger hard to use for large programs Hood: Haskell Object Observation Debugger print intermediate data structure
to do for big programs lazy evaluation vs. stack-based debugging GHCi debugger hard to use for large programs Hood: Haskell Object Observation Debugger print intermediate data structure use equational reasoning to reason about state around bug
:: a -> f a (<*>) :: f (a -> b) -> f a -> f b pure f <*> x = fmap f x pure id <*> v = v pure (.) <*> u <*> v <*> w = u <*> (v <*> w) pure f <*> pure x = pure (f x) u <*> pure y = pure ($ y) <*> u
them test with QuickCheck or similar http://austinrochford.com/posts/ 2014-05-27-quickcheck-laws.html parametricity makes some rules be always valid (Functor)
them test with QuickCheck or similar http://austinrochford.com/posts/ 2014-05-27-quickcheck-laws.html parametricity makes some rules be always valid (Functor) these rules hold over all instances of typeclass
them test with QuickCheck or similar http://austinrochford.com/posts/ 2014-05-27-quickcheck-laws.html parametricity makes some rules be always valid (Functor) these rules hold over all instances of typeclass same reasoning holds when moving from Maybe a to [a]
them test with QuickCheck or similar http://austinrochford.com/posts/ 2014-05-27-quickcheck-laws.html parametricity makes some rules be always valid (Functor) these rules hold over all instances of typeclass same reasoning holds when moving from Maybe a to [a] allow higher-level reasoning
them test with QuickCheck or similar http://austinrochford.com/posts/ 2014-05-27-quickcheck-laws.html parametricity makes some rules be always valid (Functor) these rules hold over all instances of typeclass same reasoning holds when moving from Maybe a to [a] allow higher-level reasoning easily change the semantics of the program with minimal impact on performance/accuracy/etc.
map f (map g xs) = map (f.g) xs #-} map f . map g = map (f . g) List fusion function generating list function consuming list to generate result list = temporary data structure why not eliminate it?
only for one type? or effective only for some types specialize rules toDouble :: Real a => a -> Double toDouble = fromRational . toRational {-# RULES "toDouble/Int" toDouble = i2d #-} i2d (I# i) = D# (int2Double# i)
= a + sum as sum (map (+1) x) = length x + sum x Base case: [] sum (map (+1) []) = sum [] = 0 length [] + sum [] = 0 + 0 = 0 Inductive case:(for all constructors) sum (map (+1) (x:xs)) = sum ((x+1) : map (+1) xs) = (x+1) + sum (map (+1) xs) = (x+1) + length xs + sum xs = (1 + length xs) + (x + sum xs) = length (x:xs) + sum (x:xs)
much used. The coinductive definition and proof principles for coalgebras are less well known by far, and often even not very clearly formulated. Rutten, 2000, seminal paper
much used. The coinductive definition and proof principles for coalgebras are less well known by far, and often even not very clearly formulated. Rutten, 2000, seminal paper bisimilarity, bisimulation A property holds by induction if there is good reason for it to hold; whereas a property holds by coinduction if there is no good reason for it not to hold. Induction is about finite data, coinduction is about infinite codata.
languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version
languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version compile time: 10s
languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version compile time: 10s running time: 550ms
languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version compile time: 10s running time: 550ms
languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version compile time: 10s running time: 550ms lack of tooling → every calculation must be done by hand
languages: beware ⊥ non-functional languages: possible? C++ code for cypto code on CUDA C++ templates compilation: 24 hours running time: 500ms equational reasoning to translate to non-template version compile time: 10s running time: 550ms lack of tooling → every calculation must be done by hand IDE & automatic refactorings rarely help
different versions of same code different coding styles and levels of Haskell knowledge timings between versions derivation of efficient solution and a not-so-trivial bug
the past, when you wrote it; clever Haskell code is what you hope you’ll understand in the future, when you’ll write it yourself! Sjur Gjøstein Karevoll, paraphrased