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 theEnv
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 theEnv
, it can be any type.It is also possible to specify the name of the constructor and failure functions:
Return
andFail
.[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)); }