language-ext v3.3.8 Release Notes

Release Date: 2019-08-12 // over 4 years ago
  • ๐Ÿš€ The last release instroduced the new monad builder feature that wraps a Reader<Env, A> monad into a new monad with the Env hidden inside to make it easier to use.

    ๐Ÿš€ This release improves on that feature by extending the static class that's generated with all functions, fields, and properties that are in the Env type.

    And so, if we have an Env type like so:

    public interface IOEnv { Seq\<string\> ReadAllLines(string path); Unit WriteAllLines(string path, Seq\<string\> lines); }
    

    And wrap it in a new monad called IO:

     [Reader(typeof(IOEnv))] public partial struct IO\<A\> {}
    

    Then we can use the methods within the IOEnv type like so:

    var comp = from ls in IO.ReadAllLines("c:/test.txt") from \_\_ in IO.WriteAllLines("c:/test-copy.txt", ls) select ls.Count;
    

    Which simplifies the usage of the Reader monad even more.

    NOTE: There is no requirement to use an interface for the Env, it can be any type.

    It is also possible to specify the name of the constructor and failure functions: Return and Fail.

     [Reader(Env: typeof(IOEnv), Constructor: "LiftIO", Fail: "FailIO")] public partial struct IO\<A\> { }
    

    This makes it much easier to use the static class as a namespace:

    using static IO; var comp = from ls in ReadAllLines("c:/test.txt") from \_\_ in WriteAllLines("c:/test-copy.txt", ls) from xin LiftIO(100) from yin LiftIO(200) select x \* y;
    

    The generated code for the above example looks like this:

    public partial struct IO\<A\> { readonly LanguageExt.Reader\<TestBed.IOEnv, A\> \_\_comp; internal IO(LanguageExt.Reader\<TestBed.IOEnv, A\> comp) =\> \_\_comp = comp; public static IO\<A\> LiftIO(A value) =\> new IO\<A\>(env =\> (value, false)); public static IO\<A\> FailIO =\> new IO\<A\>(env =\> (default, true)); public IO\<B\> Map\<B\>(Func\<A, B\> f) =\> new IO\<B\>(\_\_comp.Map(f)); public IO\<B\> Select\<B\>(Func\<A, B\> f) =\> new IO\<B\>(\_\_comp.Map(f)); public IO\<B\> Bind\<B\>(Func\<A, IO\<B\>\> f) =\> new IO\<B\>(\_\_comp.Bind(a =\> f(a).\_\_comp)); public IO\<B\> SelectMany\<B\>(Func\<A, IO\<B\>\> f) =\> new IO\<B\>(\_\_comp.Bind(a =\> f(a).\_\_comp)); public IO\<C\> SelectMany\<B, C\>(Func\<A, IO\<B\>\> bind, Func\<A, B, C\> project) =\> new IO\<C\>(\_\_comp.Bind(a =\> bind(a).\_\_comp.Map(b =\> project(a, b)))); public TryOption\<A\> Run(TestBed.IOEnv env) =\> \_\_comp.Run(env); public IO\<A\> Filter(Func\<A, bool\> f) =\> new IO\<A\>(\_\_comp.Where(f)); public IO\<A\> Where(Func\<A, bool\> f) =\> new IO\<A\>(\_\_comp.Where(f)); public IO\<A\> Do(Action\<A\> f) =\> new IO\<A\>(\_\_comp.Do(f)); public IO\<A\> Strict() =\> new IO\<A\>(\_\_comp.Strict()); public Seq\<A\> ToSeq(TestBed.IOEnv env) =\> \_\_comp.ToSeq(env); public IO\<LanguageExt.Unit\> Iter(Action\<A\> f) =\> new IO\<LanguageExt.Unit\>(\_\_comp.Iter(f)); public Func\<TestBed.IOEnv, S\> Fold\<S\>(S state, Func\<S, A, S\> f) { var self = this; return env =\> self.\_\_comp.Fold(state, f).Run(env).IfNoneOrFail(state); } public Func\<TestBed.IOEnv, bool\> ForAll\<S\>(S state, Func\<A, bool\> f) { var self = this; return env =\> self.\_\_comp.ForAll(f).Run(env).IfNoneOrFail(false); } public Func\<TestBed.IOEnv, bool\> Exists\<S\>(S state, Func\<A, bool\> f) { var self = this; return env =\> self.\_\_comp.Exists(f).Run(env).IfNoneOrFail(false); } }public static partial class IO{ public static IO\<A\> LiftIO\<A\>(A value) =\> IO\<A\>.LiftIO(value); public static IO\<A\> FailIO\<A\>() =\> IO\<A\>.FailIO; public static IO\<A\> asks\<A\>(Func\<TestBed.IOEnv, A\> f) =\> new IO\<A\>(env =\> (f(env), false)); public static readonly IO\<TestBed.IOEnv\> ask = new IO\<TestBed.IOEnv\>(env =\> (env, false)); public static IO\<LanguageExt.Seq\<string\>\> ReadAllLines(string path) =\> ask.Map(\_\_env =\> \_\_env.ReadAllLines(path)); public static IO\<LanguageExt.Unit\> WriteAllLines(string path, LanguageExt.Seq\<string\> lines) =\> ask.Map(\_\_env =\> \_\_env.WriteAllLines(path, lines)); }