Mike Harris
Mike Harris

Reputation: 869

Trouble Implementing Apply for Either in C#

I am working through Functional Programming in C# by Enrico Buonanno

How would I implementing Apply for the Either monad in C#? I tried the follow which does not type check:

using System;
using Xunit;
using LaYumba.Functional;
using static LaYumba.Functional.F;

namespace ch8
{
    public class UnitTest1
    {
        [Fact]
        public void Ex1()
        {
            Func<int, int, int> add = (x, y) => x + y;

            var option = Some(add)
              .Apply(3)
              .Apply(2);

            Assert.Equal(Some(5), option);

            var either = Left(add)
              .Apply(3) // does not type check
              .Apply(2);

            Assert.Equal(Left(5), either);
        }
    }

    public static class Ext
    {
        public static Either<L, R> Apply<L, R>(
            this Either<L, Func<R, R>> source, Either<L, R> target)
          => source.Match(
              l => Left(l),
              f => target.Match<Either<L, R>>(
                  l => Left(l),
                  r => Right(f(r))
              ));
    }
}

I get the following error:

watch : Started
Build started, please wait...
UnitTest1.cs(22,16): error CS1061: 'Either.Left<Func<int, int, int>>' does not contain a definition for 'Apply' and no extension method 'Apply' accepting afirst argument of type 'Either.Left<Func<int, int, int>>' could be found (are you missing a using directive or an assembly reference?) [/ch8/ch8/ch8.csproj]
UnitTest1.cs(25,26): error CS1503: Argument 1: cannot convert from 'LaYumba.Functional.Either.Left<int>' to 'string' [/ch8/ch8/ch8.csproj]
UnitTest1.cs(25,35): error CS1503: Argument 2: cannot convert from 'LaYumba.Functional.Either<L, R>' to 'string' [/ch8/ch8/ch8.csproj]
watch : Exited with error code 1
watch : Waiting for a file to change before restarting dotnet...

What am I doing wrong?

Upvotes: 1

Views: 790

Answers (1)

louthster
louthster

Reputation: 1652

I'm the technical proofer for the book, so if there are any bugs in there, it's my fault :) A lot of what's in the book is based on my library language-ext and obviously functional programming technique in general. There's a fully fledged Either implementation there if you need it.

However, for your example, you almost certainly (can't check at the moment, I'm on a train) should be using Right(add) rather than Left(add) as Right is the success route, and Left is the fail route.

And you should therefore be asserting that the result is equal to Right(5)

It's been a while since I've looked at the book, but I am assuming that Left returns Either.Left<L> which doesn't have the same API as the 'success' route.

If you cast Left(add) to Either<L, R> then you'd find that the library opens up.

The Left and Right constructor functions have to deal with the fact that Either needs two types. So they're creating intermediate values of Left<L> or Right<R> before implicitly casting to Either<L, R> - this will often save you from having to write Left<L, R>(l) and Right<L, R>(r), but sometimes the types trip over themselves.

Anyway, when I have a debugger to hand I'll take a closer look

Upvotes: 2

Related Questions