Evaluation of nullary functions in Haskell - haskell

Suppose you have a nullary function in Haskell, which is used several times in the code. Is it always evaluated only once? I already tested the following code:
sayHello :: Int
sayHello = unsafePerformIO $ do
putStr "Hello"
return 42
test :: Int -> [Int]
test 0 = []
test n = (sayHello:(test (n-1)))
When I call test 10, it writes "Hello" only once, so it's indicating the result of function is stored after first evaluation. My question is, is it guaranteed? Will I get the same result across different compilers?
Edit
The reason I used unsafePerformIO is to check whether sayHello is evaluated more than once. I don't use that in my program. Normally I expect sayHello to have exactly the same result every time its evaluated. But it's a time-consuming operation, so I wanted to know if it could be accessed this way, or if it should be passed as an argument wherever it's needed to ensure it is not evaluated multiple times, i.e.:
test _ 0 = []
test s n = (s:(test (n-1)))
...
test sayHello 10
According to the answers this should be used.

There is no such thing as a nullary function. A function in Haskell has exactly one argument, and always has type ... -> .... sayHello is a value -- an Int -- but not a function. See this article for more.
On guarantees: No, you don't really get any guarantees. The Haskell report specifies that Haskell is non-strict -- so you know what value things will eventually reduce to -- but not any particular evaluation strategy. The evaluation strategy GHC generally uses is lazy evaluation, i.e. non-strict evaluation with sharing, but it doesn't make strong guarantees about that -- the optimizer could shuffle your code around so that things are evaluated more than once.
There are also various exceptions -- for example, foo :: Num a => a is polymorphic, so it probably won't be shared (it's compiled to an actual function). Sometimes a pure value might be evaluated by more than one thread at the same time (that won't happen in this case because unsafePerformIO explicitly uses noDuplicate to avoid it). So when you program, you can generally expect laziness, but if you want any sort of guarantees you'll have to be very careful. The Report itself won't really give you anything on how your program is evaluated.
unsafePerformIO gives you even less in the way of guarantees, of course. There's a reason it's called "unsafe".

Top level no-argument functions like sayHello are called Constant Applicative Forms and are always memoised (atleast in GHC - see http://www.haskell.org/ghc/docs/7.2.1/html/users_guide/profiling.html). You would have to resort to tricks like passing in dummy arguments and turning optimisations off to not share a CAF globally.
Edit: quote from the link above -
Haskell is a lazy language, and certain expressions are only ever
evaluated once. For example, if we write:
x = nfib 25 then x will only be evaluated once (if at all), and
subsequent demands for x will immediately get to see the cached result.
The definition x is called a CAF (Constant Applicative Form), because
it has no arguments.

If you do want "Hello" printed n times, you need to remove the unsafePermformIO, so the runtime will know it can't optimize away repeated calls to putStr. I'm not clear whether you want to return the list of int, so I've written two versions of test, one of which returns (), one [Int].
sayHello2 :: IO Int
sayHello2 = do
putStr "Hello"
return 42
test2 :: Int -> IO ()
test2 0 = return ()
test2 n = do
sayHello2
test2 (n-1)
test3 :: Int -> IO [Int]
test3 0 = return []
test3 n = do
r <- sayHello2
l <- test3 (n-1)
return $ r:l

Related

Can any partial function be converted to a total version in Haskell?

So far I have seen numerous "Maybe" versions of certain partial functions that would potentially result in ⊥, like readMaybe for read and listToMaybe for head; sometimes I wonder if we can generalise the idea and work out such a function safe :: (a -> b) -> (a -> Maybe b) to convert any partial function into their safer total alternative that returns Nothing on any instances where error stack would have been called in the original function. As till now I have not found a way to implement such safe function or existing implementations of a similar kind, and I come to doubt if this idea is truly viable.
There are two kinds of bottom actually, non-termination and error. You cannot catch non-termination, for obvious reasons, but you can catch errors. Here is a quickly thrown-together version (I am not an expert so there are probably better ways)
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Exception
import System.IO.Unsafe
safe f = unsafePerformIO $ do
z <- try (evaluate f)
let r = case z of
Left (e::SomeException) -> Nothing
Right k -> Just k
return r
Here are some examples
*Main > safe (head [42])
Just 42
*Main > safe (head [])
Nothing
*Main λ safe (1 `div` 0)
Nothing
*Main λ safe (1 `div` 2)
Just 0
No, it's not possible. It violates a property called "monotonicity", which says that a value cannot become more defined as you process it. You can't branch on bottoms - attempting to process one always results in bottom.
Or at least, that's all true of the domain theory Haskell evaluation is based on. But Haskell has a few extra features domain theory doesn't... Like executing IO actions being a different thing than evaluation, and unsafePerformIO letting you hide execution inside evaluation. The spoon library packages all of these ideas together as well as can be done. It's not perfect. It has holes, because this isn't something you're supposed to be able to do. But it does the job in a bunch of common cases.
Consider the function
collatz :: Integer -> ()
collatz 1 = ()
collatz n
| even n = collatz $ n`div`2
| otherwise = collatz $ 3*n + 1
(Let's pretend Integer is the type of positive whole numbers for simplicity)
Is this a total function? Nobody knows! For all we know, it could be total, so your proposed safe-guard can't ever yield Nothing. But neither has anybody found a proof that it is total, so if safe just always gives back Just (collatz n) then this may still be only partial.

GHC: Are there consistent rules for memoization for calls with fixed values?

In my quest to understand and harness GHC automatic memoization, I've hit a wall: when pure functions are called with fixed values like fib 42, they are sometimes fast and sometimes slow when called again. It varies if they're called plainly like fib 42 or implicitly through some math, e.g. (\x -> fib (x - 1)) 43. The cases have no seeming rhyme or reason, so I'll present them with the intention of asking what the logic is behind the behavior.
Consider a slow Fibonacci implementation, which makes it obvious when the memoization is working:
slow_fib :: Int -> Integer
slow_fib n = if n < 2 then 1 else (slow_fib (n - 1)) + (slow_fib (n - 2))
I tested three basic questions to see if GHC (version 8.2.2) will memoize calls with fixed args:
Can slow_fib access previous top-level calls to slow_fib?
Are previous results memoized for later non-trivial (e.g. math) top-level expressions?
Are previous results memoized for later identical top-level expressions?
The answers seem to be:
No
No
Yes [??]
The fact that the last case works is very confusing to me: if I can reprint the result for example, then I should expect to be able to add them. Here's the code that shows this:
main = do
-- 1. all three of these are slow, even though `slow_fib 37` is
-- just the sum of the other two results. Definitely no memoization.
putStrLn $ show $ slow_fib 35
putStrLn $ show $ slow_fib 36
putStrLn $ show $ slow_fib 37
-- 2. also slow, definitely no memoization as well.
putStrLn $ show $ (slow_fib 35) + (slow_fib 36) + (slow_fib 37)
putStrLn $ show $ (slow_fib 35) + 1
-- 3. all three of these are instant. Huh?
putStrLn $ show $ slow_fib 35
putStrLn $ show $ slow_fib 36
putStrLn $ show $ slow_fib 37
Yet stranger, doing math on the results worked when it's embedded in a recursive function: this fibonacci variant that starts at Fib(40):
let fib_plus_40 n = if n <= 0
then slow_fib 40
else (fib_plus_40 (n - 1)) + (fib_plus_40 (n - 2))
Shown by the following:
main = do
-- slow as expected
putStrLn $ show $ fib_plus_40 0
-- instant. Why?!
putStrLn $ show $ fib_plus_40 1
I can't find any reasoning for this in any explanations for GHC memoization, which typically incriminate explicit variables (e.g. here, here, and here). This is why I expected fib_plus_40 to fail to memoize.
To elaborate in case it wasn't clear from #amalloy's answer, the problem is that you're conflating two things here -- the implicit memoization-like-behavior (what people mean when they talk about Haskell's "automatic memoization", though it is not true memoization!) that results directly from thunk-based lazy evaluation, and a compiler optimization technique that's basically a form of common subexpression elimination. The former is predictable, more or less; the latter is at the whim of the compiler.
Recall that real memoization is a property of the implementation of a function: the function "remembers" results calculated for certain combinations of arguments, and may reuse those results instead of recalculating them from scratch when called multiple times with the same arguments. When GHC generates code for functions, it does not automatically generate code to perform this kind of memoization.
Instead, the GHC code generates to implement function application is unusual. Instead of actually applying the function to arguments to generate the final result as a value, a "result" is immediately constructed in the form of a thunk, which you can view as a suspended function call or a "promise" to deliver a value at a later time.
When, at some future point, the actual value is needed, the thunk is forced (which actually causes the original function call to take place), and the thunk is updated with the value. If that same value is needed again later, the value is already available, so the thunk doesn't need to be forced a second time. This is the "automatic memoization". Note that it takes place at the "result" level rather than the "function" level -- the result of a function application remembers its value; a function does not remember the results it previously produced.
Now, normally the concept of the result of a function application remembering its value would be ridiculous. In strict languages, we don't worry that after x = sqrt(10), reusing x will cause multiple sqrt calls because x hasn't "memoized" its own value. That is, in strict languages, all function application results are "automatically memoized" in the same sense they are in Haskell.
The difference is lazy evaluation, which allows us to write something like:
stuff = map expensiveComputation [1..10000]
which returns a thunk immediately without performing any expensive computations. Afterwards:
f n = stuff !! n
magically creates a memoized function, not because GHC generates code in the implementation of f to somehow memoize the call f 1000, but because f 1000 forces (a bunch of list constructor thunks and then) a single expensiveComputation whose return value is "memoized" as the value at index 1000 in the list stuff -- it was a thunk, but after being forced, it remembers its own value, just like any value in a strict language would.
So, given your definition of slow_fib, none of your examples are actually making use of Haskell's automatic memoization, in the usual sense people mean. Any speedups you're seeing are the result of various compiler optimizations that are (or aren't) recognizing common subexpressions or inlining / unwrapping short loops.
To write a memoized fib, you need to do it as explicitly as you would in a strict language, by creating a data structure to hold the memoized values, though lazy evaluation and mutually recursive definitions can sometimes make it seem like it's "automatic":
import qualified Data.Vector as V
import Data.Vector (Vector,(!))
fibv :: Vector Integer
fibv = V.generate 1000000 getfib
where getfib 0 = 1
getfib 1 = 1
getfib i = fibv ! (i-1) + fibv ! (i-2)
fib :: Int -> Integer
fib n = fibv ! n
All of the examples you link at the end exploit the same technique: instead of implementing function f directly, they first introduce a list whose contents are all the calls to f that could ever be made. That list is computed only once, lazily; and then a simple lookup in that list is used as the implementation of the user-facing function. So, they are not relying on any caching from GHC.
Your question is different: you hope that calling some function will be automatically cached for you, and in general that does not happen. The real question is why any of your results are fast. I'm not sure, but I think it is to do with Constant Applicative Forms (CAFs), which GHC may share between multiple use sites, at its discretion.
The most relevant feature of a CAF here is the "Constant" part: GHC will only introduce such a cache for an expression whose value is constant throughout the entire run of the program, not just for some particular scope. So, you can be sure that f x <> f x will never reuse the result of f x (at least not due to CAF folding; maybe GHC can find some other excuse to memoize this for some functions, but typically it does not).
The two things in your program that are not CAFs are the implementation of slow_fib, and the recursive case of fib_plus_40. GHC definitely cannot introduce any caching of the results of those expressions. The base case for fib_plus_40 is a CAF, as are all of the expressions and subexpressions in main. So, GHC can choose to cache/share any of those subexpressions, and not share any of them, as it pleases. Perhaps it sees that slow_fib 40 is "obviously" simple enough to save, but it's not so sure about whether the slow_fib 35 expressions in main should be shared. Meanwhile, it sounds like it does decide to share the IO action putStrLn $ show $ slow_fib 35 for whatever reason. Seems like a weird choice to you and me, but we're not compilers.
The moral here is that you cannot count on this at all: if you want to ensure you compute a value only once, you need to save it in a variable somewhere, and refer to that variable instead of recomputing it.
To confirm this, I took luqui's advice and looked at the -ddump-simpl output. Here are some snippets showing the explicit caching:
-- RHS size: {terms: 2, types: 0, coercions: 0}
lvl1_r4ER :: Integer
[GblId, Str=DmdType]
lvl1_r4ER = $wslow_fib_r4EP 40#
Rec {
-- RHS size: {terms: 21, types: 4, coercions: 0}
Main.main_fib_plus_40 [Occ=LoopBreaker] :: Integer -> Integer
[GblId, Arity=1, Str=DmdType <S,U>]
Main.main_fib_plus_40 =
\ (n_a1DF :: Integer) ->
case integer-gmp-1.0.0.1:GHC.Integer.Type.leInteger#
n_a1DF Main.main7
of wild_a2aQ { __DEFAULT ->
case GHC.Prim.tagToEnum# # Bool wild_a2aQ of _ [Occ=Dead] {
False ->
integer-gmp-1.0.0.1:GHC.Integer.Type.plusInteger
(Main.main_fib_plus_40
(integer-gmp-1.0.0.1:GHC.Integer.Type.minusInteger
n_a1DF Main.main4))
(Main.main_fib_plus_40
(integer-gmp-1.0.0.1:GHC.Integer.Type.minusInteger
n_a1DF lvl_r4EQ));
True -> lvl1_r4ER
}
}
end Rec }
This doesn't tell us why GHC is choosing to introduce this cache - remember, it's allowed to do what it wants. But it does confirm the mechanism, that it introduces a variable to hold the repeated calculation. I can't show you core for your longer main involving smaller numbers, because when I compile it I get more sharing: the expressions in section 2 are cached for me as well.

Understanding Type of IO () in `let` Expression

Given:
λ: let f = putStrLn "foo" in 42
42
What is f's type? Why does "foo" not get printed before showing the result of 42?
Lastly, why doesn't the following work?
λ: :t f
<interactive>:1:1: Not in scope: ‘f’
What is f's type?
As you have correctly identified, it is IO () which can be thought of as an IO action that returns nothing useful (())
Why does "foo" not get printed before showing the result of 42?
Haskell is lazily evaluated, but even seq is not enough in this case. An IO action will only be performed in the REPL if the expression returns the IO action. An IO action will only be performed in a program if it's returned by main. However, there are ways to get around this limitation.
Lastly, why doesn't the following work?
Haskell's let names a value within the scope of an expression, so after the expression has been evaluated f goes out of scope.
let f = ... simply defines f, and does not "run" anything. It is vaguely similar to a definition of a new function in imperative programming.
Your full code let f = putStrLn "foo" in 42 could be loosely translated to
{
function f() {
print("foo");
}
return 42;
}
You wouldn't expect the above to print anything, right?
By comparison, let f = putStrLn "foo" in do f; f; return 42 is similar to
{
function f() {
print("foo");
}
f();
f();
return 42;
}
The correspondence is not perfect, but hopefully you get the idea.
f will be of type IO ().
"foo" is not printed because f is not 'binded' to real world. (I can't say this is a friendly explanation. If this sounds nonsense, you may want to refer some tutorial to catch the idea of Monad and lazy evaluation).
let name = value in (scope) makes the value available in, but not out of the scope, so :t won't find it in ghci's top level scope.
let without in makes it available to :t (this code is only valid in ghci):
> let f = putStrLn "foo"
> :t f
f :: IO ()
There are two things going on here.
First, consider
let x = sum [1..1000000] in 42
Haskell is lazy. Since we don't actually do anything with x, it is never computed. (Which is just as well, because it would be mildly slow.) Indeed, if you compile this, the compiler will see that x is never used, and delete it (i.e., not generate any compiled code for it).
Second, calling putStrLn does not actually print anything. Rather, it returns IO (), which you can think of as a kind of "I/O command object". Merely having a command object is different from executing the it. By design, the only way to "execute" an I/O command object is to return it from main. At least, it is in a complete program; GHCi has the helpful feature that if you enter an expression that returns an I/O command object, GHCi will execute it for you.
Your expression returns 42; again, f isn't used, so it doesn't do anything.
As chi rightly points out, it's a bit like declaring a local (zero-argument) function but never calling it. You wouldn't expect to see any output.
You can also do something like
actions = [print 5, print 6, print 7, print 8]
This creates a list of I/O command objects. But, again, it does not execute any of them.
Typically when you write a function that does I/O, it's a do-block that chains everything into one giant I/O command object and returns it to the caller. In that case, you don't really need to understand or thing about this distinction between defining a command object and executing it. But the distinction is still there.
It's perhaps easier to see this with a monad that has an explicit run-function. For example, runST takes an ST command object, runs it, and gives you back the answer. But (say) newSTVar, by itself, does nothing but construct an ST command; you have to runST that before anything actually "happens".

Haskell - Function which returns a different value each time it iterates

Say that I have a function:
doesAThing :: Int -> ChangeState
For the purpose of this question it's not especially important what ChangeState is, only that doesAThing needs to take an Int as a parameter and that doesAThing iterates infinitely.
What I want to do is take such a function:
addNum :: [Int] -> Int
addNum [n] = foldl (+) 0 ([n] ++ [n + 1])
and use it for doesAThing. Currently, the function works fine, however it doesn't do what I want it to do - it always returns the same number. The idea is that each time doesAThing iterates, addNum takes whatever its previous output was and uses that as addNum's parameter. I.e. :
First iteration: say that n was set at 0. addNum returns 1 (0 + 0 + 1) and doesAThing uses that to modify ChangeState.
Second iteration: now addNum takes 1 as its parameter, so that it returns 3 (0 + 1 + 2) and doesAThing uses that to modify ChangeState.
Third iteration: now addNum takes 3 as its parameter, returns 7 (0 + 3 + 4) and doesAThing uses 7 to modify ChangeState.
Etc.
Apologies if this is a really noobish question, self-teaching yourself Haskell can be hard sometimes.
If you want to change something, that means you need mutable state. There are two options. First, you can make current state one of the arguments of your function, and the new state — part of a result. Like addNum :: [Int] -> ([Int], Int). There is a State monad that helps with that, giving an illusion that there actually is some mutable state.
Secondly, you can store your state in an IORef and make your function use IO monad, like addNum :: IORef [Int] -> IO Int. That way you can actually modify the state kept in the IORef. There are other monads that allow the same thing, like ST, which is great if your mutable state is used only locally, or STM, which helps if your application is highly concurrent.
I would strongly recommend the first option though. Don't use IO (or other imperative things) until you absolutely need it.
You have encountered a situations where a programmer who is comfortable with Haskell would likely turn to monads. In particular the state monad, for which there are a few reasonable tutorials online:
https://acm.wustl.edu/functional/state-monad.php
http://brandon.si/code/the-state-monad-a-tutorial-for-the-confused/
https://www.schoolofhaskell.com/school/starting-with-haskell/basics-of-haskell/12-State-Monad
I didn't quite understand the "addNum" operation you are trying to describe, and I think there's some flaws with your attempts to define it. For example, the fact that your code always expects a list of exactly one element suggests that there shouldn't be a list or a foldl at all—just take n as an argument and add.
But from your description, I think the following approximates it as best as I can. (This won't be understandable without studying monads and the state monad a little bit, but hopefully it gives you an example to work with in conjunction with other materials.)
import Control.Monad.State
-- Add the previous `addNum` result to the argument.
addNum :: Int -> State Int Int
addNum n = do
-- Precondition: the previous call to `addNum` used `put`
-- (a few lines below here) to record its result as the
-- implicit state for the `State` monad.
previous <- get
let newResult = previous + n
-- Here we fulfill the precondition above.
put newResult
return newResult
The idea of the State monad is that you have get and put actions such that executing get retrieves the value that was most recently given as argument to put. To actually use addNum you need to do it within the context of a call to a function like evalState :: State s a -> s -> a, which forces you to specify the initial state that will be seen by the very first get in the very first use of addNum.
So, for example, here we use the traverse function to chain calls to addNum on consecutive elements of the list [1..10]. Each call to addNum for each list element will get the newResult value that was put by the call for the previous element. And the 0 argument to evalState means that the very first addNum call gets a 0:
>>> evalState (traverse addNum [1..10]) 0
[1,3,6,10,15,21,28,36,45,55]
If this feels overwhelming, well, for better or worse that's how Haskell feels at first. Keep at it and build up slowly to examples like this one.
What you want is impossible in Haskell, for good reason, see below.
There is a way to iterate over a function, however, by feeding it its own output in the next iteration.
Here is an example:
iterate (\c -> c + 2) 0
This creates the infinite list
[0,2,4,6,....]
Haskell is a pure language, and this means that a function can only access its arguments, constants, other functions and nothing else. Esqecially, there is no hidden state a function can access. Therefore, with the same input, a Haskell function will compute the same output all times.

Does a function in Haskell always evaluate its return value?

I'm trying to better understand Haskell's laziness, such as when it evaluates an argument to a function.
From this source:
But when a call to const is evaluated (that’s the situation we are interested in, here, after all), its return value is evaluated too ... This is a good general principle: a function obviously is strict in its return value, because when a function application needs to be evaluated, it needs to evaluate, in the body of the function, what gets returned. Starting from there, you can know what must be evaluated by looking at what the return value depends on invariably. Your function will be strict in these arguments, and lazy in the others.
So a function in Haskell always evaluates its own return value? If I have:
foo :: Num a => [a] -> [a]
foo [] = []
foo (_:xs) = map (* 2) xs
head (foo [1..]) -- = 4
According to the above paragraph, map (* 2) xs, must be evaluated. Intuitively, I would think that means applying the map to the entire list- resulting in an infinite loop.
But, I can successfully take the head of the result. I know that : is lazy in Haskell, so does this mean that evaluating map (* 2) xs just means constructing something else that isn't fully evaluated yet?
What does it mean to evaluate a function applied to an infinite list? If the return value of a function is always evaluated when the function is evaluated, can a function ever actually return a thunk?
Edit:
bar x y = x
var = bar (product [1..]) 1
This code doesn't hang. When I create var, does it not evaluate its body? Or does it set bar to product [1..] and not evaluate that? If the latter, bar is not returning its body in WHNF, right, so did it really 'evaluate' x? How could bar be strict in x if it doesn't hang on computing product [1..]?
First of all, Haskell does not specify when evaluation happens so the question can only be given a definite answer for specific implementations.
The following is true for all non-parallel implementations that I know of, like ghc, hbc, nhc, hugs, etc (all G-machine based, btw).
BTW, something to remember is that when you hear "evaluate" for Haskell it normally means "evaluate to WHNF".
Unlike strict languages you have to distinguish between two "callers" of a function, the first is where the call occurs lexically, and the second is where the value is demanded. For a strict language these two always coincide, but not for a lazy language.
Let's take your example and complicate it a little:
foo [] = []
foo (_:xs) = map (* 2) xs
bar x = (foo [1..], x)
main = print (head (fst (bar 42)))
The foo function occurs in bar. Evaluating bar will return a pair, and the first component of the pair is a thunk corresponding to foo [1..]. So bar is what would be the caller in a strict language, but in the case of a lazy language it doesn't call foo at all, instead it just builds the closure.
Now, in the main function we actually need the value of head (fst (bar 42)) since we have to print it. So the head function will actually be called. The head function is defined by pattern matching, so it needs the value of the argument. So fst is called. It too is defined by pattern matching and needs its argument so bar is called, and bar will return a pair, and fst will evaluate and return its first component. And now finally foo is "called"; and by called I mean that the thunk is evaluated (entered as it's sometimes called in TIM terminology), because the value is needed. The only reason the actual code for foo is called is that we want a value. So foo had better return a value (i.e., a WHNF). The foo function will evaluate its argument and end up in the second branch. Here it will tail call into the code for map. The map function is defined by pattern match and it will evaluate its argument, which is a cons. So map will return the following {(*2) y} : {map (*2) ys}, where I have used {} to indicate a closure being built. So as you can see map just returns a cons cell with the head being a closure and the tail being a closure.
To understand the operational semantics of Haskell better I suggest you look at some paper describing how to translate Haskell to some abstract machine, like the G-machine.
I always found that the term "evaluate," which I had learned in other contexts (e.g., Scheme programming), always got me all confused when I tried to apply it to Haskell, and that I made a breakthrough when I started to think of Haskell in terms of forcing expressions instead of "evaluating" them. Some key differences:
"Evaluation," as I learned the term before, strongly connotes mapping expressions to values that are themselves not expressions. (One common technical term here is "denotations.")
In Haskell, the process of forcing is IMHO most easily understood as expression rewriting. You start with an expression, and you repeatedly rewrite it according to certain rules until you get an equivalent expression that satisfies a certain property.
In Haskell the "certain property" has the unfriendly name weak head normal form ("WHNF"), which really just means that the expression is either a nullary data constructor or an application of a data constructor.
Let's translate that to a very rough set of informal rules. To force an expression expr:
If expr is a nullary constructor or a constructor application, the result of forcing it is expr itself. (It's already in WHNF.)
If expr is a function application f arg, then the result of forcing it is obtained this way:
Find the definition of f.
Can you pattern match this definition against the expression arg? If not, then force arg and try again with the result of that.
Substitute the pattern match variables in the body of f with the parts of (the possibly rewritten) arg that correspond to them, and force the resulting expression.
One way of thinking of this is that when you force an expression, you're trying to rewrite it minimally to reduce it to an equivalent expression in WHNF.
Let's apply this to your example:
foo :: Num a => [a] -> [a]
foo [] = []
foo (_:xs) = map (* 2) xs
-- We want to force this expression:
head (foo [1..])
We will need definitions for head and `map:
head [] = undefined
head (x:_) = x
map _ [] = []
map f (x:xs) = f x : map f x
-- Not real code, but a rule we'll be using for forcing infinite ranges.
[n..] ==> n : [(n+1)..]
So now:
head (foo [1..]) ==> head (map (*2) [1..]) -- using the definition of foo
==> head (map (*2) (1 : [2..])) -- using the forcing rule for [n..]
==> head (1*2 : map (*2) [2..]) -- using the definition of map
==> 1*2 -- using the definition of head
==> 2 -- using the definition of *
I believe the idea must be that in a lazy language if you're evaluating a function application, it must be because you need the result of the application for something. So whatever reason caused the function application to be reduced in the first place is going to continue to need to reduce the returned result. If we didn't need the function's result we wouldn't be evaluating the call in the first place, the whole application would be left as a thunk.
A key point is that the standard "lazy evaluation" order is demand-driven. You only evaluate what you need. Evaluating more risks violating the language spec's definition of "non-strict semantics" and looping or failing for some programs that should be able to terminate; lazy evaluation has the interesting property that if any evaluation order can cause a particular program to terminate, so can lazy evaluation.1
But if we only evaluate what we need, what does "need" mean? Generally it means either
a pattern match needs to know what constructor a particular value is (e.g. I can't know what branch to take in your definition of foo without knowing whether the argument is [] or _:xs)
a primitive operation needs to know the entire value (e.g. the arithmetic circuits in the CPU can't add or compare thunks; I need to fully evaluate two Int values to call such operations)
the outer driver that executes the main IO action needs to know what the next thing to execute is
So say we've got this program:
foo :: Num a => [a] -> [a]
foo [] = []
foo (_:xs) = map (* 2) xs
main :: IO ()
main = print (head (foo [1..]))
To execute main, the IO driver has to evaluate the thunk print (head (foo [1..])) to work out that it's print applied to the thunk head (foo [1..]). print needs to evaluate its argument on order to print it, so now we need to evaluate that thunk.
head starts by pattern matching its argument, so now we need to evaluate foo [1..], but only to WHNF - just enough to tell whether the outermost list constructor is [] or :.
foo starts by pattern matching on its argument. So we need to evaluate [1..], also only to WHNF. That's basically 1 : [2..], which is enough to see which branch to take in foo.2
The : case of foo (with xs bound to the thunk [2..]) evaluates to the thunk map (*2) [2..].
So foo is evaluated, and didn't evaluate its body. However, we only did that because head was pattern matching to see if we had [] or x : _. We still don't know that, so we must immediately continue to evaluate the result of foo.
This is what the article means when it says functions are strict in their result. Given that a call to foo is evaluated at all, its result will also be evaluated (and so, anything needed to evaluate the result will also be evaluated).
But how far it needs to be evaluated depends on the calling context. head is only pattern matching on the result of foo, so it only needs a result to WHNF. We can get an infinite list to WHNF (we already did so, with 1 : [2..]), so we don't necessarily get in an infinite loop when evaluating a call to foo. But if head were some sort of primitive operation implemented outside of Haskell that needed to be passed a completely evaluated list, then we'd be evaluating foo [1..] completely, and thus would never finish in order to come back to head.
So, just to complete my example, we're evaluating map (2 *) [2..].
map pattern matches its second argument, so we need to evaluate [2..] as far as 2 : [3..]. That's enough for map to return the thunk (2 *) 2 : map (2 *) [3..], which is in WHNF. And so it's done, we can finally return to head.
head ((2 *) 2 : map (2 *) [3..]) doesn't need to inspect either side of the :, it just needs to know that there is one so it can return the left side. So it just returns the unevaluated thunk (2 *) 2.
Again though, we only evaluated the call to head this far because print needed to know what its result is, so although head doesn't evaluate its result, its result is always evaluated whenever the call to head is.
(2 *) 2 evaluates to 4, print converts that into the string "4" (via show), and the line gets printed to the output. That was the entire main IO action, so the program is done.
1 Implementations of Haskell, such as GHC, do not always use "standard lazy evaluation", and the language spec does not require it. If the compiler can prove that something will always be needed, or cannot loop/error, then it's safe to evaluate it even when lazy evaluation wouldn't (yet) do so. This can often be faster so GHC optimizations do actually do this.
2 I'm skipping over a few details here, like that print does have some non-primitive implementation we could step inside and lazily evaluate, and that [1..] could be further expanded to the functions that actually implement that syntax.
Not necessarily. Haskell is lazy, meaning that it only evaluates when it needs to. This has some interesting effects. If we take the below code, for example:
-- File: lazinessTest.hs
(>?) :: a -> b -> b
a >? b = b
main = (putStrLn "Something") >? (putStrLn "Something else")
This is the output of the program:
$ ./lazinessTest
Something else
This indicates that putStrLn "Something" is never evaluated. But it's still being passed to the function, in the form of a 'thunk'. These 'thunks' are unevaluated values that, rather than being concrete values, are like a breadcrumb-trail of how to compute the value. This is how Haskell laziness works.
In our case, two 'thunks' are passed to >?, but only one is passed out, meaning that only one is evaluated in the end. This also applies in const, where the second argument can be safely ignored, and therefore is never computed. As for map, GHC is smart enough to realise that we don't care about the end of the array, and only bothers to compute what it needs to, in your case the second element of the original list.
However, it's best to leave the thinking about laziness to the compiler and keep coding, unless you're dealing with IO, in which case you really, really should think about laziness, because you can easily go wrong, as I've just demonstrated.
There are lots and lots of online articles on the Haskell wiki to look at, if you want more detail.
Function could evaluate either return type:
head (x:_) = x
or exception/error:
head _ = error "Head: List is empty!"
or bottom (⊥)
a = a
b = last [1 ..]

Resources