Skip to content

Instantly share code, notes, and snippets.

@Pzixel Pzixel/Statemonad.cs
Last active Dec 19, 2019

Embed
What would you like to do?
using System;
namespace ConsoleApp28
{
public readonly struct Unit
{
public static Unit Instance { get; } = new Unit();
}
public class State<S, A>
{
public Func<S, (A, S)> Run { get; }
public State(Func<S, (A, S)> run)
{
Run = run;
}
public static State<S, A> Return(A a) => new State<S, A>(s => (a, s));
public State<S, B> Bind<B>(Func<A, State<S, B>> g) => new State<S, B>(s1 =>
{
var (a, s2) = Run(s1);
return g(a).Run(s2);
});
}
public static class State
{
public static State<S, S> Get<S>() => new State<S, S>(s => (s, s));
public static State<S, Unit> Set<S>(S s) => new State<S, Unit>(_ => (Unit.Instance, s));
}
public static class XState
{
public static State<S, B> Select<S, A, B>(this State<S, A> value, Func<A, B> map) =>
value.Bind(a => State<S, B>.Return(map(a)));
public static State<S, TResult> SelectMany<S, A, B, TResult>(this State<S, A> value, Func<A, State<S, B>> bind, Func<A, B, TResult> project) =>
value.Bind(a => bind(a).Bind(b => State<S, TResult>.Return(project(a, b))));
}
class Program
{
static State<int, Unit> Foo(int a) =>
from x in State.Get<int>()
let valueToAdd = a > 0 ? 1 : a == 0 ? 2 : 3
from _ in State.Set(x + valueToAdd)
select Unit.Instance;
static State<string, Unit> ConcatStates(State<string, Unit> a, State<string, Unit> b) =>
from __ in a
from aValue in State.Get<string>()
from _ in b
from bValue in State.Get<string>()
from ___ in State.Set<string>(aValue + bValue)
select Unit.Instance;
static void Main(string[] args)
{
var initial = State<int, Unit>.Return(Unit.Instance);
var next = Foo(0);
var next2 = Foo(-1);
Console.WriteLine(next.Bind(_ => next2).Run(100));
var a = State.Set("Hello ");
var b = State.Set("World!");
Console.WriteLine(ConcatStates(a, b).Run(""));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.