Skip to content

Instantly share code, notes, and snippets.

@atifaziz
Last active June 13, 2024 12:23
Show Gist options
  • Save atifaziz/4a0438946e6002148001a98804f93b3d to your computer and use it in GitHub Desktop.
Save atifaziz/4a0438946e6002148001a98804f93b3d to your computer and use it in GitHub Desktop.
Interact Monad, derived from https://fssnip.net/8ay (Interactive computation that asks the user questions)
// Interact Monad, derived from https://fssnip.net/8ay (by Tomas Petricek)
// Interactive computation that asks the user questions
using System;
using System.Diagnostics;
using System.Linq;
static Interactive<Color> GetColor() => new WhatColor<Color>(Interactive.Return);
static Interactive<int> GetNumber() => new WhatNumber<int>(Interactive.Return);
var demo =
from c1 in GetColor()
from c2 in GetColor()
from n in GetNumber()
select Enumerable.Repeat(c1 == c2, n);
var flags = Run(demo);
Console.WriteLine($"Got {string.Join(", ", flags)}");
static T Run<T>(Interactive<T> c)
{
switch (c)
{
case Done<T>(var r):
return r;
case WhatNumber<T>(var f):
var input = Console.ReadLine();
return Run(f(int.Parse(input)));
case WhatColor<T>(var f):
return Console.ReadLine() switch
{
"pink" => Run(f(Color.Pink)),
"purple" => Run(f(Color.Purple)),
_ => throw new("Wrong input."),
};
default: throw new UnreachableException();
}
}
abstract record Interactive<T>;
sealed record Done<T>(T Result) : Interactive<T>;
sealed record WhatNumber<T>(Func<int, Interactive<T>> Cont) : Interactive<T>;
sealed record WhatColor<T>(Func<Color, Interactive<T>> Cont) : Interactive<T>;
enum Color { Pink, Purple }
static class Interactive
{
public static Interactive<T> Return<T>(T result) => new Done<T>(result);
public static Interactive<U> Bind<T, U>(this Interactive<T> comp,
Func<T, Interactive<U>> f) =>
comp switch
{
Done<T>(var v) => f(v),
WhatColor<T>(var g) => new WhatColor<U>(c => g(c).Bind(f)),
WhatNumber<T>(var g) => new WhatNumber<U>(n => g(n).Bind(f)),
};
public static Interactive<U> Select<T, U>(this Interactive<T> comp, Func<T, U> f) =>
comp.Bind(e => Return(f(e)));
public static Interactive<V> SelectMany<T, U, V>(this Interactive<T> comp,
Func<T, Interactive<U>> f,
Func<T, U, V> g) =>
comp.Bind(a => from b in f(a) select g(a, b));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment