Sometimes imperative is so much easier
Take a look at the following Erlang function:
count_promises(Id, N, {_, PromisesQueue}) -> rec_count_promises(0, Id, N, PromisesQueue). rec_count_promises(Count, _, _, []) -> Count; rec_count_promises(Count, Id, N, [{Id, N, _, _} | RestQueue]) -> rec_count_promises((Count + 1), Id, N, RestQueue); rec_count_promises(Count, Id, N, [_ | RestQueue]) -> rec_count_promises(Count, Id, N, RestQueue).
I am reading a codebase full of this sort of things, and it is really painful. I keep thinking back to how I would do it in C#:
public int CountPromises(int id, int n, Tuple<List<Record>, List<Record>> phase1) { int count=0; foreach(var record in phase1.Item2) { if(record.Id == id && record.N == n) count ++; } return count ; }
Yet that is imperative, and involve mutating state. I agree, it is a huge improvement, but it can be made both functionally safe and easier to read:
phase1.Items2.Count(record => record.Id == id && record.N == n);
As I said, I am currently going through a codebase full of these sort of functions, and it is painful, annoying and irritating. I am not experienced enough with Erlang to be able to tell conclusively if this is idiomatic Erlang code, but I think so.
Comments
Did the Erlang code come from couchdb?
If so, I would be curious to know what benefit there is in rewriting couchdb on another platform?
Writing out the recursion and pattern matching for this function sure feels like a waste of time.
It seems to me that the Erlang code should be re-factored to make use of higher level functions, like "filter".
Paul,
No, libpaxos
Yeah it's hard to see how this can can be more readable in anyone's mind. I'm aware the mathematical mind works differently and prefers the purity of functional programming without side-effects but does it work this different?
IMHO readability of code is just as important as succinctness, i.e. there's no point having really tight code with low signal/noise ratio if it takes others longer to scan and understand a page of code.
This is horrible functional programming style. I'm not a Erlang wizard, so this is how I would write the function in Haskell:
countPromises id n = length . filter ((id', n') -> id' == id && n' == n) . snd
Much better! If you want it to look like C# you can also define:
count p = length . filter p
countPromises id n = count ((id', n') -> id' == id && n' == n) . snd
If you use GHC, all the intermediate lists wil be fused away, so this will actually compile into the tight imperative loop you wrote above.
This cannot be idiomatic erlang code because it would mean that most erlang programmers are not very smart. That is hard to believe.
Oh. I thought you said "idiotic" Erlang code.
I think yes, it is.
count_promises(Id, N, {_, PromisesQueue}) ->
lists:foldr(fun(X,ACC) -> {I,NN,_,_} = X, if I==Id , NN==N -> ACC+1; true -> ACC end end , 0, PromisesQueue).
Probably no comments in the mess either.
count_promises(Id, N, {_, PromisesQueue}) ->
length(lists:filter(fun(X, Y, _, _}) -> X =:= Id andalso Y =:= N end, PromisesQueue)).
Doesnt look idiomatic functional programming at all, it looks like a mechanical conversion of an imperative loop with mutating state to a recursive function call with accumulators. Which is basic functional programming 101, but in general once the user learns that they can do this relieably, they then move on to composing simple functions over lists to accomplish the same goal. Not sure its possible that maybe there is some performance gain in the erlang implementation if you feel this was programmed by advanced functional programmers. A lot of times when performance is taken into account, an advanced programmer has to strip out all the nice functional patterns and put in some worst of both worlds imperative/functional chimera
Comment preview