It seems that the next major transition / fad will be towards Functional Programming. What resources / experiences are you finding necessary to grok functional programming?
I found Charming Python: Functional Programming Part 1 and Part 2 to be a good introduction. I'm a Python newbie and it seemed like a good way to start without learning a completely unfamiliar language.
There are some techniques in there that I find useful to apply but I haven't had the need to go to a purely functional approach to anything.
I think a more important question here would be "Under what circumstances should I be using functional programming techniques?"
I'd love to be able to give examples where F# (for example) is "better" than C#, but I am yet to read any persuasive arguments either way.
Really? I think as a community we're having enough trouble getting our heads round OOP and design patterns. Is Functional Programming really a new wave? This looks like a nice little resource page about it from the 90s.
A Guide to Functional Programming on the Web
Maybe I am showing my ignorance, or perhaps the PHP world is in a different place right now, but this seems of little relevance to me as a web developer.
It does bring up an interesting question; I tend to assume everyone else here is from the web design or web development industry, because that's what I do. Do we have lots of enterprise COBOL and Java developers, embedded application developers and proper desktop application developers here? What other programming worlds are there?
@ZombieSheep: I agree that knowing the circumstances would help you learn, but just as Procedural > OO was a major mind shift, so I think Functional programming could bring a revolutionary change. Particularly when we can start to offload processing to our mostly idle GPUs (e.g. CUDA, OpenCL).
What functional programming seems to do is lessen the need for variables. These "placeholders" are factored out more because functions themselves are seen in the code being used as someone who works in imperative languages would use variables.
This allows you to have tighter more elegant code. Someone who's worked in a C derivative language could see it as putting the meat of the code within a function's argument list.
Here's a good example of why functional programming just for the sake of it is a bad idea. I wrote this little word counting program just as an exercise and it's pretty horrible to look at.
#!/usr/bin/python
import sys
import string
###############################################################
def incrementCounts(word):
if counts.has_key(word):
counts[word] += 1
else:
counts[word] = 1
def printCount(key):
print counts[key], "\t", key
cleanWord = lambda x: x.strip(',').strip('.').strip()
###############################################################
counts = {}
map(
lambda y: map(
incrementCounts,
map(
cleanWord,
y.split()
)
),
sys.stdin.readlines()
)
map(
printCount,
counts.keys()
)
You can also listen to the Berkeley CS 61A Podcasts, which are fantastic, and deal with Functional Programming in Scheme.
Something that's perhaps even more mindblowing is Logic Programming, which goes even further. And with increased parallelisation, might even improve performance!
@Flubba: Daily I work on MS SQL-centric OLAP applications, with user inputs deployed using .NET ClickOnce as WinForm applications.
OO design revolutionized the way I develop applications (even though many of the concepts were decades old), and I am anticipating the same kind of benefits from scaling out calculations and/or MapReduce type of solutions using a Functional paradigm.
I tried Haskell years ago, and it just didn't click, I don't know why. But I've been looking at it now that I know ocaml, and I have a bit more free time and things are looking of the norm. Ocaml, was a great transition, for me. There are a number of great 'books' out their, Introduction to Ocaml, was the one I started on.
I mentioned in another thread that reading Purely Functional Data-Structures will help you get in the mindset and understand saving space and time in a persistent world. But, there are definitely tons of free resources --a great Haskell introduction is Real World Haskell.
Also, I would check out the great video series, Structure and Interpretation of Computer Programs. It'll definitely help you start thinking in a functional manor.
@Mark --this might look a little better -- I don't know python, and I didn't have time to figure out exactly from the code what you were doing --I read it now and it makes sense. Following, is what you want to do in ocaml, and it looks fine. I arbitrarily used a hashtable, you'd really want to make a functor that can manage the data better.
let freq_words str =
let add_mem tbl elm =
if Hashtbl.mem tbl elm then
Hashtbl.replace tbl elm ((Hashtbl.find tbl elm)+1)
else Hashtbl.add tbl elm 1
in
let tbl = Hashtbl.create 10 in
let str_lst = Str.split (Str.regexp "[ \t]+") str in
let () = List.iter (add_mem tbl) str_lst in
Hashtbl.iter (fun x y -> Printf.printf "%s: %d\n" x y) tbl
# freq_words "foo foo bar foo bar foobar barfoo foo foobar";;
foo: 4
foobar: 2
bar: 2
barfoo: 1
Good Luck!
I'd say the easiest way to transition to functional programming is definitely Scala. The syntax is a lot easier for newcomers to follow, and it seems that with other functional languages (O'Caml, Haskell, Lisp), the big hangups all involve not being used to the different style of syntax. Scala also comes with a hefty manual that's pretty easy to follow along and plays itself (imo) kinda like Java without all the keyword-bloat and with functions as first class.
@nlucaroni
The intention is to count the frequency of words in a file and print out each word with the count beside it. Is that what your snippet is doing?
Either way, it illustrates my point that, done injudiciously, functional programming can destroy the readability of a block of code. Of course it's easy to write horrible code using any language or methodology.
One more reason to be careful about using something for the sake of it rather than an actual need.
Functional program has been treated like a religion for quite some time, but in reality it is more of a style. Just like Object Oriented programming. The best way to get get started using functional programming is to just write code. I highly reccomend taking a stab at Project Euler problems in any functional language as a starting point.
But since functional programming in most common languages (C++, C#, Java) is difficult, I would reccomend learning a multi-paradigm language. (One which does OO and Functional, as a way of learning functional programming without jumping off the deep end.)
Coming from Java, Scala seems like the most resonable choice. And for .NET developers coming from a C# background, F# is the way to go.
F# seems to be shaping up as Microsoft's .NET answer in the functional programming world. Matt Podwysocki has a ton of functional programming posts on his blog: http://podwysocki.codebetter.com/
Many of his posts deal with the questions that you have posed.
@ZombieSheep: I'd love to be able to give examples where F# (for example) is "better" than C#, but I am yet to read any persuasive arguments either way.
Check out Matt's blog for some side-by-side comparisons of the C# vs F# approaches to FP.
@Mark Biek That code sample isn't functional as it modifies the count variable. Successive calls to incrementCounts will not give the same result as it is dependent on the state of counts.
The counting problem is an example of a problem that is highly paralisable using MapReduce.
Just try to apply the functional programming process to your current work with your current language. At work, I use functional principles in C++, VB6 and JavaScript and it works great, I write less code and more features.
Here are the principles you should consider:
Immutable Objects
You should as much as possible use constants instead of variables. More variables means more states for your function, more code paths to test, more bugs you can introduce. Haven't you ever introduce a bug because that variable contains "plop" at the beginning of the function and surprise, it actually contains "onk" at the end and you do not understand where it changed. Well the best way to deal with that is to never change.
const int price = getPrice();
const int priceWithVAT = price * 1.196;
return priceWithVAT;
instead of
int price = getPrice();
price *= 1.196;
return price;
Side effect: you will have more constants than variables and will be forced to name them. A little more brainwork but it makes the code far more readable and you won't need comments anymore.
When it is not possible, for performance reason or readability, try to isolate the variable within its own function.
Using constants will help the compiler to know when your program actually changes state and when it's not, helping it during its optimization process.
Generic algorithms and closures
Try to factorize as much as possible your code, even your simplest algorithms. Making some algorithms generic will make your code more readable and more robust because you won't be always writing the same mistakes.
struct Displayer
{
const std::string& str;
Displayer(const std::strin& str): str(str) {}
void operator()(const Value& val)
{
cout << str << val;
}
}
std::for_each( array.begin(), array.end(),
Displayer("plop")
);
std::for_each( array2.begin(), array2.end(),
Displayer("onk")
);
Again the compiler will be your friend here. Note that the loop I wrote here will be faster than the loop an average programmer will write. This is because for_each() is really optimized to be fast (no temporaries, no recomputing, etc.) and using a functor instead of a function pointer actually helps the compiler to inline the code (because a compiler is not allowed to inline a function as long as someone takes a pointer to it).
Note that all these examples are in C++, the language considered the less functional, maybe after ASM :D
What I mean is that functional programming can help you in any language as long as you understand the principles and don't close your mind on a specific language.
Start simple -- remember the basic principle is that you do not do anything that would harm or otherwise change the state of any of the arguments to your function. Void functions are automatically suspect as they don't return anything -- so they must be modifying something somewhere.
Try to eliminate variables where practical and where it won't be an obvious performance drag to do so. Replace those variables with the call to the function instead. If you do need variables, make sure they are limited (mostly) to within the functions themselves.
After a while you'll start to write more and more naturally in this style and imperative programming will start to seem a bit clumsy to you.
But remain practical, don't do anything stupidly inefficient just to remain compliant with a particular school of programming wisdom.
Here's my Haskell version. Haskell's term for a hashtable is Data.Map;
module Main where
import System.Environment
import Data.Map
main = do
strings <- getArgs
let hash = freq_words (concat strings)
formatIt hash
formatIt hash = mapM_ (\(k,v) -> putStrLn (k ++ ": "++(show v) )) $ assocs hash
freq_words string = foldl h empty (words string)
where h hash word = -- if the word is already there, increment the count; otherwise, add it.
insertWith (+) word 1 hash
-- test stuff
t1 = "foo foo bar foo bar foobar barfoo foo foobar"
t2 = [("a",1),("b",2),("c",3)]
fmt = formatIt
test1 = freq_words t1
test2 = fmt test1
Here's another Haskell version of word count program in point free style:
import Char
import List
main = interact $ unlines -- combine list into output text
. map (\x -> shows(length x) $ ' ' : head x) -- get word/freq for each group
. group -- group the list of words
. sort -- Sort the list of words
. words -- break text into list of words
. filter (\x->isAlpha x || isSpace x) -- remove non words
. map toLower -- Convert text to lower case
Due to the function pipeline with the function composition operator (the period '.'), you would logically read this code from bottom up. This code could also be formatted so the entire code is a single line (without the comments) and operations would go from right to left.
import Char
import List
main = interact$unlines.map (\x -> shows(length x) $ ' ' : head x).group.sort.words.filter(\x->isAlpha x || isSpace x).map toLower
Given the myriad of different ways and styles that you can write a Haskell code and in ways that are not necessarily easy to understand, I almost liken Haskell as Perl of functional programming language.
In terms of learning functional programming languages, I like Graham Hutton's "Programming in Haskell" book the best. It's an easy and introductory book to Haskell and reminds me a lot of the old K&R C programming book. In terms of actual practice with functional programming, I'm more inclined to work with F# and use that to work through the book examples that uses C# code. I get to learn functional programming and new technology/API at the same time. For F# programming, I highly recommend Don Syme's "Expert F#" book. However, since F# allows for a mix of functional programming style and imperative programming style, you might easily fall back to an imperative style of programming. I would recommend working with Haskell first just so that you get an understanding of what it's like to program in a purely functional programming language.
BTW, SQL and XSLT are functional programming languages also. So if you ever program in those, you already know functional programming!
The word counting game seemed fun so here is my Scala version
def countWords(s:String) =
{
"\\S+".r.findAllIn(s).foldLeft(Map[String,Int]()){
(count:Map[String,Int],word:String) => count + (word -> (count.getOrElse(word,0) + 1))
}
}
To really teach myself what's necessary and different about functional programming, I read many of the old papers on functional programming (especially Paul Hudak's 1989 survey and John Hughes' 1984 justification), and wrote small shell scripts to implement functional programming commands (map, fold, etc.). The greatest advantages I found were that (1) I reuse generalized code from "for" loops in separate scripts, and (2) I save about an order of magnitude execution time, since my "map" command dynamically writes a makefile so "gmake -j" can execute commands in parallel.
Those example of word counting seemed a bit imperative to me so I tried my hand at it. Here we have my attempt in Javascript 1.6.
var count=new Array();
function getWordFrequency(text){
var addRef =
function(w){
count[w]=lstWords.filter(function(x){return x === w;}).length;
}
var lstWords = text.split(" ");
lstWords.forEach(addRef);
}
getWordFrequency("foo foo bar foo bar foobar barfoo foo foobar");
for (var w in count)
{
document.writeln(w + ": " + count[w]);
}
It's not that hard to follow. It takes each word from the list and filters the list based on that word. Then computes the length of that sub-list and using a well-known JS trick stores it in an associative array with the words being the key value.
In C# it might look like this:
var getWordFrequency = (string text)=> text.Split(' ')
.Select(w => { word=w, count = text.Split(' ').Count(t => t == w)});