Const
const x y = xEager
const 42 expensiveLazy
const 42 (error "fail")← won’t see the error!- Now you can’t know whether or not an error happens → whether or not a particular computation happens!
- Reasoning about order of evaluation is difficult.
Data
data Nat = -- Peano
z -- Natural
| S Nat -- Numbers
0 = z 1 = S z 2 = S (S z) 3 = S (S (S z))
“the lazy natural numbers”
num = S (error "NaN")
case num of
z -> 42
S _ -> 21
-- exception not thrown! returns 21!A More Interesting Example
inf = S inf -- definiting infinity as a natural number w/o an infinite loop
plus x y =
case x of
z -> y
S i -> S (plus i y)We can return a natural number without computing anything - we never actually look at y
plus (S (S z)) inf -- does not result in an infinite loop! Because we never look at inf.
plus inf inf -- also doesn't result in an infinite loop.Drawbacks of Lazy
- There is a constant factor applied to every lazy program that is not present in the eager program.
- Does not having to compute expensive operations make up for that constant factor? -it’s complicated.
- In practice, languages like Haskell end up being very fast, but not because of the laziness, it’s because of the purity
- Allows for optimizations without side effects
- Harder to debug - it’s not just about the control flow
Lists
inf = 1 : map (+ 1) inf -- infinite, recursive data structure!
take 5 inf => [1, 2, 3, 4, 5]
xs = [1, 2, error "3", 4, 5]
length xs ≡ ?
-- do we evaluate error "3" or not?
length xs =
case xs of
[] -> ∅
y:ys -> 1 + length ys
-- so we don't evaluate error "3"!
-- therefore,
length xs ≡ 3
(f xs) -- "demand" on the data structure --
mapm print xs -- "1, 2, error '3' (exit) -> we used xs in both length and mapm, but one of them errored, the other didn't - the DEMAND was different - it's only meaningful in the CONTEXT it's used inSide Effects
Haskell doesn’t allow arbitrary side effects. (Not side effects as a whole!)
print::Int -> ()
const (print 42) 42 -- const uses its first argument
-- but doesn't actually print 42!
-- doesn't allow arbitrary side effects. Pure expression - can't do it!
f x = (print x, x)In OCaml, f 42 ≡ ((), 42) ⟹ in the console, "42" is printed
Haskell doesn’t allow this.
print_int::Int -> IO() -- things that have an effect are tagged with that effect in the type!
f::() -> Int
f (print_int 42) -- ERROR!!!! Compilation error. () ≢ IO()
main::IO() -- main is allowed to do side effects!
-- but pure functions do not allow them. SEPARATION of things that do SEs and things that don't. AWESOME!