Language-ext: Chaining methods - Breaking out when first method provides a Some(x)

Created on 6 Oct 2018  路  5Comments  路  Source: louthy/language-ext

First, I love this library. I'm learning so much about FP and this library has helped me a ton!

Question: How do I take the imperative logic below and make it FP using the library?

Problem - Get the first Some value from a chain of delegates that call external sources or provide a default value

I was reading your wiki page on Function Signatures. You stated it is best to stay in context and use Match as a last resort when you need to get to the bound values. I'm trying to figure out the best way to build a pipeline and stay in context _(I assume this means that evaluation stays lazy and at the end of the pipeline, I end up with something monadic over T)_.

Requirements

  • Chain of external sources will return an Option<string>.
  • All external calls should catch exceptions, write them to our telemetry client through an Action<Exception> delegate. and return an Option<string>.None.
  • At the end of the chain of external calls, if the current result is still None then return a default value provided by a Func<string> getDefaultValue = () => {...} delegate.
  • Keep everything lazy. No delegates should be called unless they are needed.

    • Even better if we could memoize some calls but not others.

      Example - Imperative


static readonly Action<Exception> WriteExceptionsToTelemetryClient = (Exception ex) => {...};
static Option<string> HandleDelegatesToExternalSources(Func<string> GetStringFromExternalSource)
{
    Option<string> result;
    try
    {
        result = GetStringFromExternalSource();
    }
    catch (Exception ex)
    {
        WriteExceptionsToTelemetryClient(ex);
        result = Option<string>.None;
    }
    return result;
}

static readonly Func<string> GetStringFromFirstExternalSource = () =>  throw new Exception();
static readonly Func<string> GetStringFromSecondExternalSource = () => null;
static readonly Func<Some<string>> GetStringFromSourceThatDoesntThrowExceptions = () => LanguageExt.Some.Create<string>("foo");

// Function signature indicates that caller gets an Option in Some state. Returning None is not an option.
static Some<string> GetString()
{
    Option<string> result;

    // First external source
    result = HandleDelegatesToExternalSources(GetStringFromFirstExternalSource);
    if (result.IsSome) return new Some<string>(result);

    // Second external source
    result = HandleDelegatesToExternalSources(GetStringFromSecondExternalSource);
    if (result.IsSome) return new Some<string>(result);

    // Default value
    return GetStringFromSourceThatDoesntThrowExceptions();
}

The result of calling GetString() is Some<string>("foo"). Also the Telemetry Client wrote an exception.

examples / documentation

Most helpful comment

Can you explain what you mean by "global" fields

Essentially lots of public static fields or properties. It will create a messy set of dependencies that will be hard to reason about and maintain. For example if I have a function prototype like this:
```c#
int Divide(int x, int y);

It should do nothing other than divide two numbers.  If behind the scenes it fires off calls to various global services then it hides what's really going on, that approach over time makes code brittle and hard to deal with.

Now imagine this:
```c#
   int Divide(int x, int y, Func<Exception, Unit> telemetry);

It's obvious to all users of your code that it may do something more than add two numbers together.

The problem with that approach is that there are still possible side-effects happening during the function. Which may have performance implications, race condition implications, or just _extra argument to every function_ implications.

So, we could change Divide to not do any telemetry at all, and just return the result or the error:

```c#
Either Divide(int x, int y);

Now, that talks to me.  The function should have no external dependencies other than the arguments being passed, but the result could be either an `Exception` or an `int`.  Obviously the exception could come from divide-by-zero, and so now you can imagine what the function might look like:
```c#
    Either<Exception, int> Divide(int x, int y) => 
        Try(() => x / y).ToEither();

We now have a _declarative_ and _pure_ function.

So, what happens with the Exception, when does it get logged?

