Pure functions in D

bearophile bearophileHUGS at lycos.com
Mon Sep 22 08:10:28 PDT 2008


Brian Palmer:

> Since this wasn't touched on in the article, I want to point out that Haskell allows "pure functions" to throw exceptions, but not catch them. We need the same limitation in D2 pure functions -- since the exceptions can only be caught in impure code, it's OK that the pure function threw instead of returning. What can't happen is we can't have pure functions catching exceptions, since they can then return a different value when, for example, an out-of-memory exception is thrown.

This is quite interesting and it has some consequences. So a pure function can call another pure function only if the second one can't throw?
Pure functions can be recursive (because if the stack finishes all the program stops with an error). So recursive pure functions can't throw exceptions? :-)
Now I am sure that some knowledge of Haskell may help the design of the functional parts of D.

----------------

Walter says on Reddit:

>There's also nothrow, which would specify that the function also did not throw.<

But then you have to write function signatures as:

nothrow pure int foo(int x, const int[] a) {...}

That looks a bit long to write.

----------------

Walter:

>Functional programming capability is an exciting addition to imperative programming languages.<

I agree.
A general comment: functional programming (like OOP) doesn't work in vacuum. Computer languages are like ecologies of many interacting syntaxes. So for some functional programming capability to "survive" well in one of such ecologies several other parts of that ecology have to be fit. To make the usage of FP capabilities handy/good enough to be actually used several other things in a compiler/language have to be fit, like:
- Good closures
- A very compact syntax for delegates/closures. In Haskell and other FP languages you can see how you can even turn operators into functions in a very short space.
- Some type inference, because types tend to become quite convoluted, etc. FP languages have type systems that are much more complex than the currend D one (you don't need to look at Haskell type system, eve, lesser FP languages fit the bill).
- Some higher-order functions with a short and flexible syntax, like folds, maps, filters you can find in most FP languages, list comprehensions, etc that in various forms you can find in Python, Ruby, Haskell, etc.
- Good management of operator precedence.
- Good management of lazy iterables, for example like the presence of the len() function of my libs  that returns the length of both eager and lazy iterables, etc.

D already has some/part of those things and I am not saying that you need all of them to program in a functional style. In truth you can probably have FP even without all of them. But then the functional programming itself become awkward, feels unnatural, or that requires too much code, and in the end it becomes used very little.

So I can already use something like (this is just for show, not working):
map((int i){ return op(i)+op(i); }, xfilter((int i){ ....}, iterable)));

but it's too much unreadable, so it becomes worse than a normal for loop. While with a Python (or Haskell, or even Ruby) syntax you can do the same thing in a readable enough way, so programmers feel encouraged to actually use functional constructs. This is why syntax matters. Note that for a short syntax to work, the compiler may need to perform more type inferencing, and this in turn may require a a bit more powerful type system...
So to make FP in D actually usable a more powerful type system (plus some shorter/sugared syntax) may be needed. I don't know, we'll see.

Bye,
bearophile



More information about the Digitalmars-d mailing list