views:

333

answers:

2

My Related Questions box overfloweth with functional programming questions. Having reviewed the most relevant, I'm still curious to hear opinions on the following:

How do you think about structuring an application in a functional language?

I'm not talking about a language-specific grammar. I'm interested in conceptual organizational paradigms (e.g object orientation).

Like many, my first exposure to encapsulation and code reuse came from the OO background. As I've been researching different languages, functional programming really caught my eye. I'm beginning to grasp the benefits of immutability, higher-order functions, et cetera. But I still lose my sense of how to structure a functional application without falling back on OO concepts. Actually, many of the functional examples I've seen have more in common with spaghetti code, although I'm sure that's due to the simplicity of the examples rather than any inherent flaw in the functional approach.

This question is kin to "when should I use functional programming," but I've already satisfied myself that the functional approach, despite pros and cons in certain domains, is usable for just about anything that you want. I just have trouble picturing the big-picture organization of a complex app.

+2  A: 

Most of the overall design patterns are completely applicable:

Separation of Concerns; Model-Control-Presentation (in all of it's variants); Layered Architecture; Input-Process-Output, etc.

Once you've decomposed a big problem into smaller problems, the smaller problems are a matter of working through the various transformations from source to destination representation.

I find that the input-process-output pattern and transformation pipeline patterns help.

S.Lott
Thanks for a great answer. I'm pretty new to programming, so many of these terms were unfamiliar to me -- that's a good thing, more to explore. Nothing a few hours on Wikipedia can't cure.
DanielMason
+14  A: 

In the late 1970s, Barbara Liskov and others developed a boatload of large-scale "object-oriented design" techniques which are still widely used today and which apply unchanged to functional programming. They are easiest to apply with a language that has explicit interfaces and implementations, which means Standard ML (where interfaces are called "signatures" and implementations are called "structures" or "functors") or Objective Caml (where interfaces are called "module types" and implementations are called "modules"). If you prefer Scheme then the "unit" language developed by Matthew Flatt and Matthias Felleisen is built into PLT Scheme and is a very good way of expressing large-scale functions.

In brief:

  • Organize your applications around abstract types (classes in OO, "abstract types" in FP) and the operations on those types.

  • Use encapsulation mechanisms (classes in OO, modules in FP) to hide the representations of your abstract types.

  • Structure your application so that each implementation depends on other implementations indirectly, through their interfaces. This way you limit the amount of code you have to understand to build or modify any one piece of your application.

  • Go to town!

The main difference is that when you're writing functional programs, you don't use inheritance to reuse implementations. Instead you use higher-order functions, or you use modules which take other modules as parameters.

Summary: at the architectural level, there's not a lot of difference, but when using functional languages you may need to hunt a little harder to find the encapsulation mechanisms that you need.

Norman Ramsey
Awesome answer. In general, are there performance drawbacks to the module-taking-module-parameter approach, or does it just cost you a pointer? (Javascript is mental model that I have of this)
DanielMason
@DanielMason: For a naive compiler, you pay about the same overhead you would in an object-oriented language: the module is represented by a pointer to a vtable. But the better compilers do a good job inlining small functions across module boundaries, so they have less overhead. And MLton is a really good whole-program compiler, so there's no run-time overhead at all. http://mlton.org/
Norman Ramsey
Thank you for the follow-up. That gives me a lot to delve into.
DanielMason
Unfortunately F# (which the only specific language tagged on this question) doesn't support modules taking other modules as parameters.
Ganesh Sittampalam