这是C#Monad,问题出在哪里? [英] Here is the C# Monad, where is the problem?

查看:101
本文介绍了这是C#Monad,问题出在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Reading a Previous SO Question I was confused to find Eric Lippert saying that an interface cannot be defined in C# for all Monads, using an implementation as below:

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

我的问题是问题中列出的所有问题似乎都可以轻松解决:

My problem is all the problems listed in the question seem to have easy solutions:

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

Monad是一种模式,允许对包装类型的操作进行链接 为所有Monad定义一个C#接口似乎很容易,这使我们可以为所有Monad编写一个通用类 哪里出问题了?

Monad is a pattern allowing chaining of operations on wrapped types it seems easy to define a C# interface for all Monads allowing us to write a generic class for all monads Where's the problem?

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#接口似乎很容易.哪里出问题了?

it seems easy to define a C# interface for all monads. Where's the problem?

您的建议是:

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

我已经省略了展开",因为提取操作的存在不是monad的要求. (许多monad都有此操作,但不是全部都有.如果要求进行提取操作,则可能实际上是在使用 comonad .)

I've omitted the "unwrap" because the existence of an extraction operation is not a requirement of a monad. (Many monads have this operation, but not all do. If you require an extract operation, you are probably actually using a comonad.)

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

You ask why this is wrong. This is wrong in several ways.

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

The first way it is wrong is: there is no way to create a new instance of the monad via Wrap without already having an instance! You have a chicken-and-egg problem here.

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

The "wrap" or "unit" or "return" operation -- whatever you want to call it -- is logically a static factory; it's how you make a new instance of the monad. It's not an operation on an instance. It is a requirement of a static method on a type. (Or, the requirement that a type implement a particular constructor, which is effectively the same thing. Either way, it is not supported in C# at this time.)

让我们从下一点开始排除Wrap.为什么Bind错误?

Let's eliminate Wrap from consideration in the next point. Why is Bind wrong?

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

The second way it is wrong is you do not have the right restrictions in place. Your interface says that a monad of T is a thing that provides a bind operation that returns a monad of U. But that is not restrictive enough! Suppose we have a monad Maybe<T> : IMonad<T>. Now suppose we have this implementation:

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

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

That satisfies the contract, which tells us that the contract is not the real monad contract. The monad contract should be that Wrong<T>.Bind<U> returns Wrong<U>, not IMonad<U>! But we have no way of expressing in C# "bind returns an instance of the class which defines bind".

类似地,这是错误的,因为必须要求调用者提供的Func返回Wrong<U>,而不是IMonad<U>.假设我们有第三个monad,例如State<T>.我们本来可以

Similarly it is wrong because the Func that is provided by the caller must be required to return Wrong<U>, not IMonad<U>. Suppose we have a third monad, say, State<T>. We could have

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

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

And now this is all messed up. Wrong<T>.Bind<U> must take a function that returns some Wrong<U> and must itself return Wrong<U> of the same type, but this interface allows us to have a bind that takes a function that returns State<Newspaper> but the bind returns Maybe<Newspaper>. This is a total violation of the monad pattern. You have not captured the monad pattern in your interface.

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

The C# type system is not strong enough to express the constraint "when the method is implemented it must return an instance of the class that did the implementation". If C# had a "this_type" compile-time annotation then Bind could be expressed as an interface, but C# does not have that annotation.

这篇关于这是C#Monad,问题出在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