Created
March 28, 2013 12:46
-
-
Save dtchepak/5262838 to your computer and use it in GitHub Desktop.
Messing around with an IO type in C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace Workshop.Terminal | |
{ | |
// Meh, close enough | |
public sealed class Unit { } | |
public sealed class IO<T> | |
{ | |
private readonly Func<T> ioAction; | |
public IO(Func<T> ioAction) { this.ioAction = ioAction; } | |
public IO<TNext> Then<TNext>(IO<TNext> next) | |
{ | |
return new IO<TNext>(() => { | |
ioAction(); | |
return next.ioAction(); | |
}); | |
} | |
public IO<TNext> Then<TNext>(Func<T, IO<TNext>> useValue) | |
{ | |
return new IO<TNext>(() => { | |
var value = ioAction(); | |
var nextIO = useValue(value); | |
return nextIO.ioAction(); | |
}); | |
} | |
public IO<TB> SelectMany<TA, TB>(Func<T, IO<TA>> useValue, Func<T, TA, TB> selector) | |
{ | |
return new IO<TB>(() => { | |
var value = ioAction(); | |
var nextIO = useValue(value); | |
var nextValue = nextIO.ioAction(); | |
return selector(value, nextValue); | |
}); | |
} | |
public IO<TNext> Select<TNext>(Func<T, TNext> selector) | |
{ | |
return new IO<TNext>(() => selector(ioAction())); | |
} | |
// DON'T CALL THIS! | |
public T UnsafePerformIO() { return ioAction(); } | |
} | |
public static class IO | |
{ | |
private static Random random = new Random(); | |
public static IO<Unit> WriteLine(string s) | |
{ | |
return new IO<Unit>(() => { Console.WriteLine(s); return new Unit(); }); | |
} | |
public static IO<string> ReadLine() { return new IO<string>(Console.ReadLine); } | |
public static IO<int> Random(int min, int max) | |
{ | |
return new IO<int>(() => random.Next(min, max)); | |
} | |
} | |
class Program | |
{ | |
public static void SideEffecty() | |
{ | |
Console.WriteLine("Hi, I'm C#. What's your name?"); | |
var name = Console.ReadLine(); | |
Console.WriteLine("Nice to meet you " + name); | |
} | |
public static Action NotSoSideEffecty() | |
{ | |
return () => | |
{ | |
Console.WriteLine("Hi, I'm C#. What's your name?"); | |
var name = Console.ReadLine(); | |
Console.WriteLine("Nice to meet you " + name); | |
}; | |
} | |
public static IO<Unit> GuessNumber(int i) | |
{ | |
return IO.ReadLine() | |
.Select(int.Parse) // should use Option type here for error handling | |
.Then(guess => | |
{ | |
if (guess > i) | |
{ | |
return IO.WriteLine("Too high!").Then(GuessNumber(i)); | |
} | |
else if (guess < i) | |
{ | |
return IO.WriteLine("Too low!").Then(GuessNumber(i)); | |
} | |
return IO.WriteLine("You got it!"); | |
}); | |
} | |
static void Main(string[] args) | |
{ | |
var program = | |
from a in IO.WriteLine("Hi, I'm C#. What's your name?") | |
from name in IO.ReadLine() | |
from b in IO.WriteLine("Nice to meet you " + name + | |
". I'm thinking of a number between 1 and 10. Try and guess it!") | |
from rand in IO.Random(1,10) | |
from c in GuessNumber(rand) | |
select new Unit(); | |
program.UnsafePerformIO(); | |
Console.ReadLine(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Accompanying post: http://davesquared.net/2013/04/side-effect-free-csharp.html