Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intended usage when calling method that itself return a OneOf<T> #145

Open
BADF00D opened this issue Mar 29, 2023 · 2 comments
Open

Intended usage when calling method that itself return a OneOf<T> #145

BADF00D opened this issue Mar 29, 2023 · 2 comments

Comments

@BADF00D
Copy link

BADF00D commented Mar 29, 2023

I'm new to this library and not quite sure if I use it the right way.

Imagine I want to write a little Parser, that returns a record of type Result. Each property is parsed by invoking a method that can parse this property or returns an exception. How would I write the Parse method, that collects the values from the methods?

My current solution looks like the following:

public record Result(string Name, int Age, Guid Id);
public class Parser
{
    public OneOf<Result, Exception> Parse()
    {
        return GetName()
            .Match(name => GetAge()
                .Match(age => GetId()
                    .Match(
                        id => OneOf<Result, Exception>.FromT0(new Result(name, age, id)), 
                        e => e), 
                    e => e), 
                e => e);
    }

    private OneOf<string, Exception> GetName()  => "Value1";
    private OneOf<int, Exception> GetAge() => 123;
    private OneOf<Guid, Exception> GetId() => Guid.NewGuid();
}

Is there a better, more readable way to write the Parse method?

@ghostnguyen
Copy link

ghostnguyen commented Apr 19, 2023

You can try the Bind ext method.

public record Result(string Name, int Age, Guid Id);

public class Parser
{
    public OneOf<Result, Exception> Parse()
    {
        return GetName()
            .Combind(GetAge())
            .Combind2(GetId())
            .MapT0(_ => new Result(_.Item1, _.Item2, _.Item3));
    }

    private OneOf<string, Exception> GetName() => "Value1";

    private OneOf<int, Exception> GetAge() => 123;

    private OneOf<Guid, Exception> GetId() => Guid.NewGuid();
}

public static class Ext
{
    public static OneOf<(T1, T2), E> Combind<T1, T2, E>(this OneOf<T1, E> opt1, OneOf<T2, E> opt2)
        => opt1.Match(
            t1 => opt2.Match(
                t2 => OneOf<(T1, T2), E>.FromT0((t1, t2)),
                e => e
                ),
            e => e
            );

    public static OneOf<(T1, T2, T3), E> Combind2<T1, T2, T3, E>(this OneOf<(T1, T2), E> opt1, OneOf<T3, E> opt2)
        => opt1.Combind(opt2).MapT0(_ => (_.Item1.Item1, _.Item1.Item2, _.Item2));
}

@emperador-ming
Copy link

emperador-ming commented Jun 11, 2023

Is there a better, more readable way to write the Parse method?

@BADF00D, enter the monad!

#r "nuget: OneOf, 3.0.243"

using OneOf;

public class Parser
{
    public OneOf<Result, Exception> Parse() =>
        GetName()
            .AsBindable()
            .Bind(name => new Result(name).AsBindable())
            .Bind(result => GetAge().AsBindable().Bind(age => (result with { Age = age }).AsBindable()))
            .Bind(result => GetId().AsBindable().Bind(id => (result with { Id = id }).AsBindable()))
            .Result();

    private OneOf<string, Exception> GetName()  => "Value1";
    private OneOf<int, Exception> GetAge() => 123;
    private OneOf<Guid, Exception> GetId() => Guid.NewGuid();
}

// Monad
public class Maybe<TA> where TA: notnull
{
    private OneOf<TA, Exception> value;
    
    private Maybe(Exception ex) => value = ex;
    
    public Maybe(TA someValue) => value = someValue;
    
    public Maybe(OneOf<TA, Exception> value) => this.value = value;
    
    public Maybe<TB> Bind<TB>(Func<TA, Maybe<TB>> f) where TB : notnull
        => value.Match(
                taValue => f(taValue),
                ex => Maybe<TB>.Exception(ex));

    public static Maybe<TA> Exception(Exception ex) => new Maybe<TA>(ex);
    public OneOf<TA, Exception> Result() => value;
}

// Extension methods
public static Maybe<TA> AsBindable<TA>(this TA value) where TA : notnull
    => new Maybe<TA>(value);

public static Maybe<TA> AsBindable<TA>(this OneOf<TA, Exception> oneof) where TA : notnull
    => new Maybe<TA>(oneof);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants