As you can guess, functions are highly regarded in functional programming. There is an emphasis on "purity", something you don't hear much about in OO. Simply put, a pure function does its work without side effects. Repeatedly invoking a pure function with the same arguments will always yield the same result.
When you hear this topic discussed in FP, it frequently includes references to mutable state. For example, if invoking your function changes the state of a variable, your function is not pure. In fact, if your function even references a global variable, it is not pure. Why? Because you can't guarantee that invoking your function repeatedly, with the same arguments, will yield the same results, because it relies on state over which it has no control.
In functional programming, the goal is to keep code as pure as possible and to isolate impure code. One advantage of pure code is in testing, as you don't have to worry about the effect of other threads on the results produced by your code. In addition to code that employs mutable state, other examples of impure code are: any I/O, pinging a web service for that live data feed, and so on. As I go through my self-training, I will be very interested in how useful an FP application will be in my field. I write mostly middle-tier Java code with a lot of interfaces to web services, and I have to admit at this stage I'm a little skeptical. Will I write a big chunk of FP code that's 99% "impure" and feel that I just performed the equivalent of porting a Fortran program to C++? I hope not. But it's way too early to pass judgment, and I expect a far happier outcome.
Anatomy of a Haskell function
Functions in Haskell look a lot different than Java functions. I've spent a few months trying to become proficient in Erlang, and so the structure of an FP function is starting to become familiar to me. Here's an example Haskell function:
Given an agent's code number, it returns the agent's (real) name. In general, a function consists of:
agentName code =
if code == 86
then "adams"
else if code == 99
then "feldon"
else "unknown"
- The name of the function
- The argument names, separated by whitespace
- The equals "=" sign
- The expression that your function evaluates and returns
agentName code =you will see the following:
if code == 86
then "adams"
else if code == 99
then "feldon"
agentName.hs:7:1: parse error (possibly incorrect indentation)the reason being that there are some inputs for which the function will not be able to return a value at all. If you've ever declared a non-void Java function and forgot to return a value from a branch of an if statement, then this error message seems reasonable, if not quite as informative.
If we go back to the original version of the function, we can test its behavior:
Prelude> :load agentName.hsNote, in the examples, the indentation, which is required when a statement (in this case, the function definition) extends across a line boundary. The size of the indentation and the characters used (space, tab) are not important, as long as the indentation is there.
[1 of 1] Compiling Main ( agentName.hs, interpreted )
Ok, modules loaded: Main.
*Main> agentName 86
"adams"
*Main> agentName 99
"feldon"
*Main> agentName 007
"unknown"
There is obviously a lot more to Haskell functions, of course. The above points are what stand out to me as a mostly-OO developer.
I've been using the Glasgow Haskell Compiler and, in the examples above, the interactive interpreter (and debugger) ghci. Although I'm generally following Real World Haskell, I don't really expect to review the entire book in slow-motion on a blog (who would read that?). So I may not write a post about defining types unless it seems unusually foreign to OO. My ultimate goal is to become proficient enough to provide useful and practical advice, oriented toward an OO developer wanting to learn to write production-quality FP code.