Reputation: 869
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
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