Convert loop to Maybe monad

203 views Asked by At

Recently I tried applying Maybe monad pattern in my C# code using this library.

What I found difficult to grasp was converting such a function into Maybe paradigm:

public Maybe<object> DoSomething(IReader reader)
{
    while (true)
    {
        var result = reader.Read();
        if (result == null) return Maybe<object>.Nothing;
        if (result.HasValue) return new Maybe<object>(null);
    }
}

I would like to have it written using from x in X form. The functionality that stands behind this function is to read IReader until it returns a value (Maybe has a value) or an error occurs (null gets returned).

1

There are 1 answers

0
Random Dev On BEST ANSWER

the answer to your comment/question is: you don't - yeah you could try it using recursive calls but this might fail horrible in C# and you are way better of with the while

from x in X is just the monadic - bind (it get's translated into the SelectMany functions) and there is just no direct way in the LINQ syntax for this.

But you can write your own function like this:

public tValue DoUntilSome<tValue>(Func<Maybe<tValue>> f)
{
    while (true)
    {
        var x = f();
        if (x.HasValue) return x.Value;
    }
}

and call like (see below)

var result = DoUntilSome(() => TryRead(reader));

remarks

first the Maybe<object> (object) part is a smell - because you most certainly want a concrete type in there instead of the generic object

Then new Maybe<object>(null) is very strange too

I would have suggested something like:

public Maybe<tValue> TryRead<tValue>(IReader reader)
{
    var result = reader.Read();
    if (result == null || !result.HasValue) 
        return Maybe<tValue>.Nothing;
    return new Maybe<tValue>((tValue)reader.Value);
}

then of course this part is there to get some Maybe value - the thing you are trying to do with from x in X is the monadic-bind - which you can only use once you have a Maybe to start with:

from value in TryRead<tValue>(reader)
from other in TrySomethingDifferent(value) // here is the bind
select .... 

disclaimer

I did not compile any of this (because I was to lazy to download the github project and stuff) - put you should be able to easily solve any syntax errors that might hide there - sorry for that

In case you have major troubles just leave a comment