Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

'Lifting' a C# function as a monoidal fails and changes signature

I’m trying to write a general monoidal pattern in C#, starting with a homogeneous function combining two non-null values, and returning either value if the other is null, or the combined value if neither is, or null. So I have this:

public static Func<TIn?, TIn?,TIn?> Drop2<TIn>(Func<TIn, TIn, TIn> f)
{
    return (lhs, rhs) =>
    {
        if (lhs == null && rhs == null)
        {
            return default;
        }

        if (lhs == null && rhs != null)
        {
            return rhs;
        }

        if (rhs == null && lhs != null)
        {
            return lhs;
        }

        return f(lhs, rhs);
    };
}

This looks fine and it even compiles, but when I try to use it, two odd things happen.

    Func<int, int, int> sum = (lhs, rhs) => lhs + rhs;

    var sumNonNull = DropNullable.Drop2(sum);

The Intellisense for sumNonNull shows as Func<int, int, int>?, not the expected Func<int?, int?, int?>, and I can’t pass in null as either argument for sumNonNull (can’t convert from int? to int).

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Should this work? What am I missing?

Thanks in advance for any help

>Solution :

I think you want something like this:

    public static Func<TIn?, TIn?, TIn?> Drop2<TIn>(Func<TIn?, TIn?, TIn?> f)
    {
        return (lhs, rhs) =>
              lhs is null ? rhs
            : rhs is null ? lhs
            : f(lhs, rhs);
    }

note TIn? in both input argument and the result (both of them can be null). Then you can use it as follow:

// note int? - sumInt accepts nulls (int? is a short for Nullable<int>)
Func<int?, int?, int?> sumInt = (a, b) => a + b;

Console.WriteLine(Drop2(sumInt)(null, 123));
Console.WriteLine(Drop2(sumInt)(456, null));
Console.WriteLine(Drop2(sumInt)(456, 123));
Console.WriteLine(Drop2(sumInt)(null, null));

// strings can be null
Func<string, string, string> sumStr = (a, b) => a + b;

Console.WriteLine(Drop2(sumStr)(null, "123"));
Console.WriteLine(Drop2(sumStr)("456", null));
Console.WriteLine(Drop2(sumStr)("456", "123"));
Console.WriteLine(Drop2(sumStr)(null, null));
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading