gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 23:11:42 26 4
gpt4 key购买 nike

阅读 Previous SO Question我很困惑地找到 Eric Lippert说不能在 C# 中为所有 Monad 定义接口(interface),使用如下实现:

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

我的问题是问题中列出的所有问题似乎都有简单的解决方案:
  • 没有“高级类型” => 使用父接口(interface)
  • 接口(interface)中没有静态方法。 => 为什么要使用静态?!只使用实例方法

  • Monad 是一种允许在包装类型上链接操作的模式
    为所有 Monad 定义 C# 接口(interface)似乎很容易,允许我们为所有 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);
    }
    }
    }

    最佳答案

    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。)

    你问为什么这是错误的。这在几个方面是错误的。

    错误的第一种方式是:无法通过 Wrap 创建 monad 的新实例。还没有实例!你有一个先有鸡还是先有蛋的问题。

    “wrap”、“unit”或“return”操作——不管你怎么称呼它——在逻辑上是一个静态工厂;这就是创建 monad 的新实例的方式。这不是对实例的操作。这是对类型的静态方法的要求。 (或者,要求一个类型实现一个特定的构造函数,这实际上是同一件事。无论哪种方式,目前 C# 都不支持它。)

    让我们消除 Wrap从下一点考虑。为什么是 Bind错误的?

    第二种错误的方式是您没有适当的限制。您的界面说 T 的单子(monad)是提供返回 U 单子(monad)的绑定(bind)操作的东西。但这还不够严格!假设我们有一个单子(monad) Maybe<T> : IMonad<T> .现在假设我们有这个实现:
    class Wrong<T> : IMonad<T>
    {
    public IMonad<U> Bind<U>(Func<T, IMonad<U>> map)
    {
    return new Maybe<U>();
    }
    }

    这满足了合约,它告诉我们合约不是真正的 monad 合约。 monad 合约应该是 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>相同的类型,但是这个接口(interface)允许我们有一个绑定(bind),它接受一个返回 State<Newspaper> 的函数。但绑定(bind)返回 Maybe<Newspaper> .这完全违反了单子(monad)模式。您尚未在界面中捕获 monad 模式。

    C# 类型系统不足以表达约束“当方法实现时,它必须返回执行实现的类的实例”。如果 C# 有一个“this_type”编译时注解,那么 Bind可以表示为接口(interface),但 C# 没有该注释。

    关于c# - 这是 C# Monad,问题出在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59921510/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com