[m-users.] spawn in Rosettacode
Paul Bone
paul at bone.id.au
Sun Sep 7 13:18:57 AEST 2014
On Sun, Aug 31, 2014 at 02:39:36PM +1000, Robert Smart wrote:
> Thanks Mark. I've put a link a link to your email in my blog post on the
> subject (
> http://wombatlang.blogspot.com.au/2014/08/lazyness-backtracking-and-explicit-io.html).
> Mistakes in my post will be quickly fixed. I look forward to understanding
> it all better one day!
>
if you don't mind I have some feedback about your blog post.
"The reason it is explicit about IO is because it supports backtracking
when searching for a logical result. So it needs to thread IO to prevent
backtracking into an IO operation that has already happened."
This is part of the reason, the other part is that without explicit marking
of IO the language would not be declaratively pure. We believe that being
declaratively pure is important because it makes programs more reliable.
Consider a predicate:
:- pred do_something(x::in, y::out) is det.
By inspection, we can see that it takes some type "x" as input and produces
a result whose type is "y". We can also see that it is deterministic and
does not do any IO (interact with the world outside your program). However,
if Mercury was not pure, then this predicate might or might-not interact
with the world, we can't tell from its declaration. We behave that it's
useful to be able to see at a glance if the predicate can interact with the
world or modify data. Firstly this helps programmers debug their programs
and secondly it can help the compiler compile (even optimize) the program.
"Why does Mercury have eager evaluation instead of lazy, since it is
declarative?"
Firstly, because it is faster. A lazy language must, as it reads every
piece of data, check if it has been evaluated yet or not. This test takes
up time and is performed very frequently. For example a binary tree is not
not one piece of data but N pieces of data, looking up an item in a balanced
binary tree causes log N checks. These add up and slow a program down. The
Glasgow Haskell Compiler goes to great lengths to try to optimize this,
unsuccessfully attempting to solve a problem that can be designed out by
simply using an eager language with a lazy module in the standard library.
The second problem, and probably a more important problem, is that reasoning
about performance is very difficult in a lazy language. Consider any
arbitrary predicate or function, is it slow or fast? It might be simple,
without any loops ore recursion and therefore you would assume it would be
fast, however if the data it is passed hasn't been evaluated yet then it
will have to evaluate that data first, which could be slow. A related
problem is known as a "space leak", this occurs when the chain of
unevaluated "thunks" is larger than the eventual result of the computation.
This can create programs that use excessive amounts of memory. These are
common problem in Haskell, just ask the developers of darcs.
Another problem, is that it's difficult to write a debugger for a lazy
language. A required feature of a debugger is being able to provide a stack
trace. This is difficult in a lazy language because the evaluation of a
function is not always related to when and where that function was called.
Laziness is still very useful and can help programmers express certain kinds
of problems. However it's not needed most of the time so a language that is
strict-by-default is faster, easier to engineer (writing a debugger) and
easier to use (easier to understand your program's performance).
I hope this information is useful and that you enjoy using Mercury. I look
forward to reading your other posts (after lunch).
Thanks.
--
Paul Bone
More information about the users
mailing list