Is this functional code? Dr.T. Reply ….


 


This would be a functional approach:


CountWithPrevious : [‘a] => (a => a => bool) => int // type of the function
CountWithPrevious [] _                    = 0
CountWithPrevious [_]  _                  = 0
CountWithPrevious [prev, val | tail] pred = CountWithPrevious [val | tail] + (pred val prev ? 1 : 0)


Some observations:


  • _” is used as wildcard argument – matches any value that you don’t need a name for.

  • [ x,y,z | t ] are pattern matching over lists – here x,y and z get bound to the first elements and t is the rest of the list.

  • Both CountWithPrevious and the passed-in pred are curried – they take two arguments but one at a time.

  • The CountWithPrevious function is defined with pattern matching – at runtime it searches through the definitions until one matches.

  • The type declaration is optional – the compiler can figure out the type from the last case of the function.

In C# we don’t have pattern matching and currying, and so would probably need a helper function.

public static int CountWithPrevious<T>(IEnumerable<T> en, PredWithPrevious pred) {

IEnumerator<T> rest = en.GetEnumerator();

if (rest.MoveNext()) return Helper(rest.Current,rest,pred);

else return 0;

}

private static int Helper<T>(T prev, IEnumerator<T> rest, PredWithPrevious pred) {

if (rest.MoveNext()) {

T val = rest.Current;

return Helper(val,rest,pred) + (pred(val,prev) ? 1 : 0);

} else return 0;

}


We could simulate local functions with lambdas so that we don’t need to pass pred, prev and T along:

public static int CountWithPrevious<T>(IEnumerable<T> en, PredWithPrevious pred) {

IEnumerator<T> rest = en.GetEnumerator();

Func<T,int> helper = prev => {

if (rest.MoveNext()) {

T val = rest.Current;

return Helper(val) + (pred(val,prev) ? 1 : 0);

} else return 0;

};

if (rest.MoveNext()) return Helper(rest.Current);

else return 0;

}


Comments (1)

  1. Welcome to the twentieth Community Convergence. I’m Charlie Calvert, the C# Community PM, and this is