Comparing

strict and lazy

Arnaud Spiwack

The sad truth

Most of the time: it doesn't even remotely matters

The happy truth

Can you spot the bug?

atomicPut :: Handle -> String -> IO ()
atomicPut h line =
  withMVar lock $ \_ -> do
    hPutStrLn h line

All you've got to do is call

or :: [Bool] -> Bool
or =  foldr (||) False

any :: (a -> Bool) -> [a] -> Bool
any p =  or . map p

Applicative functors 🤩

zipWith1 :: (a -> b) -> [a] -> [b]
zipWith2 :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
zipWith4 :: (a -> b -> c -> d -> e) -> [a] -> [b] -> [c] -> [d] -> [e]
zipWith5 :: (a -> b -> c -> d -> e -> f) -> [a] -> [b] -> [c] -> [d] -> [e] -> [f]





zipWith5 :: (a -> b -> c -> d -> e -> f) -> [a] -> [b] -> [c] -> [d] -> [e] -> [f]
zipWith5 f as bs cs ds es = f <$> as <*> bs <*> cs <*> ds <*> es
(<$>) :: (a -> b) -> [a] -> [b]
(<*>) :: [a -> b] -> [a] -> [b]

Matching lazy data is weird

“The answer to all questions in Haskell is ‘bottom’.”
— Simon Peyton Jones

f :: Bool -> Bool -> Int
f _    False = 1
f True False = 2
f _    _     = 3
f :: T a -> U a -> Int
f (TBool b1) (UBool b2) = 0
data U a where
  UChar :: Char -> U Char
  UBool :: Bool -> U Bool 
data T a where
  TInt :: Int -> T Int
  TBool :: Bool -> T Bool

Guarded recursion

map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (a:as) = f a : map f as

Memory leaks

Tail recursion

length :: [a] -> Integer
length [] = 0
length (_:as) = 1 + length as
length :: [a] -> Integer
length = go 0
  where
    go :: Integer -> [a] -> Integer
    go acc [] = acc
    go acc (_:as) = go (acc+1) as
length :: [a] -> Integer
length = go 0
  where
    go :: Integer -> [a] -> Integer
    go !acc [] = acc
    go !acc (_:as) = go (acc+1) as

Memory heisenbug

Observing a lazy value changes its state

This slide is intentionally left blank

Lazy IO

readFile :: FilePath -> IO String

Limitations:

Lazy IO

readFile :: FilePath -> IO String
lines :: String -> [String]
read :: Read a => String -> a
f :: Read a => FilePath -> IO [a]
f p = (map read . lines) <$> readFile p

Limitations:

Lazy deserialisation

…  { … , foo : { … }, … }  …
(…, Object (<thunk>, Field "foo" (Object …), <thunk>), …)

Observability

traceEvent "START PureCode" $
somePureCode

¿¿Where do I put

traceEvent "STOP PureCode"

??

Taking laziness seriously

Laziness has a real implementation cost

— Simon Peyton Jones (2003)

Keeps you honest

“Every call-by-value language has given into the siren call of side effects.”

— Simon Peyton Jones (2003)

https://slides.com/aspiwack/hx2020

Thank you for listening

Made with Slides.com