这是C#Monad,问题出在哪里?

匿名莫斯

阅读上一个SO问题,我很困惑,发现Eric Lippert说无法使用以下实现在C#中为所有Monad定义接口:

typeInterface Monad<MonadType<A>>
{
       static MonadType<A> Return(A a);
       static MonadType<B> Bind<B>(MonadType<A> x, Func<A, MonadType<B>> f);
}

我的问题是问题中列出的所有问题似乎都有简单的解决方案:

  • 没有“更高种类的类型” =>使用父接口
  • 接口中没有静态方法。=>为什么要使用静态?只是使用实例方法

Monad是一种允许对包装类型进行操作链接的模式,为所有Monad定义C#接口似乎很容易,允许我们为所有monad编写泛型类。问题出在哪里?

using System;
using System.Linq;          
public class Program
{
    public static void Main()
    {//it works, where's the problem?
            new SequenceMonad<int>(5)
                .Bind(x => new SequenceMonad<float>(x + 7F))
                .Bind(x => new SequenceMonad<double>(x + 5D))
                ;
    }
    interface IMonad<T>{

        IMonad<T> Wrap(T a);
        IMonad<U> Bind<U>(Func<T, IMonad<U>> map);
        T UnWrap();//if we can wrap we should be able to unwrap
    }
    class GenericClassForAllMonads<T>
    {//example writing logic for all monads
        IMonad<U> DoStuff<U>(IMonad<T> input, Func<T, IMonad<U>> map)
        { return map(input.UnWrap()); }
    }
    class SequenceMonad<T> : IMonad<T> where T:new()
    {//specific monad implementation
        readonly T[] items;//immutable
        public SequenceMonad(T a)
        {
            Console.WriteLine("wrapped:"+a);
            items =  new[] { a }; 
        }
        public IMonad<B> Bind<B>(Func<T, IMonad<B>> map)
        {  return map(UnWrap()); }

        public T UnWrap()
        { return items == null? default(T) : items.FirstOrDefault();  }

        public IMonad<T> Wrap(T a)
        {
            Console.WriteLine("wrapped:"+a);
            return new SequenceMonad<T>(a); 
        }
    }
}
埃里克·利珀特

为所有monad定义C#接口似乎很容易。哪里出问题了?

您的建议是:

interface IMonad<T>
{
    IMonad<T> Wrap(T a);
    IMonad<U> Bind<U>(Func<T, IMonad<U>> map);
}

我省略了“展开”,因为提取操作的存在不是monad的要求。(许多monad都有此操作,但并非全部都有。如果需要提取操作,则可能实际上是在使用comonad。)

您问为什么这是错误的。这在几种方面是错误的。

错误的第一种方法是:如果没有实例,就无法通过创建单实例的新Wrap实例!您在这里遇到了鸡和蛋的问题。

从逻辑上讲,“包装”或“单元”或“返回”操作(无论您想称呼它)都是静态工厂。这就是创建monad的新实例的方式这不是对实例的操作。它是对类型的静态方法的要求。(或者,要求类型实现特定的构造函数,这实际上是同一件事。无论哪种方式,C#目前均不支持。)

Wrap接下来,让我们从考虑中消除为什么Bind错了?

第二种错误的方法是您没有适当的限制。您的界面说,T的单子是提供绑定操作并返回U的单子的事物。但这还不够严格!假设我们有一个单子Maybe<T> : IMonad<T>现在假设我们有以下实现:

class Wrong<T> : IMonad<T>
{
  public IMonad<U> Bind<U>(Func<T, IMonad<U>> map)
  {
    return new Maybe<U>();
  }
}

这样就满足了合同,这告诉我们合同不是真正的单子合同。单子合同应该是Wrong<T>.Bind<U>回报Wrong<U>,而不是IMonad<U>但是我们无法用C#表示“ bind返回定义bind的类的实例”。

同样,这是错误的,因为Func必须要求调用方提供的而Wrong<U>不是返回IMonad<U>假设我们有第三个monad State<T>我们可以有

Wrong<Frog> w = whatever;
var result = w.Bind<Newspaper>(t=>new State<Newspaper>());

现在,这一切都搞砸了。Wrong<T>.Bind<U>必须具有返回某些函数Wrong<U>并且本身必须返回Wrong<U>相同类型的函数,但是此接口允许我们具有一个绑定,该bind接受具有返回State<Newspaper>但绑定返回的函数Maybe<Newspaper>这完全违反了monad模式。您尚未在界面中捕获monad模式。

C#类型系统不够强大,无法表达约束条件“实现方法时,它必须返回执行该实现的类的实例”。如果C#具有“ this_type”编译时注释,则Bind可以表示为接口,但C#没有该注释。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

if else语句和打印的问题出在哪里?

来自分类Dev

继续获取IDLE内部异常TypeError,但它没有告诉我问题出在哪里

来自分类Dev

解析错误,文件意外结束-无法确定问题出在哪里

来自分类Dev

我的python输出在哪里?

来自分类Dev

我的调试输出在哪里?

来自分类Dev

使用moviepy库将2个视频合并在一起简单问题!输出在哪里?

来自分类Dev

已部署的 ERC23 Token 在我的钱包中显示余额为 0,问题出在哪里?

来自分类Dev

PostgreSQL pg_dump的输出在哪里

来自分类Dev

调试时QtCreator的标准输出在哪里?

来自分类Dev

安卓检测测试的输出在哪里?

来自分类Dev

HDInsight hadoop-mapreduce-examples.jar输出在哪里?

来自分类Dev

Ubuntu 11.10上的强制退出在哪里?

来自分类Dev

Ubuntu 11.10上的强制退出在哪里?

来自分类Dev

knitr:example(help = knitr)的输出在哪里?

来自分类Dev

HP Loadrunner“系统”调用的输出在哪里?

来自分类Dev

调试时QtCreator的标准输出在哪里?

来自分类Dev

HDInsight hadoop-mapreduce-examples.jar输出在哪里?

来自分类Dev

使用COUNTIF找出在哪里找到项目

来自分类Dev

在哪里报告快照问题?

来自分类Dev

拼写器适用于某些单词而不适用于其他单词。不知道问题出在哪里

来自分类Dev

Nullable <T> monad上的绑定和标识函数在哪里?

来自分类Dev

MYSQL + PHP问题,名字在哪里

来自分类Dev

随机洗牌的问题在哪里

来自分类Dev

问题开放程序,我在哪里安装?

来自分类Dev

这个python代码在哪里出问题?

来自分类Dev

Laravel在哪里有升级问题

来自分类Dev

硒与python的问题在哪里?

来自分类Dev

问题开放程序,我在哪里安装?

来自分类Dev

C#在哪里选择

Related 相关文章

热门标签

归档