Reputation: 2103
I am trying to better understand functional Programming. The example below was provided, this example creates a predicate lambda. Then creates a static method to Count the number of items that pass the predicate conditions.
public Predicate<string> longWords = (x) => x.Length > 10;
public static int Count<T>(T[] array, Predicate<T> predicate, int counter)
{
for (int i = 0; i < array.Length; i++)
{
if (predicate(array[i]))
{
counter++;
}
}
return counter;
}
I wanted to make this solution follow the Referential Transparency
principle which states that you can determine the result of applying that function only by looking at the values of its arguments.
Unfortunately longWords
doesn't tell me what a long word really means, I need to pass in an argument to longWords
telling it the length that makes a function a long word, ie not hardcoding '10'.
Predicates
only take in one parameter, and making longWords
require Predicate<Tuple<string,int>>
, comes with its challenges.
Below is my attempt at coming to a solution, and the two error messages that resulted.
public class BaseFunctions
{
public Predicate<Tuple<string, int>> longWords = (x) => x.Item1.Length > x.Item2;
public static int Count<T>(T[] array, Predicate<T> predicate, int counter)
{
for (int i = 0; i < array.Length; i++)
{
/// error below: Cannot convert from 'T' to 'string'
/// in the example provided predicate(array[i]) worked fine when the predicate had only string type
if (predicate(new Tuple<string, int>(array[i], 10)))
{
counter++;
}
}
return counter;
}
}
and it's usage
BaseFunctions b = new BaseFunctions();
string[] text = ["This is a really long string", "Not 10"];
/// also error below on BaseFunctions.Count 'The type arguments for method BaseFunctions.Count<T>(T[], Predicate<T>, int) cannot be inferred from the usage. Try specifying the arguments explicitly
Console.WriteLine(BaseFunctions.Count(text, b.longWords, 0).ToString());
Console.ReadLine();
Upvotes: 3
Views: 5170
Reputation: 56473
I'd do:
public Func<string, int, bool> longWords = (str, number) => str.Length > number;
instead of:
public Predicate<Tuple<string, int>> longWords = (x) => x.Item1.Length > x.Item2;
This is simply because I believe it's easier to work with a function that takes a string
and an int
then returns a bool
as opposed to a predicate that takes a tuple of string
and int
and returns a bool
. plus this version of the tuple type is cumbersome to work with. consider the new tuple types if you're using C#7
and above.
Then change the method signature from:
public static int Count<T>(T[] array, Predicate<T> predicate, int counter)
to:
public static int Count<T>(T[] array, Func<T, int, bool> predicate, int counter)
To accommodate the change of delegate types mentioned above.
Then the if
condition needs to be changed from:
if (predicate(new Tuple<string, int>(array[i], 10)))
to:
if (predicate(array[i], 10))
To accommodate the change of delegate types mentioned above.
Also, note that in C#
you'll need to define the array like this:
string[] text = { "This is a really long string", "Not 10" };
and not with the [
]
braces.
Now your usage code becomes:
BaseFunctions b = new BaseFunctions();
string[] text = { "This is a really long string", "Not 10" };
Console.WriteLine(BaseFunctions.Count(text, b.longWords, 0).ToString());
Console.ReadLine();
Upvotes: 4