C#连续Monad实现

我一直在努力让功能链。 我创建了一个名为continuationmonad的类,它接受一个值,并从a => b函数。 这使我可以使用fmap和绑定将它们链接在一起。 我也使用懒惰允许的电话在可能的情况下被打败。

这个类真的是继续monad还是别的东西。 我发现很难找到不是Haskell的优秀文献。

还有关于如何改进/纠正此问题的任何评论。

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);
        }
    }
}

这不是延续monad。 你更接近Haskell Monad实例的功能。

你没有得到任何你无法从Lazy<>获得的东西。 由于在构建类的实例时提供了输入,因此您不构建函数,而是构建由尚未评估过的计算所确定的值。 Lazy<>延迟计算评估直到需要该值。

让我们把Haskell Monad实例放在一起,用于c#中的函数。 LINQ语法为c#中的Monad建立了约定。 他们应该有:

  • 一个类似于Haskell FunctorfmapSelect扩展方法
  • 一个类似于Haskell的Monad>>=SelectMany扩展方法
  • LINQ语法使用的额外SelectMany 。 这需要一个将两个步骤的值结合在一起的附加功能。
  • 不幸的是,对于Monadreturn模拟应该被称为什么没有规定。 我们会打电话给我们的Constant 。 不幸的是, Constant不会很方便,因为c#的类型推断将无法计算出类型。

    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);
            };
        }
    }
    

    请注意,定义这些扩展方法只允许您使用类似于Monad方式进行交互,但它不会让您编写通用于所使用的特定Monad代码。 这个答案的后半部分有一个如何做到这一点的草图。


    这可能有点意见,但我会尽力给你我的5ct。

    让我们来看看你的班级和他们的实例:

    它包括一个价值和一个功能,你(试过)让它变得懒惰。 从理论的角度来看,我可以一眼看出Lazy<T>没有任何区别:

    你当然可以将Continuation<Input,Output>中的一个转换为Lazy<Output>

    相反的情况也是如此:给定一些懒惰的值a你可以用一个实例来创建一个实例

    new Continuation(a, x => x)
    

    所以对我来说,你似乎只是改造了Lazy (这是一个monad,在Haskell中你可以称之为Identity

    Cont monad不是很容易崩溃,但它更与.net-Events或.net-Observables相关。 数据结构本身就是这样

    Func<Func<Input,Output>, Output>
    

    在你继续传递Func<Input,Output>到一些内部计算的地方,然后在结构计算输入Input以获得最终结果时调用它。

    这可能有点神秘,但是.net应用程序是F#使用的Async工作流程,在某种意义上,它是C#异步/等待行为的模型。

    我有一些材料用于在github上的C#中对这个monad的简化版本的讨论,也许你会发现它很有趣。

    链接地址: http://www.djcxy.com/p/58765.html

    上一篇: C# Continuation Monad Implementation

    下一篇: Serializing Running Programs in a Functional Interpreter