Let's imagine we had a small API that was _declarative_ and _pure_ like the Divide function:
```c#
public class Error : NewType
{
public Error(string value) : base(value) { }
public static Error FromEx(Exception e) => new Error(e.Message);
}

Either Div(int x, int y) =>
Try(() => x / y).ToEither(Error.FromEx);

Either FromString(string value) =>
parseInt(value).ToEither(Error.New("String can't be parsed into an integer"));

Either Div(string left, string right) =>
from l in FromString(left)
from r in FromString(right)
from n in Div(l, r)
select n;

Either Add(string left, string right) =>
from l in FromString(left)
from r in FromString(right)
select l + r;

Either Sub(string left, string right) =>
from l in FromString(left)
from r in FromString(right)
select l - r;

Either Mul(string left, string right) =>
from l in FromString(left)
from r in FromString(right)
select l * r;

Either Foo() =>
from x in Div("48", "2")
from y in Add("10", "12")
from z in Sub("5", "3")
select x + y + z;

Notice how the `Error` type propagates, and function `Foo` which is using other possible error throwing functions is relatively more complex.  You can maintain this right up to the 'edges' of your application.  i.e. away from your pure code.  That means if something goes wrong, the expression backs out and then you `Match` on failure and call your telemetry providers there.  No need for injection.

That works well if you never recover from failure.  In your example you try to return a default value if the others fail (I'd argue this isn't always great practice, it can make much more sense to propagate the error, but it really does depend on the use-case).  But if you do need call IO functionality mid-way through an expression then there are a number of routes to achieve this.  

### Reader monad

This is a built in type in lang-ext that allows you to pass an _environment_ to your computations.  It isn't always the easiest thing to use, but it is effective in that you can gain access to telemetry without having to explicitly pass an extra argument:

First, you create a type to pass in as the telemetry:
```c#
public class World
{
    public readonly Func<string, Unit> SendTelemetry;

    public World(Func<string, Unit> sendTelemetry)
    {
        SendTelemetry = sendTelemetry;
    }
}

Then we'll add a couple of extension methods that work with Reader<World, A>. Writing bespoke extensions for your environment type tends to make it easier to work with. These will convert between Try<A>, Option<A> to Reader<World, A>:
```c#
public static Reader ToReader(this Try ma) => env =>
ma.Match(
Succ: x => (x, false),
Fail: ex =>
{
env.SendTelemetry(ex.ToString());
return (default(A), true);
});

    public static Reader<World, A> ToReader<A>(this Option<A> ma, string message) => env =>
        ma.Match(
            Some: x  => (x, false),
            None: () =>
            {
                env.SendTelemetry(message);
                return (default(A), true);
            });
Notice the `Try<A>` variant will send the telemetry if there's an exception caught.

If the returning of `(x, false)` and ` (default(A), true)` looks wierd.  Take a look at the declaration of `Reader`:

```c#
namespace LanguageExt
{
    public delegate (A Value, bool IsFaulted) Reader<Env, A>(Env env);
}

It's just a delegate that takes an Env and returns (A, bool) the bool indicates whether it's faulted or not.

Before we use the Reader in anger, we can add a helper function to send random telemetry whenever we want:
```c#
public static Reader SendTelemetry(string message) =>
from world in ask()
let _ = world.SendTelemetry(message)
select _;

Notice how the function only takes a `string`, but somehow returns a `Reader<World, Unit>`.  That's because of the `ask<World>()` call.  Which goes and gets the environment for you and puts it in `world`.  We can then invoke the injected `Func` to deliver the message.

Now we can use for real:

```c#
static Reader<World, int> Div(int x, int y) =>
    Try(() => x / y).ToReader();

static Reader<World, int> FromString(string value) =>
    parseInt(value).ToReader("String can't be parsed into an integer");

static Reader<World, int> Div(string left, string right) =>
    from l in FromString(left)
    from r in FromString(right)
    from n in Div(l, r)
    from _ in SendTelemetry($"Result of {left} / {right} = {n}")
    select n;

static Reader<World, int> Add(string left, string right) =>
    from l in FromString(left)
    from r in FromString(right)
    from _ in SendTelemetry($"Result of {left} + {right} = {l + r}")
    select l + r;

static Reader<World, int> Sub(string left, string right) =>
    from l in FromString(left)
    from r in FromString(right)
    from _ in SendTelemetry($"Result of {left} - {right} = {l - r}")
    select l - r;

static Reader<World, int> Mul(string left, string right) =>
    from l in FromString(left)
    from r in FromString(right)
    from _ in SendTelemetry($"Result of {left} - {right} = {l * r}")
    select l * r;

Notice the calls to SendTelemetry.

Writer monad

Obviously that still calls the telemetry during the computation. So, another approach is to use a Writer<Exception, A> monad to collect telemetry and then dump it all in one go when you're done. Instead of using ask to get the environment, you call tell(exception) to log your output.

Roll your own

Another approach is to build your own monadic type. That might be a bit out of your reach at the moment if you're just getting started, but once you know how to write a Bind function the rest is trivial.

