
On 10/12/09 12:07, Magnus Therning wrote:
As I understand it it all started with laziness. I don't know if laziness is impossible without purity, but talks and papers tend to say something like "laziness has kept Haskell pure".
This is true, but laziness has its own advantages. Suppose I have two modules, Foo and Bar. Foo generates a data structure which is then consumed by Bar (possibly with some other component calling both of them). In a strict language I have to choose between one of these three options: 1. Foo generates the structure all at once, and some kind of reference is then passed to Bar. This is nice, simple and modular, but it only works for small structures. There can also be a problem if the structure is slow to generate but is only consumed a bit at a time (e.g. by the user interface) because Bar can only start work once Foo has finished the whole thing. You may also find the Foo is doing lots of unnecessary work building bits of the structure that Bar uses only rarely. 2. Foo and Bar are built together in a single module with their functionality interleaved. This means that Foo can build a bit of the structure, have Bar process it, and so on. However it also destroys any modularity the system might have had. If Bar is part of the user interface, for instance, it means that core functionality gets mixed up. 3. Implement some kind of generator object. This takes a lot of code and makes the logic of Foo and Bar harder to follow. For instance the version of Foo from option 1 might have had a loop of the form "foreach i in xs". Now "i" has to be turned into some kind of member variable with logic to move to the next instance. Of course what you are really doing is creating an ad-hoc hand-coded version of lazy evaluation. Different applications are going to require different choices. Worse yet, the right answer can change. For instance you may start with option 1, then discover that the program runs too slowly. Or marketing decide that the maximum size of the data structure has to be increased. So at that point you have to rewrite a big chunk of code. Or else you go with option 2 or 3 because the designer thought it was necessary for efficiency when in fact option 1 would have done nicely. Of course with lazy evaluation you get option 3 all the time automatically. So its just not a problem. This makes the design much simpler because things that previously had to be decided by a human are now decided by the compiler. Paul.