10月30日
I found this interview/debate with Mads Torgersen (C# guy), Joe Armstrong (Erlang guy) and Erik Meijer (Haskell guy) very entertaining!
It's a classic debate. I remember hearing it in the 25-year-old SICP lectures in which Hal Abelson said,
“Generally, I think what you're seeing is that we're running across what I think's a very basic problem in Computer Science; which is how to define languages that somehow can talk about delayed evaluation but also be able to reflect this view that there are objects in the world. How do we somehow get both? I think that's a very hard problem and it may be that it's a very hard problem that has nothing to do with Computer Science. It really is a problem with having two very incompatible ways of looking at the world.”
But hey, before you start thinking that Erlang must be the answer to all the world’s problems
, you should read this post showing how to do the same message passing style w/async workflows and MailboxProcessor in F#: http://strangelights.com/blog/archive/2007/10/24/1601.aspx
10月24日
I just did a little Functional Programming brownbag talk today. One example that went over pretty well was this:
double CheapGasNearby(IEnumerable<GasResult> results)
{
double min = double.MaxValue;
foreach (GasResult r in results) {
if (r.Distance < 5.0) {
double price = r.Price;
if (r.Name == "Safeway")
price *= 0.9;
if (price < min)
min = price;
} }
return min;
}
This works to find the minimum price for gas within 5 miles; taking into account a 10% Safeway discount. Ahhh! Mutation and mixing of intent all over the place!
Let’s see if we can, most importantly, separate out the intentions and also get rid of the use of assignment:
double CheapGasNearby(IEnumerable<GasResult> results)
{
double min = double.MaxValue;
foreach (GasResult r in results) {
if (r.Distance < 5.0) {
double price = r.Price;
if (r.Name == "Safeway")
price *= 0.9;
if (price < min)
min = price;
} }
return min;
}
Examining the code in red, you notice that it's essentially doing a map (just converting a collection of GapResults to adjusted doubles), and the green is a reduce operation (threading the min accumulator throughout the iteration) and the purple is obviously a filter. This can be rewritten in a much more straightforward way using the functional extension methods hanging off of IEnumerable in .NET 3.5+:
double CheapGasNearby(IEnumerable<GasResult> results)
{
return results
.Where(r => r.Distance < 5.0)
.Select(r => r.Price * (r.Name == "Safeway" ? 0.9 : 1.0))
.Aggregate(double.MaxValue, (m, p) => p < m ? p : m));
}
Of course there’s already a Min() method available and additionally it’s even more succinct using LINQ keywords:
double CheapGasNearby(IEnumerable<GasResult> results)
{
return (from r in results
where r.Distance < 5.0
select r.Price * (r.Name == "Safeway" ? 0.9 : 1.0)
).Min()
}
Why would we ever want to write it in the "mini-Rube Goldberg machine" imperative style?
Here's the brownbag deck if you're interested...