For example if we create a lightweight Maybe monad (which works like the Option monad):
```c#
public class Maybe

{
public static Maybe
Just(A value) => new Just(value);
public readonly static Maybe
Nothing = new Nothing();
}

public class Just<A> : Maybe<A>
{
    public readonly A Value;
    public Just(A value)
    {
        Value = value;
    }
}

public class Nothing<A> : Maybe<A>
{
    public Nothing()
    {
    }
}
The `Bind` function would look like this:
```c#
    public static class MaybeExtensions
    {
        public static Maybe<B> Bind<A, B>(this Maybe<A> ma, Func<A, Maybe<B>> f) =>
            ma is Just<A> just
                ? f(just.Value)
                : Maybe<B>.Nothing;
    }

It encapsulates the rules of the monad (i.e. don't run anything else if we get a Nothing).

Once the Bind is written, the extensions to make it work with LINQ is almost cut n paste:
```c#
public static Maybe Select(this Maybe
ma, Func f) =>
ma.Bind(x => Maybe.Just(f(x)));

    public static Maybe<B> SelectMany<A, B>(this Maybe<A> ma, Func<A, Maybe<B>> f) =>
        ma.Bind(f);

    public static Maybe<C> SelectMany<A, B, C>(this Maybe<A> ma, Func<A, Maybe<B>> bind, Func<A, B, C> project) =>
        ma.Bind(a => bind(a).Select(b => project(a, b)));

`` Just changeMaybe` to the name of your monad and it will work for anything.

The point of this is that you can relatively easily roll your own monadic types, which carry injected functionality and are less cumbersome than Reader or Writer; and easily allow you to change what you do with IO or any external dependencies.

Free monad

And the final, most pure method, is the Free monad approach. This creates true separation between the pure and IO code. I've written about this in depth before and there are two samples in the Samples folders that use this approach.

It is very powerful, but requires a reasonable amount of typing, however it's a reeeeally powerful technique.

All 5 comments

I'd do something like this:

```c#
using LanguageExt;
using static LanguageExt.Prelude;
using System;

namespace ConsoleApp11
{
public static class Telemetry
{
public static readonly Action Client = (Exception ex) =>
{
Console.WriteLine(ex.Message);
};
}

public static class TryExtensions
{
    public static Try<A> LogFailures<A>(this Try<A> ma) =>
        ma.Match(
            Succ: x => Try(x),
            Fail: ex =>
            {
                Telemetry.Client(ex);
                return Try<A>(ex);
            });
}

class Program
{
    static readonly Func<string> GetStringFromFirstExternalSource = () => throw new Exception();
    static readonly Func<string> GetStringFromSecondExternalSource = () => null;
    static readonly Func<string> GetStringFromSourceThatDoesntThrowExceptions = () => LanguageExt.Some.Create<string>("foo");

    static string GetStringOrDefault() =>
       GetString().IfNone(GetStringFromSourceThatDoesntThrowExceptions());

    static Option<string> GetString() =>
        Get(Seq(GetStringFromFirstExternalSource, GetStringFromSecondExternalSource));

    static Option<A> Get<A>(Seq<Func<A>> delegates) =>
        delegates.FoldWhile(
            Option<A>.None,
            (state, fun) => Try(fun).LogFailures().ToOption(),
            (state) => state.IsNone);
}

}
```

Personally I wouldn't bother so much with the Some<A> type, mostly because now that I always use Option for optional values, when I see a reference type that isn't an Option then I know it should never be null. This does require a certain amount of team discipline obviously.

You'll notice I created an extension method for Try<A> for logging, this is only required if you don't use the built in error-logger in TryConfig, and instead you want to make a decision on a case-by-case basis whether you want to log or not.

I have split the GetString method up into a more general Get and then less general GetString, and GetStringOrDefault method. This makes each function much simpler and easier to reason about.

One thing I'd warn against is the path you appear to be going down of creating lots of 'global' fields. That's going to get you in to trouble quite quickly. Consider either passing external IO functions through to the functions, or trying to move IO to the edges, or build your own monadic types to capture IO operations.

Pure functions are your best friend, and that's where you'll get the most wins from taking a functional approach.

Thanks! Can you explain what you mean by "global" fields? I've been struggling with how to handle connections, clients, telemetry, etc.

Can you explain what you mean by "global" fields

Essentially lots of public static fields or properties. It will create a messy set of dependencies that will be hard to reason about and maintain. For example if I have a function prototype like this:
```c#
int Divide(int x, int y);

It should do nothing other than divide two numbers.  If behind the scenes it fires off calls to various global services then it hides what's really going on, that approach over time makes code brittle and hard to deal with.

Now imagine this:
```c#
   int Divide(int x, int y, Func<Exception, Unit> telemetry);

It's obvious to all users of your code that it may do something more than add two numbers together.

The problem with that approach is that there are still possible side-effects happening during the function. Which may have performance implications, race condition implications, or just _extra argument to every function_ implications.

So, we could change Divide to not do any telemetry at all, and just return the result or the error:

```c#
Either Divide(int x, int y);

Now, that talks to me.  The function should have no external dependencies other than the arguments being passed, but the result could be either an `Exception` or an `int`.  Obviously the exception could come from divide-by-zero, and so now you can imagine what the function might look like:
```c#
    Either<Exception, int> Divide(int x, int y) => 
        Try(() => x / y).ToEither();

We now have a _declarative_ and _pure_ function.

So, what happens with the Exception, when does it get logged?

Let's imagine we had a small API that was _declarative_ and _pure_ like the Divide function:
```c#
public class Error : NewType
{
public Error(string value) : base(value) { }
public static Error FromEx(Exception e) => new Error(e.Message);
}

Either Div(int x, int y) =>
Try(() => x / y).ToEither(Error.FromEx);

Either FromString(string value) =>
parseInt(value).ToEither(Error.New("String can't be parsed into an integer"));

Either Div(string left, string right) =>
from l in FromString(left)
from r in FromString(right)
from n in Div(l, r)
select n;

Either Add(string left, string right) =>
from l in FromString(left)
from r in FromString(right)
select l + r;

Either Sub(string left, string right) =>
from l in FromString(left)
from r in FromString(right)
select l - r;

Either Mul(string left, string right) =>
from l in FromString(left)
from r in FromString(right)
select l * r;

Either Foo() =>
from x in Div("48", "2")
from y in Add("10", "12")
from z in Sub("5", "3")
select x + y + z;

Notice how the `Error` type propagates, and function `Foo` which is using other possible error throwing functions is relatively more complex.  You can maintain this right up to the 'edges' of your application.  i.e. away from your pure code.  That means if something goes wrong, the expression backs out and then you `Match` on failure and call your telemetry providers there.  No need for injection.

That works well if you never recover from failure.  In your example you try to return a default value if the others fail (I'd argue this isn't always great practice, it can make much more sense to propagate the error, but it really does depend on the use-case).  But if you do need call IO functionality mid-way through an expression then there are a number of routes to achieve this.  

### Reader monad

This is a built in type in lang-ext that allows you to pass an _environment_ to your computations.  It isn't always the easiest thing to use, but it is effective in that you can gain access to telemetry without having to explicitly pass an extra argument:

First, you create a type to pass in as the telemetry:
```c#
public class World
{
    public readonly Func<string, Unit> SendTelemetry;

    public World(Func<string, Unit> sendTelemetry)
    {
        SendTelemetry = sendTelemetry;
    }
}

Then we'll add a couple of extension methods that work with Reader<World, A>. Writing bespoke extensions for your environment type tends to make it easier to work with. These will convert between Try<A>, Option<A> to Reader<World, A>:
```c#
public static Reader ToReader(this Try ma) => env =>
ma.Match(
Succ: x => (x, false),
Fail: ex =>
{
env.SendTelemetry(ex.ToString());
return (default(A), true);
});

    public static Reader<World, A> ToReader<A>(this Option<A> ma, string message) => env =>
        ma.Match(
            Some: x  => (x, false),
            None: () =>
            {
                env.SendTelemetry(message);
                return (default(A), true);
            });
Notice the `Try<A>` variant will send the telemetry if there's an exception caught.

If the returning of `(x, false)` and ` (default(A), true)` looks wierd.  Take a look at the declaration of `Reader`:

```c#
namespace LanguageExt
{
    public delegate (A Value, bool IsFaulted) Reader<Env, A>(Env env);
}

It's just a delegate that takes an Env and returns (A, bool) the bool indicates whether it's faulted or not.

Before we use the Reader in anger, we can add a helper function to send random telemetry whenever we want:
```c#
public static Reader SendTelemetry(string message) =>
from world in ask()
let _ = world.SendTelemetry(message)
select _;

Notice how the function only takes a `string`, but somehow returns a `Reader<World, Unit>`.  That's because of the `ask<World>()` call.  Which goes and gets the environment for you and puts it in `world`.  We can then invoke the injected `Func` to deliver the message.

Now we can use for real:

```c#
static Reader<World, int> Div(int x, int y) =>
    Try(() => x / y).ToReader();

static Reader<World, int> FromString(string value) =>
    parseInt(value).ToReader("String can't be parsed into an integer");

static Reader<World, int> Div(string left, string right) =>
    from l in FromString(left)
    from r in FromString(right)
    from n in Div(l, r)
    from _ in SendTelemetry($"Result of {left} / {right} = {n}")
    select n;

static Reader<World, int> Add(string left, string right) =>
    from l in FromString(left)
    from r in FromString(right)
    from _ in SendTelemetry($"Result of {left} + {right} = {l + r}")
    select l + r;

static Reader<World, int> Sub(string left, string right) =>
    from l in FromString(left)
    from r in FromString(right)
    from _ in SendTelemetry($"Result of {left} - {right} = {l - r}")
    select l - r;

static Reader<World, int> Mul(string left, string right) =>
    from l in FromString(left)
    from r in FromString(right)
    from _ in SendTelemetry($"Result of {left} - {right} = {l * r}")
    select l * r;

Notice the calls to SendTelemetry.

Writer monad

Obviously that still calls the telemetry during the computation. So, another approach is to use a Writer<Exception, A> monad to collect telemetry and then dump it all in one go when you're done. Instead of using ask to get the environment, you call tell(exception) to log your output.

Roll your own

Another approach is to build your own monadic type. That might be a bit out of your reach at the moment if you're just getting started, but once you know how to write a Bind function the rest is trivial.

For example if we create a lightweight Maybe monad (which works like the Option monad):
```c#
public class Maybe

{
public static Maybe
Just(A value) => new Just(value);
public readonly static Maybe
Nothing = new Nothing();
}

public class Just<A> : Maybe<A>
{
    public readonly A Value;
    public Just(A value)
    {
        Value = value;
    }
}

public class Nothing<A> : Maybe<A>
{
    public Nothing()
    {
    }
}
The `Bind` function would look like this:
```c#
    public static class MaybeExtensions
    {
        public static Maybe<B> Bind<A, B>(this Maybe<A> ma, Func<A, Maybe<B>> f) =>
            ma is Just<A> just
                ? f(just.Value)
                : Maybe<B>.Nothing;
    }

It encapsulates the rules of the monad (i.e. don't run anything else if we get a Nothing).

Once the Bind is written, the extensions to make it work with LINQ is almost cut n paste:
```c#
public static Maybe Select(this Maybe
ma, Func f) =>
ma.Bind(x => Maybe.Just(f(x)));

    public static Maybe<B> SelectMany<A, B>(this Maybe<A> ma, Func<A, Maybe<B>> f) =>
        ma.Bind(f);

    public static Maybe<C> SelectMany<A, B, C>(this Maybe<A> ma, Func<A, Maybe<B>> bind, Func<A, B, C> project) =>
        ma.Bind(a => bind(a).Select(b => project(a, b)));

`` Just changeMaybe` to the name of your monad and it will work for anything.

The point of this is that you can relatively easily roll your own monadic types, which carry injected functionality and are less cumbersome than Reader or Writer; and easily allow you to change what you do with IO or any external dependencies.

Free monad

And the final, most pure method, is the Free monad approach. This creates true separation between the pure and IO code. I've written about this in depth before and there are two samples in the Samples folders that use this approach.

It is very powerful, but requires a reasonable amount of typing, however it's a reeeeally powerful technique.

@louthy Wow, another amazing reply! I wish you would turn these replies into articles, there is sooo much useful info in here, and it just gets lost when the issue is closed.

Anyway, I'm working my way through this, trying to understand it all, but am struggling to understand what the Reader monad is used for. You created a Div function that takes two strings, and attempts to divide their int values. Please can you explain a) how you would use such a function, as I can't see what you do with the Reader<World, int> that is returned, and b) what the Reader adds here that you didn't have with the code you showed earlier.

Thanks again for another great article

@louthy Paul, I know you just closed this, but is there any chance you could answer the two questions I asked on Feb 7?

Thanks

Was this page helpful?
0 / 5 - 0 ratings