Skip to content

Instantly share code, notes, and snippets.

@masaeedu
Created July 25, 2018 08:54
Show Gist options
  • Save masaeedu/ba0cde72ba513080c660f390924169ac to your computer and use it in GitHub Desktop.
Save masaeedu/ba0cde72ba513080c660f390924169ac to your computer and use it in GitHub Desktop.
using System;
using System.Threading.Tasks;
namespace tmp.zNpqzfT0PE
{
class Program
{
static void Main(string[] args)
{
var job = ChangeForegroundColor(ConsoleColor.Blue)
.BindDisp(_ => Print("Blue prompt says: 'please enter something in red, I will echo it back in green'").LiftDisp())
.BindDisp(_ => ChangeForegroundColor(ConsoleColor.Red))
.BindDisp(_ => ReadInput.LiftDisp())
.BindDisp(input => ChangeForegroundColor(ConsoleColor.Green).MapDisp(_ => input))
.BindDisp(input => Print(input).LiftDisp());
job.BindCont(result => result.Cleanup)
.Run(_ => { });
// We should be back to black here
Console.WriteLine("This text in boring black :(");
}
public static Cont<Unit> Print(string message)
=> new Cont<Unit>(cb =>
{
Console.WriteLine(message);
cb(Unit.Only);
});
public static Cont<String> ReadInput { get; }
= new Cont<string>(cb =>
{
var result = Console.ReadLine();
cb(result);
});
public static Cont<Acq<ConsoleColor>> ChangeForegroundColor(ConsoleColor color)
{
return Disposable.Acquire<ConsoleColor>(
new Cont<ConsoleColor>(cb =>
{
var oldColor = Console.ForegroundColor;
// Console.WriteLine($"Changing color from {oldColor} to {color}");
Console.ForegroundColor = color;
cb(oldColor);
}),
oldColor => new Cont<Unit>(cb =>
{
// Console.WriteLine($"Reverting color to {oldColor}");
Console.ForegroundColor = oldColor;
cb(Unit.Only);
})
);
}
}
public sealed class Unit
{
private Unit() { }
public static Unit Only { get; } = new Unit();
}
public class Acq<V>
{
public V Value { get; }
public Cont<Unit> Cleanup { get; }
public Acq(V value, Cont<Unit> cleanup)
{
Value = value;
Cleanup = cleanup;
}
}
public static class Disposable
{
public static Cont<Acq<V>> LiftDisp<V>(this Cont<V> c)
=> c.MapCont(v => new Acq<V>(v, Cont.PureCont(Unit.Only)));
public static Cont<Acq<V>> PureDisp<V>(V v)
=> Cont.PureCont(new Acq<V>(v, Cont.PureCont(Unit.Only)));
public static Cont<Acq<B>> BindDisp<A, B>(this Cont<Acq<A>> a, Func<A, Cont<Acq<B>>> f)
{
return a.BindCont(acqA =>
{
var va = acqA.Value;
var cleanupA = acqA.Cleanup;
return f(va)
.MapCont(b => new Acq<B>(b.Value, b.Cleanup.BindCont(_ => cleanupA)));
});
}
public static Cont<Acq<B>> MapDisp<A, B>(this Cont<Acq<A>> a, Func<A, B> f)
=> a.BindDisp(v => PureDisp(f(v)));
public static Cont<Acq<A>> Acquire<A>(Cont<A> run, Func<A, Cont<Unit>> cleanup)
=> run.MapCont(a => new Acq<A>(a, cleanup(a)));
}
public class Cont<A>
{
public Action<Action<A>> Run { get; }
public Cont(Action<Action<A>> run)
{
Run = run;
}
}
public static class Cont
{
public static Cont<A> New<A>(Action<Action<A>> run)
=> new Cont<A>(run);
public static Cont<A> PureCont<A>(A a)
=> new Cont<A>(cb => cb(a));
public static Cont<B> BindCont<A, B>(this Cont<A> a, Func<A, Cont<B>> f)
=> new Cont<B>(cb => a.Run(v => f(v).Run(cb)));
public static Cont<B> MapCont<A, B>(this Cont<A> a, Func<A, B> f)
=> a.BindCont(v => PureCont(f(v)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment