Const

const x y = x

Eager

  • const 42 expensive Lazy
  • 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 in

Side 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!