Let's say, I've the below logic. How to write that in Functional Programming?
public int doSomeCalc(int[] array)
{
int answer = 0;
if(array!=null)
{
for(int e: array)
{
answer += e;
if(answer == 10) break;
if(answer == 150) answer += 100;
}
}
return answer;
}
The examples in most blogs, articles… I see just explains the simple case of one straight forward math function say 'Sum'.
But, I have a logic similar to the above written in Java and would like to migrate that to functional code in Clojure.
If we can't do the above in FP, then the kind of promotions for FP doesn't state this explicitly.
I know that the above code is totally imperative. It was not written with the forethought of migrating it to FP in future.
Best Answer
The closest equivalent to looping over an array in most functional languages is a
fold
function, i.e. a function that calls a user-specified function for each value of the array, passing an accumulated value along the chain. In many functional languages,fold
is augmented by a variety of additional functions that provide extra features, including the option to stop early when some condition arises. In lazy languages (e.g. Haskell), stopping early can be achieved simply by not evaluating any further along the list, which will cause additional values to never be generated. Therefore, translating your example to Haskell, I would write it as:Breaking this down line by line in case you're not familiar with Haskell's syntax, this works like this:
Defines the type of the function, accepting a list of ints and returning a single int.
The main body of the function: given argument
values
, returnfoldr1
called with argumentscombine
(which we'll define below) andvalues
.foldr1
is a variant of the fold primitive that starts with the accumulator set to the first value of the list (hence the1
in the function name), then combines it using the user specified function from left to right (which is usually called a right fold, hence ther
in the function name). Sofoldr1 f [1,2,3]
is equivalent tof 1 (f 2 3)
(orf(1,f(2,3))
in more conventional C-like syntax).Defining the
combine
local function: it receives two arguments,v1
andv2
. Whenv1
is 10, it just returnsv1
. In this case, v2 is never evaluated, so the loop stops here.Alternatively, when v1 is 150, adds an extra 100 to it, and adds v2.
And, if neither of those conditions is true, just adds v1 to v2.
Now, this solution is somewhat specific to Haskell, because the fact that a right fold terminates if the combining function doesn't evaluate its second argument is caused by Haskell's lazy evaluation strategy. I don't know Clojure, but I believe it uses strict evaluation, so I would expect it to have a
fold
function in its standard library that includes specific support for early termination. This is often calledfoldWhile
,foldUntil
or similar.A quick look at the Clojure library documentation suggests that it is a little different from most functional languages in naming, and that
fold
isn't what you're looking for (it's a more advanced mechanism aimed at enabling parallel computation) butreduce
is the more direct equivalent. Early termination occurs if thereduced
function is called within your combining function. I'm not 100% sure I understand the syntax, but I suspect what you're looking for is something like this:NB: both translations, Haskell and Clojure, are not quite right for this specific code; but they convey the general gist of it -- see discussion in the comments below for specific problems with these examples.