Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Lazy Evaluation in Haskell

I am trying to learn Haskell, but i am stuck in understanding lazy evaluation. Can someone explain me lazy evaluation in detail and the output of the following 2 cases[with explaination] in relation to the below given

Pseudo Code:

x = keyboard input (5)
y = x + 3 (=8)
echo y (8)
x = keyboard input (2)
echo y

Case 1: Static binding, lazy evaluation

Case 2: Dynamic binding, lazy evaluation.

I need to know what will the last line (echo y) is going to print...in the above 2 cases.

like image 412
RanRag Avatar asked Oct 14 '11 23:10

RanRag


People also ask

Why Haskell is lazy evaluation?

Haskell is a lazy language. It does not evaluate expressions until it absolutely must. This frequently allows our programs to save time by avoiding unnecessary computation, but they are at more of a risk to leak memory. There are ways of introducing strictness into our programs when we don't want lazy evaluation.

Does Haskell use lazy evaluation?

Haskell uses lazy evaluation for all functions. On the plus side, lazy evaluation never does more reduction steps than eager evaluation, and sometimes many fewer. On the minus side, lazy evaluation can use a lot more memory in some cases, and it can be difficult to predict its performance ahead of time.

How does lazy evaluation work?

In programming language theory, lazy evaluation, or call-by-need, is an evaluation strategy which delays the evaluation of an expression until its value is needed (non-strict evaluation) and which also avoids repeated evaluations (sharing).

How are Haskell expressions evaluated?

An expression is evaluated by normal order (leftmost outermost redex first). To avoid unnecessary computation, normal order reduction chooses to apply the function rather than first evaluating the argument.


1 Answers

Sorry this is way too long but...

I'm afraid the answer is going to depend a lot on the meaning of the words...

First, here's that code in Haskell (which uses static binding and lazy evaluation):

readInt :: String -> Int
readInt = read

main = do
    x <- fmap readInt getLine
    let y = x + 3
    print y
    x <- fmap readInt getLine
    print y

It prints 8 and 8.

Now here's that code in R which uses lazy evaluation and what some people call dynamic binding:

delayedAssign('x', as.numeric(readLines(n=1)))
delayedAssign('y', x + 3)
print(y)

delayedAssign('x', as.numeric(readLines(n=1)))
print(y)

It prints 8 and 8. Not so different!

Now in C++, which uses strict evaluation and static binding:

#include <iostream>

int main() {
    int x;
    std::cin >> x;
    int y = x + 3;
    std::cout << y << "\n";
    std::cin >> x;
    std::cout << y << "\n";
}

It prints 8 and 8.

Now let me tell you what I think the point of the question actually was ;)

"lazy evaluation" can mean many different things. In Haskell it has a very particular meaning, which is that in nested expressions:

f (g (h x))

evaluation works as if f gets evaluated before g (h x), ie evaluation goes "outside -> in". Practically this means that if f looks like

f x = 2

ie just throws away its argument, g (h x) never gets evaluated.

But I think that that is not where the question was going with "lazy evaluation". The reason I think this is that:

  • + always evaluates its arguments! + is the same whether you're using lazy evaluation or not.

  • The only computation that could actually be delayed is keyboard input -- and that's not really computation, because it causes an action to occur; that is, it reads from the user.

Haskell people would generally not call this "lazy evaluation" -- they would call it lazy (or deferred) execution.

So what would lazy execution mean for your question? It would mean that the action keyboard input gets delayed... until the value x is really really needed. It looks to me like that happens here:

echo y

because at that point you must show the user a value, and so you must know what x is! So what would happen with lazy execution and static binding?

x = keyboard input     # nothing happens
y = x + 3              # still nothing happens!
echo y (8)             # y becomes 8. 8 gets printed.
x = keyboard input (2) # nothing happens
echo y                 # y is still 8. 8 gets printed.

Now about this word "dynamic binding". It can mean different things:

  1. Variable scope and lifetime is decided at run time. This is what languages like R do that don't declare variables.

  2. The formula for a computation (like the formula for y is x + 3) isn't inspected until the variable is evaluated.

My guess is that that is what "dynamic binding" means in your question. Going over the code again with dynamic binding (sense 2) and lazy execution:

x = keyboard input     # nothing happens
y = x + 3              # still nothing happens!
echo y (8)             # y becomes 8. 8 gets printed.
x = keyboard input (2) # nothing happens
echo y                 # y is already evaluated, 
                       # so it uses the stored value and prints 8

I know of no language that would actually print 7 for the last line... but I really think that's what the question was hoping would happen!

like image 67
Owen Avatar answered Oct 01 '22 14:10

Owen