Understanding Lazy Assessment in Haskell

I am trying to learn Haskell , but I am stuck in understanding lazy evaluation . Can someone explain to me the lazy assessment in detail and deduce the following two cases [with explanation] regarding the below

Pseudocode:

 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 the last line will print ( echo y ) ... in the above cases.

+7
source share
3 answers

Sorry, this is too long, but ...

I am afraid that the answer will greatly depend on the meaning of the words ...

First, here is this 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 

He prints 8 and 8 .

Now here is this code in R that uses lazy evaluation and what some people call dynamic linking:

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

He prints 8 and 8 . Not certainly in that way!

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"; } 

He prints 8 and 8 .

Now let me tell you that I think the point of the question really was :)

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

 f (g (hx)) 
Rating

works as if f is evaluated to g (hx) , i.e. the rating goes "outside → to". In practice, this means that if f looks like

 fx = 2 

those. just discards its argument, g (hx) never evaluated.

But I think that this is not the question that comes with a "lazy assessment." The reason I think this is:

  • + always evaluates his arguments! + is the same, whether you use lazy ratings or not.

  • The only calculation that can be delayed is keyboard input - and this is not really a calculation, because it invokes an action; that is, it is read from the user.

Haskell’s people usually don’t call this “lazy rating” - they will call this lazy (or delayed) performance.

So what would lazy execution mean for your question? This would mean that the keyboard input action is delayed ... until the x value is really needed. It seems to me that this is happening here:

 echo y 

because at this moment you should show the user the value, and therefore you should know that x is! So what will 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 linking". It can mean different things:

  • The variable scope and lifetime are determined at runtime. This is what languages ​​like R, for example, do not declare variables.

  • The formula for the calculation (for example, the formula for y is x + 3 ) is not checked until the variable is evaluated.

I assume that is what “dynamic linking” means in your question. Gathers over the code again with dynamic linking (meaning 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 don't know the language that actually prints 7 for the last line ... but I really think that what this question was hoping for!

+11
source

Hazell's Lazy Evaluation: Leftmost + Graph Reduction

Square x = x * x

Square (area 42)

(Square 42) * (Square 42) → Square 42 will only be calculated once by reducing the graph

(42 * 42) * (Area 42)

(1764) * (Square 42) → next - Zoom Out

1764 * 1764
= 3111696

The left-most-innermost (Java, C ++)

Square (area 42)

square (42 * 42)

square (1764)

1764 * 1764 = 3111696

+2
source

The key thing about lazy evaluation in Haskell is that it does not affect the output of your program at all. You can read it as if everything was evaluated as soon as it is determined, and you will still get the same result.

Lazy evaluation is simply a strategy for determining the meaning of an expression in a program. There are many of them, and all of them give the same result [1]; any evaluation strategy that changes the meaning of the program will not be a valid strategy!

So, from a certain point of view, you do not need to sort out a lazy assessment (for now) if this gives you problems. When you learn Haskell, especially if this is your first functional and clean language, thinking about how to express yourself in this way is much more important. I would also appreciate learning on my own to make it comfortable to read the Haskell (often quite dense) syntax as more important than a completely grokking lazy grade. Therefore, do not worry too much if the concept gives you difficulties.

However, I will explain it below. I did not use your examples, because they were not affected by a lazy assessment, and Owen spoke more clearly than I could about dynamic binding and delayed execution according to your example.


The most important difference between (valid) evaluation strategies is that some strategies may not return at all, where another strategy may be successful. Lazy evaluation has a special property, which if any (real) evaluation strategy can find a result, a lazy rating will find it. In particular, programs that generate endless data structures and then use only a finite amount of data can end with a lazy assessment. In a rigorous evaluation, which you are probably accustomed to, the program must complete the creation of an infinite data structure before it can continue to use part of it, and, of course, it will.

Lazy assessment achieves this by only evaluating something when you need to figure out what to do next. When you call a function that returns a list, it "returns immediately" and gives you a placeholder for the list. This placeholder can be passed to other functions stored in other data structures, whatever. Only when the program needs to know something about the list will it be actually evaluated and only as necessary.

Say that now the program will do something different if the list is empty than if it weren’t. The function call that the placeholder originally returned is evaluated a little further to see if it returns an empty list or a list with a title element. Then the evaluation stops again, as the program now knows where to go. If the rest of the list is never needed, it will never be rated.

But he was also not evaluated more than once. If a placeholder has been passed into several functions (so that it is now involved in other not yet evaluated functions calls) or stored in several different data structures, Haskell still “knows” that they are all the same, and will arrange everything for them to “see” the consequences of any further placeholder evaluation caused by any of them. In the end, if the whole list is needed somewhere, they will all point to the usual fully evaluated data structure, and laziness does not have a further effect.

But it’s important to remember that everything needed to create this list is already defined and fixed when creating the placeholder. He cannot work on anything else that has happened in the program since then. If this were not so, then Haskell would not be clean . And vice versa; in unclean languages ​​there cannot be total laziness in the Haskell style, because the results you get can change a lot depending on when you need the results in the future . Instead, unclean languages ​​that support lazy evaluation tend to have it only for certain things explicitly stated by the programmer, with warnings in the manual that say, "Don't use laziness on something that depends on side effects."


[1] I am lying a little here. Continue reading below line to understand why.

+2
source

All Articles