I'm confused by Haskell's lazy evaluation - haskell

I'm concerned about efficiency in Haskell's lazy evaluation.
consider following code
main = print $ x + x
where x = head [1..]
here, x first hold the expression of head [1..] instead of the result 1, due to the laziness,
but then when I call x + x, will the expression head [1..] be executed twice?
I found the following description on haskell.org
Lazy evaluation, on the other hand, means only evaluating an expression when its results are needed (note the shift from "reduction" to "evaluation"). So when the evaluation engine sees an expression it builds a thunk data structure containing whatever values are needed to evaluate the expression, plus a pointer to the expression itself. When the result is actually needed the evaluation engine calls the expression and then replaces the thunk with the result for future reference.
So does this mean that, in x + x, when calling the first x, head [1..] is executed and x is re-assigned to 1, and the second x is just calling a reference of it?
Did I understand this right?

This is more of a question about particular Haskell implementations than about Haskell itself, since the language makes no particular guarantees about how things are evaluated.
But in GHC (and most other implementations, as far as I'm aware): yes, when thunks are evaluated they are replaced by the result internally, so other references to the same thunk benefit from the work done evaluating it the first time.
The caveat is that there are no real guarantees about which expressions end up implemented as references to the same thunk. The compiler is in general allowed to make whatever transformations to your code it likes so long as the result is the same. Of course, the reason to implement code transformations in a compiler is usually to try to make the code faster, so it's hopefully not likely to rewrite things in such a way as to make it worse, but it can never be perfect.
In practice though, you're usually pretty safe assuming that whenever you give an expression a name (as in where x = head [1..]), then all uses of that name (within the scope of the binding) will be references to a single thunk.

At first, x is just a thunk. You can see that as follows:
λ Prelude> let x = head [1..]
λ Prelude> :sprint x
x = _
Here the _ indicates that x has not yet been evaluated. Its mere definition is recorded.
Then, you can understand how x + x is constructed by just realizing that x is a pointer to this thunk: both those x will point to the same thunk. Once one is evaluated, the other is, since it's the same thunk.
You can see that with ghc-vis:
λ Prelude> :vis
λ Prelude> :view x
λ Prelude> :view x + x
should show you something along the lines of:
Here you can see that the x + x thunk actually points twice to the x thunk.
Now, if you evaluate x, by printing it for example:
λ Prelude> print x
You'll obtain:
You can see here that the x thunk is no longer a thunk: it's the value 1.

There are two ways to evaluate an expression:
Lazy (evaluate outermost first).
Strict (evaluate innermost first).
Consider the following function:
select x y z = if x > z then x else y
Now let's call it:
select (2 + 3) (3 + 4) (1 + 2)
How will this be evaluated?
Strict evaluation: Evaluate innermost first.
select (2 + 3) (3 + 4) (1 + 2)
select 5 (3 + 4) (1 + 2)
select 5 7 (1 + 2)
select 5 7 3
if 5 > 3 then 5 else 7
if True then 5 else 7
5
Strict evaluation took 6 reductions. To evaluate select we first had to evaluate its arguments. In strict evaluation the arguments to a function are always fully evaluated. Hence functions are "call by value". Thus there's no extra bookkeeping.
Lazy evaluation: Evaluate outermost first.
select (2 + 3) (3 + 4) (1 + 2)
if (2 + 3) > (1 + 2) then (2 + 3) else (3 + 4)
if 5 > (1 + 2) then 5 else (3 + 4)
if 5 > 3 then 5 else (3 + 4)
if True then 5 else (3 + 4)
5
Lazy evaluation only took 5 reductions. We never used (3 + 4) and hence we never evaluated it. In lazy evaluation we can evaluate a function without evaluating its arguments. The arguments are only evaluated when needed. Hence functions are "call by need".
However "call by need" evaluation strategies need extra bookkeeping - you need to keep a track of whether an expression has been evaluated. In the above expression when we evaluate x = (2 + 3) we don't need to evaluate it again. However we do need to keep a track of whether it was evaluated.
Haskell supports both strict and lazy evaluation. However it supports lazy evaluation by default. To enable strict evaluation you would have to use the special seq and deepSeq functions.
Similarly you can have lazy evaluation in strict languages like JavaScript. However you would need to keep a track of whether an expression has been evaluated or not. You could research about implementing thunks in JavaScript or similar languages.

Related

Infix function evaluation with $

$ is an infix operator with the lowest possible precedence:
f $ a = f a
Does this not mean that, in the expression below, the part
$ 2 ^ 2
should be evaluated first and then add $ 2? It appears 2 + 2 is evaluated first
Prelude> (2^) $ 2 + 2
returns :
16
No. Try to think of precedence not as being about what gets "evaluated first", and more about where parentheses are inserted.
The fact that $ has the lowest precedence means that parentheses are inserted around everything to the right of it (and, separately, to the left of it, if needed, but they aren't needed here). So
(2^) $ 2 + 2
is equivalent to
(2^) $ (2 + 2)
which is of course
(2^) 4 (i.e. 16)
Precedence rules can be confusing, but I like to think of it as "lower precedence" means "do later". Since $ has the lowest precedence (for example, below (+)), it is performed after (+). Thus (2^) $ 2 + 2 evaluates (2^) to a partially applied function, then evaluates 2+2 to 4, then applies 4 to 2^ to get 16.

What is meant by “replace equals by equals”

I'm Haskell newbie and reading :
http://www.seas.upenn.edu/~cis194/spring13/lectures/01-intro.html
It states "In Haskell one can always “replace equals by equals”, just like you learned in algebra class.". What is meant by this and what are its advantages ?
I don't recall learning this in algebra but perhaps I do not recognise the terminology.
It means that if you know that A (an expression) is equal to B (another expression), then you may always replace A for B in any expression involving A, and vice-versa.
For instance, we know that even = not . odd. Therefore
filter even
=
filter (not . odd)
On the other hand, we know that odd satisfies the following equation
odd = (1 ==) . (`mod` 2)
As such, we also know that
filter even
=
filter (not . odd)
=
filter (not . (1 ==) . (`mod` 2))
Moreover, you know that mod 2 always returns 0 or 1. So, by case analysis, the following is valid.
not . (1 ==)
=
(0 ==)
Therefore, we can also say
filter even
=
filter ((0 ==) . (`mod` 2))
The advantage of being able to replace equals by equals is to design a program by massaging equation after equation until a suitable definition is found, like in typical solve for x kind of problems of Algebra.
In its simplest form, substituting "equals by equals" means replacing a defined identifier with its definition. For instance
let x = f 1 in x + x
can be equivalently written as
f 1 + f 1
in the sense that the result will be the same. In GHC, you can expect the second one to re-compute f 1 twice, possibly degrading performance, but the result of the sum is the same.
In impure languages, such as Ocaml, the two snippets above are instead not equivalent. This is because side effects are allowed: evaluating f 1 can have observable effects. For instance, f could be defined as follows:
(* Ocaml code *)
let f = let r = ref 0 in
fun x -> r := !r + x ; !r
Using the above definition, f has an internal mutable state, which gets incremented by its argument every time it is called, before the new state is returned. Because of this,
f 1 + f 1
would evaluate to 1 + 2 since the state is incremented twice, while
let x = f 1 in x + x
would evaluate to 1 + 1, since only one increment of the state is performed.
The consequence is that, in Ocaml, replacing x with its definition would not be a semantics-preserving program transformation. Of course, the same would hold in imperative languages, which allow side effects. Only in pure languages (Haskell, Agda, Coq, ...) the transformation is safe.

Haskell length + map explanation?

I'm playing around with Haskell since I'm learning the language, and I just found something I don't understand and I can't find an explanation. If I try to run this code:
map (`div` 0) [1,2,3,4]
I get a divide by 0 exception, which is expected.
But if I run this code:
length (map (`div` 0) [1,2,3,4])
I get 4!
I'd like to know why I don't get the divide by 0 exception when I do the mapping inside the length function!
The map and length functions can be defined this way:
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
length :: [a] -> Int
length [] = 0
length (_:xs) = 1 + length xs
Now, let's work out by hand why your second example works the way it does. It goes like this:
length (map (`div` 0) (1:2:3:4:[]))
= length (1 `div` 0 : map (`div` 0) (2:3:4:[])) -- second map equation
= 1 + (length (map (`div` 0) (2:3:4:[]))) -- second length equation
= 1 + (length (2 `div` 0 : map (`div` 0) (3:4:[]))) -- second map equation
.
.
.
= 1 + (1 + (1 + (1 + length (map (`div` 0) []))))) -- second length equation
= 1 + (1 + (1 + (1 + length [])))) -- first map equation
= 1 + (1 + (1 + (1 + 0)))) -- first length equation
= 4 -- arithmetic
What's the trick here? In Haskell the process of evaluating an expression is called forcing it. Forcing an expression performs the minimum work necessary in order to figure out the outermost data constructor of the result. As part of this, subexpressions will be forced only as necessary to achieve the goal.
So in this example, the outermost expression we're forcing is an application of the length function. The definition of length has two cases, one which uses the [] list constructor and the other which uses the (:) constructor, so to apply length we need to figure out which of these two cases to apply to the argument. Since the argument doesn't have either constructor in its outermost position, we have to force it to find out. That's what happens in the step between the first and the second line of the derivation above; we force the map subexpression by looking at its arguments and choosing the second map equation.
But after that point, we have all the information we need to determine which of the two equations for length applies, so we go by the "outermost first" rule and apply the appropriate length equation. In this case, this discards the subexpression that contains the division by zero, which means that subexpression will never be forced, and the error will never be triggered.
In your first example, however, when you type the expression into GHCI, you're implicitly asking the interpreter to print its result. This requires it to force the spine of the list to access its elements, and force the elements themselves to print them. So the division by zero error happens when you force the first element of the list.
EDIT: Let me point out one nuance you may have not noticed. When we try your first example in GHCI, this is the result of the session:
*Main> map (`div` 0) [1,2,3,4]
[*** Exception: divide by zero
See that lonely opening square bracket at the beginning of the second line? That's the opening bracket for the list that was being printed, before the divide by zero error happened. Likewise, notice what happens in this example:
*Main> map (20 `div`) [1,2,0,4]
[20,10,*** Exception: divide by zero
The first two elements of the result list, and even the comma separating the second element from the third, print successfully because Haskell doesn't attempt to compute the third list element until it needs to be printed.
If you type the map expression into the interpreter, it will evaluate it and then print the resulting list. In order to do that all elements of the resulting list need to be evaluated because they will be part of the string that is displayed.
However when the interpreter evaluates the length expression, it only needs to look at the structure of the resulting list. It does not have to look at the actual elements inside the list. So since Haskell, being a lazy language, only evaluates what it has to, that means that the elements will not be evaluated and thus no exception is thrown.
This is some good old Haskell lazy evaluation! If Haskell doesn't have to compute something, it wont. In this case, you are calling map on a list of length 4. As far as Haskell is concerned, applying map to any list will return a list of the same size, regardless of what operation you are applying. Therefore, Haskell simply tells you the length is 4, without actually dividing anything by 0.

Time cost of Haskell `seq` operator

This FAQ says that
The seq operator is
seq :: a -> b -> b
x seq y will evaluate x, enough to check that it is not bottom, then
discard the result and evaluate y. This might not seem useful, but it
means that x is guaranteed to be evaluated before y is considered.
That's awfully nice of Haskell, but does it mean that in
x `seq` f x
the cost of evaluating x will be paid twice ("discard the result")?
The seq function will discard the value of x, but since the value has been evaluated, all references to x are "updated" to no longer point to the unevaluated version of x, but to instead point to the evaluated version. So, even though seq evaluates and discards x, the value has been evaluated for other users of x as well, leading to no repeated evaluations.
No, it's not compute and forget, it's compute - which forces caching.
For example, consider this code:
let x = 1 + 1
in x + 1
Since Haskell is lazy, this evaluates to ((1 + 1) + 1). A thunk, containing the sum of a thunk and one, the inner thunk being one plus one.
Let's use javascript, a non-lazy language, to show what this looks like:
function(){
var x = function(){ return 1 + 1 };
return x() + 1;
}
Chaining together thunks like this can cause stack overflows, if done repeatedly, so seq to the rescue.
let x = 1 + 1
in x `seq` (x + 1)
I'm lying when I tell you this evaluates to (2 + 1), but that's almost true - it's just that the calculation of the 2 is forced to happen before the rest happens (but the 2 is still calculated lazily).
Going back to javascript:
function(){
var x = function(){ return 1 + 1 };
return (function(x){
return x + 1;
})( x() );
}
I believe x will only be evaluated once (and the result retained for future use, as is typical for lazy operations). That behavior is what makes seq useful.
You can always check with unsafePerformIO or trace…
import System.IO.Unsafe (unsafePerformIO)
main = print (x `seq` f (x + x))
where
f = (+4)
x = unsafePerformIO $ print "Batman!" >> return 3
Of course seq by itself does not "evaluate" anything. It just records the forcing order dependency. The forcing itself is triggered by pattern-matching. When seq x (f x) is forced, x will be forced first (memoizing the resulting value), and then f x will be forced. Haskell's lazy evaluation means it memoizes the results of forcing of expressions, so no repeat "evaluation" (scary quotes here) will be performed.
I put "evaluation" into scary quotes because it implies full evaluation. In the words of Haskell wikibook, "Haskell values are highly layered; 'evaluating' a Haskell value could mean evaluating down to any one of these layers."
Let me reiterate: seq by itself does not evaluate anything. seq x x does not evaluate x under any circumstance. seq x (f x) does not evaluate anything when f = id, contrary to what the report seems to have been saying.

Learning Haskell maps, folds, loops and recursion

I've only just dipped my toe in the world of Haskell as part of my journey of programming enlightenment (moving on from, procedural to OOP to concurrent to now functional).
I've been trying an online Haskell Evaluator.
However I'm now stuck on a problem:
Create a simple function that gives the total sum of an array of numbers.
In a procedural language this for me is easy enough (using recursion) (c#) :
private int sum(ArrayList x, int i)
{
if (!(x.Count < i + 1)) {
int t = 0;
t = x.Item(i);
t = sum(x, i + 1) + t;
return t;
}
}
All very fine however my failed attempt at Haskell was thus:
let sum x = x+sum in map sum [1..10]
this resulted in the following error (from that above mentioned website):
Occurs check: cannot construct the infinite type: a = a -> t
Please bear in mind I've only used Haskell for the last 30 minutes!
I'm not looking simply for an answer but a more explanation of it.
I'm not looking simply for an answer but a more explanation of it.
On the left-hand side of the = you use sum as a function applied to x. The compiler doesn't know the type of x, so the compiler uses type variable a to stand for "the type of x." At thus point the compiler doesn't know the result type of the function sum either, so it picks another type variable, this type t, to stand for the result type. Now on the left-hand side the compiler thinks that the type of x is a -> t (function accepting a and returning t).
On the right-hand side of the = you add x and sum. In Haskell all kinds of numbers can be added, but you can add two numbers only if they have the same type. So here the compiler assumes that sum has the same type as x, namely type a.
But in Haskell an identifier has one type—maybe a whangdilly complicated type, but one type nevertheless. This includes sum, whose type should be the same on both sides of the ` sign, so the compiler tries to solve the equation
a = a -> t
There are no values for a and t that solve this equation. It simply can't be done. There is no a such that a is equal to a function that accepts itself as an argument. Thus ariseth the error message
cannot construct the infinite type: a = a -> t
Even with all the explanation, it's not such a great error message, is it?
Welcome to Haskell :-)
P.S. You might enjoy trying "Helium, for learning Haskell", which gives much nicer error messages for beginners.
'sum' takes a list of values and reduces it to a single value. You can either write it as an explicit loop (remember that Haskell has no loop keywords, but uses recursion). Note how the definition has two parts, based on the shape of the list:
mysum [] = 0
mysum (x:xs) = x + mysum xs
Or more efficiently, in a tail-recursive style:
mysum xs = go 0 xs
where
go n [] = n
go n (x:xs) = go (n+x) xs
However, Haskell has a rich library of control structures that operate on lazy lists. In this case, reduction of a list to a single value can be done with a reduce function: a fold.
So mysum can be written as:
mysum xs = foldr (+) 0 xs
For example:
Prelude> foldr (+) 0 [1..10]
55
Your mistake was to use a map, which transforms a list, one element at a time, rather than a fold.
I'd suggest you start with an introduction to Haskell, perhaps "Programming in Haskell", to get a feel for the core concepts of functional programming. Other good introductory materials are described in this question.
You need to read a good tutorial, there are a number of big misunderstandings.
First I'm going to assume you mean lists and not arrays. Arrays exist in Haskell, but they aren't something you'd encounter at the beginner level. (Not to mention you're using [1..10] which is a list of the numbers 1 to 10).
The function you want is actually built in, and called sum, so we'll have to call our something else, new_sum:
new_sum [] = 0
new_sum (h:t) = h + (sum t)
Let's look at the first part of this:
let sum x = x+sum
What would the type of sum be in this case? It takes a number and returns a function that takes a number which returns a function that takes a number etc. if you had written it
let sum x = + x
you would have a function that takes a number and returns the function +x.
and
let sum = +
would return a function that takes two integers and adds them.
so now let's look at the second part.
in map sum [1..10]
map takes a function of one argument and applies it to every element of the list. There is no room to wedge an accumulator in there, so let's look at other list functions in particular foldl, foldr. both of these take a function of two arguments a list and a beginning value. The difference between foldl and foldr is on the side in which they start. l being left so 1 + 2 + 3 etc and r being right 10 + 9 + 8 etc.
let sum = (+) in foldl sum 0 [1..10]

Resources