On Fri, 13 Feb 2009, Jon Lang wrote:
> In reading about functional programming, I ran across the concept of
> the "pure function" - i.e., a function that doesn't produce side
> effects.
[...]
> It occurred to me that this business of marking functions as pure could be
> done in perl by means of traits

Excellent plan.

But it's actually impurity that is infectious -- an impure function being
any function that might modify an object whose lifetime exceeds the
invocation of the function, either directly or by calling another impure
function. In the simple case that devolves to "you're impure if you call
another impure function, or modify anything in an outer scope".

But if you have objects and nested functions, the exact inference rule gets
a whole lot more complicated. With exceptions, threads and co-routines it's a
nightmare. In the general case, if your language has both pure and impure
functions, proving (at compile time) that something is not impure is an
NP-complete problem.

So you really want the programmer to mark them for you, and to have run-time
checking to make sure assumptions are not violated. And to encourage
efficiency generally, you want the Huffman coding for "pure" to be shorter
than the Huffman coding for "impure", or better still, "pure by default".

Perhaps anonymous code using the arrow notation should be implicitly
":pure"?


Another approach would be to treat purity like class finalization: start by
assuming you have pure functions, but go back and regenerate them if you
discover that a sub-function somewhere is actually impure. It won't be
trivial, given that you'll have to restart the regenerated code somewhere in
the middle.


Something else to be considered: we're close to reaching the limit on CPU
clock speed -- maybe only one more order of magnitude over the next couple
of decades. From here on the big gains will be from packing ever more cores
into a CPU, and development massively parallel software to take advantage of
them.

Applicative languages have a huge head-start on that; their no-overwrite
rule ("there are no variables, only values") means that data-flow
dependencies are *always* obvious, so very fine-grained parallel scheduling
can be used get a performance gain from every extra hyperthread (*1).

Although Perl6 will get quite a boost from various code migration
techniques, probably the biggest win will be from such implicit massive
micro-threading. If Perl6 can dispatch lots of threads all the time, not
just with "map" or "grep", then it will make the best possible use of the
available hardware.

However for this to be possible, just being "pure" won't be enough. It will
also need:

(A) cacheable functions whose return value depend only on the declared
parameters (this is orthogonal to not modifying the external environment);
and

(B) truly immutable objects, and declarative ways to guarantee them in all
contexts, such as:

        * immutable function parameters (that can't be changed by the function)

        * constant function parameters (that can't be changed by someone else 
while the function is looking at them, even by other threads or coroutines)

        * deep auto-cloning mutable "container" objects into immutable "value" 
ones

        * auto-boxing immutable "value" objects into "container" objects


-Martin

(*1: Google for the report by G Y Matthews (Sydney University, 1994) on
reformulating the "Magma" mathematical research language as an applicative
language.)

Reply via email to