C# Continuation Monad Implementation
I have been working on allowing function chaining. I have created a class called continuationmonad which takes a value, and a function from a => b. This allows me to use fmap and bind to chain these together. I have also used lazy to allowed calls to be defered where possible.
Is this class really the continuation monad or is it something else. I am finding it hard to find good literature which is not is Haskell.
Also any comments on how to improve / correct this.
using NUnit.Framework;
using System;
namespace Monads
{
public class Continuation<Input, Output>{
public Continuation(Input value, Func<Input,Output> function){
this.value = new Lazy<Input>( () => value);
this.function = function;
}
public Continuation(Lazy<Input> value, Func<Input,Output> function){
this.value = value;
this.function = function;
}
public Continuation<Output, Result> FMap<Result>(Func<Output, Result> map){
return new Continuation<Output, Result>(new Lazy<Output>( () => Run() ), x => map(x));
}
public Continuation<Output,Result> Bind<Result>(Func<Output, Continuation<Output, Result>> f){
return f(Run());
}
public Output Run(){
return function(value.Value);
}
private Func<Input, Output> function;
private Lazy<Input> value;
}
public static class ContinuationExtension{
public static Continuation<A,B> Unit<A,B>(this Func<A,B> f, A value){
return new Continuation<A, B>(value,f);
}
public static Continuation<A,B> Unit<A,B>(this A value,Func<A,B> f){
return new Continuation<A, B>(value,f);
}
}
[TestFixture]
public class MonadTests
{
public Continuation<int,int> Wrapped(int value){
return new Continuation<int,int>(value, x => x * 10);
}
[Test]
public void ContinuationMonadTests()
{
var number = 42;
var result = number.Unit(x => x + 8).FMap(x => x * 2).Bind(Wrapped).Run();
Console.WriteLine(result);
}
}
}
This is not the continuation monad. You are much closer to the Haskell Monad
instance for functions.
You aren't getting anything that you couldn't get just from using Lazy<>
. Since you have provided the input when you build an instance of your class, you aren't building functions, you are building values that are determined by a computation that hasn't been evaluated yet. Lazy<>
delays the evaluation of computation until the value is needed.
Let's put together something like the Haskell Monad
instance for functions in c#. LINQ syntax has established the convention for Monad
s in c#. They should have:
Select
extension method analogous to a Haskell Functor
's fmap
SelectMany
extension method analogous to Haskell's Monad
's >>=
SelectMany
that LINQ syntax uses. This takes an additional function that combines the value from two steps together. Unfortunately, there's no convention for what the analog of a Monad
's return
should be called; we'll call ours Constant
. Unfortunately, Constant
won't be very convenient because c#'s type inference won't be able to figure out the types.
public static class Function
{
public static Func<TIn, TOut> Constant<TIn, TOut>(TOut result)
{
return x => result;
}
public static Func<TIn, TOut> Select<TIn, TMid, TOut>(
this Func<TIn, TMid> func,
Func<TMid, TOut> proj)
{
return x => proj(func(x));
}
public static Func<TIn, TOut> SelectMany<TIn, TMid, TOut>(
this Func<TIn, TMid> func,
Func<TMid, Func<TIn, TOut>> proj)
{
return x => proj(func(x))(x);
}
public static Func<TIn, TOut> SelectMany<TIn, TMid1, TMid2, TOut>(
this Func<TIn, TMid1> func,
Func<TMid1, Func<TIn, TMid2>> proj1,
Func<TMid1, TMid2, TOut> proj2)
{
return x => {
var mid1 = func(x);
var mid2 = proj1(mid1)(x);
return proj2(mid1, mid2);
};
}
}
Note that defining these extension methods only lets you interact with something like it's a Monad
, it doesn't let you write code that's generic over the specific Monad
being used. There's a sketch of how to do that in the second half of this answer.
This might be a bit opinion based but I'll try to give you my 5ct anyway.
Let's have a look at your class and their instances:
It includes a value and a function where you (tried) to make it all a lazy. From a theoretical view I can see no difference to Lazy<T>
on first glance:
You can surely convert one of your Continuation<Input,Output>
to just a Lazy<Output>
.
The same is true for the reverse: given some lazy value a
you can make a instance with just
new Continuation(a, x => x)
So to me it seems that you just reinvented Lazy
(which is an monad, in Haskell you would call it Identity
.
The Cont
monad is not really easy to crasp but it's really more related to .net-Events or .net-Observables. The datastructure itself would be like
Func<Func<Input,Output>, Output>
Where you pass in a continuation Func<Input,Output>
to some internal calculation and then the struture than will call it when it has calculated an input Input
to get the final result.
This might be a bit cryptic but one .net application are the Async
workflows F# uses and which stood model for C#s async/await behaviour in some sense.
I have some material I used for a talk on a simpified version of this monad in C# on github maybe you'll find it interesting.
链接地址: http://www.djcxy.com/p/58766.html上一篇: STM与fclabels
下一篇: C#连续Monad实现