C# – Should Functions Taking Functions as Parameters Also Take Their Parameters?

Architecturecfunctional programming

I often find myself writing functions that look like this because they
allow me to easily mock data access, and still provide a signature that accepts parameters to determine what data to access.

public static string GetFormattedRate(
        Func<string, RateType>> getRate,
        string rateKey)
{
    var rate = getRate(rateKey);
    var formattedRate = rate.DollarsPerMonth.ToString("C0");
    return formattedRate;
}

Or

public static string GetFormattedRate(
        Func<RateType, string> formatRate,
        Func<string, RateType>> getRate,
        string rateKey)
{
    var rate = getRate(rateKey);
    var formattedRate = formatRate(rate);
    return formattedRate;
}

Then I use it something like this:

using FormatterModule;

public static Main()
{
    var getRate = GetRateFunc(connectionStr);
    var formattedRate = GetFormattedRate(getRate, rateType);
    // or alternatively
    var formattedRate = GetFormattedRate(getRate, FormatterModule.FormatRate, rateKey);

    System.PrintLn(formattedRate);
}

Is this a common practice? I feel like I should be doing something more like

public static string GetFormattedRate(
        Func<RateType> getRate())
{
    var rate = getRate();
    return rate.DollarsPerMonth.ToString("C0");
}

But that doesn't seem to work very well because I'd have to make a new function to pass into the method for every rate type.

Sometimes I feel like I should be doing

public static string GetFormattedRate(RateType rate)
{
   return rate.DollarsPerMonth.ToString("C0");
}

But that seems to take away any fetch and format re-usability. Whenever I want to fetch and format I have to write two lines, one to fetch and one to format.

What am I missing about functional programming? Is this the right way to do it, or is there a better pattern that's both easy to maintain and use?

Best Answer

If you do this long enough, you'll eventually find yourself writing this function over and over:

public static Type3 CombineFunc1AndFunc2(
    Func<Type1, Type2> func1,
    Func<Type2, Type3>> func2,
    Type1 input)
{
    return func2(func1(input))
}

Congratulations, you've invented function composition.

Wrapper functions like this don't have much use when they're specialized to one type. However, if you introduce some type variables and omit the input parameter, then your GetFormattedRate definition looks like this:

public static Func<A, C> Compose(
    Func<B, C> outer, Func<A, B>> inner)
{
    return (input) => outer(inner(input))
}

var GetFormattedRate = Compose(FormatRate, GetRate);
var formattedRate = GetFormattedRate(rateKey);

As it stands, what you're doing has little purpose. It's not generic, so you need to duplicate that code all over the place. It overcomplicates your code because now your code has to assemble everything it needs from a thousand tiny functions on its own. Your heart's in the right place though: you just need to get used to using these sorts of generic higher order functions to put things together. Or, use a good old fashion lambda to turn Func<A, B> and A into Func<B>.

Don't repeat yourself.

Related Topic