using LanguageExt; using System; using static LanguageExt.Prelude; namespace free_monad_vs_typeclass { public abstract class ResourcePrinterFree { public class Return : ResourcePrinterFree { public T Value; public Return(T value) { Value = value; } } public class Print : ResourcePrinterFree { public string Output; public Func> Next; public Print(string output, Func> next) { Output = output; Next = next; } } public class AcquireResource : ResourcePrinterFree { public Func> Next; public AcquireResource(Func> next) { Next = next; } } } public static class ResourcePrinterFreeExtensions { public static T Map(this ResourcePrinterFree op, Func, T> f) => f(op); } public static class FreeInterpreter { public static Unit Interpret(ResourcePrinterFree op) => Interpret(None, op); public static Unit Interpret(Option resource, ResourcePrinterFree op) => resource.Map(_ => op).IfNone(new ResourcePrinterFree.AcquireResource(() => op)).Apply(o => o is ResourcePrinterFree.Return r ? r.Value : o is ResourcePrinterFree.Print p ? resource.Map(fun((ResourceWrapper rs) => rs.Print(p.Output))).Apply(_ => Interpret(resource, p.Next())) : o is ResourcePrinterFree.AcquireResource a ? use(new ResourceWrapper(), rw => Interpret(rw, a.Next())) : throw new InvalidOperationException() ); } }