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

2024-02-01

读一上一个问题 https://stackoverflow.com/questions/35951818/why-can-the-monad-interface-not-be-declared-in-java/35959910#35959910?newreg=ad78d85f7589403db182f4211ea4cf2b我很困惑地发现埃里克·利珀特 https://stackoverflow.com/users/88656/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 的要求。 (许多单子都有这个操作,但不是全部都有。如果你require提取操作,您可能实际上正在使用comonad.)

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

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

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

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

第二种错误是你没有适当的限制。你的接口说 T 的 monad 是一个提供返回 U 的 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>, not IMonad<U>!但我们无法在 C# 中表达“bind 返回定义 bind 的类的实例”。

同样,这是错误的,因为Func必须要求调用者返回Wrong<U>, not IMonad<U>。假设我们有第三个单子,比如说,State<T>。我们可以有

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 模式。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

这是C# Monad,问题出在哪里? 的相关文章

  • 全球化自定义数字格式 - 可变小数点

    我正在尝试更改公司应用程序中现有的数字格式 以使其对国际用户更具可读性 这是一个股票交易应用程序 因此大多数股票价格的数字精确到小数点后 2 位 例如 gt 17 23 我们还可以得到精确到小数点后 4 位的价格变动 因此细价股票可能是 0
  • 我可以声明一个可以将指向自身的指针作为参数的函数吗?

    在阅读 stackoverflow 中的一个问题时 我想知道是否可以声明一个带有指向自身的指针的函数 IE 作出这样的声明foo 对于其中以下内容是正确的 foo foo 最简单的想法是转换为另一个函数指针 不能转换为void 因为它可能更
  • 如何在 Qt Creator 中编辑 QtWebKit 的右键上下文菜单?

    好吧 这是我的困境 我正在使用 Qt Creator 制作一个使用 Webkit 的简单应用程序 我认为 Qt Creator 会有一种简单的方法来使用信号和槽编辑器编辑右键单击上下文菜单 但事实证明这不是真的 我知道 webkit 有与上
  • 使 MahApps.Metro 中的 ProgressRing 更小

    看起来 MahApps Metro ProgressRing 控件默认的最小尺寸为 60x60 ProgressRing 有一个名为 IsLarge 的属性 但即使将其设置为 False 似乎也不会影响使 ProgressRing 小于 6
  • 从 gdb 设置 std::string 变量值?

    是否有可能 当调试器在断点处停止时 修改 std string 变量的值 而不需要采取诸如调整当前缓冲区的内存映像之类的黑客手段 例如类似于 set var mystring hello world 试试这个 经过测试并且对我有用 call
  • 如何在Windows窗体中平滑地重新绘制Panel

    如何将面板重漆成光滑的 我正在使用一个使面板无效的计时器 panel1 Invalidate 每 300 毫秒一次 然后panel1 Paint如果我向该面板添加图像 问题是它看起来像是在跳跃 我需要尽可能快地移动其上的一张图像 这是截屏问
  • 如何确定一个值是否在某个范围内?

    我对 C 语言比较陌生 不幸的是我必须在学校做这件事 而且我在最简单的练习中遇到了问题 这里我必须检查一个数字是否在某个区间内 例如4到6之间 我是这样制作的 include
  • 如何重写 C++ 标准库类函数?

    如何重写 C 标准库类函数 在我的应用程序中 我使用ofstream代码中许多不同位置的对象 现在我想在Linux Ubuntu中以不同的权限模式打开文件 但open的函数ofstream没有参数来指定它创建的文件的权限模式 现在我想覆盖o
  • C++ 将 HashMap 对象返回给 Java

    我有一个 JAVA 调用的 JNI 函数 需要构建并返回一个 HashMap 映射的键是 String 相应的值是 boolean 或 Boolean 任何一个都可以 只要它有效 使用我当前的代码 如下 该字符串已成功添加到返回的映射中 并
  • 编译器之间的重载分辨率不同

    我构建了以下我的问题的最小示例 include
  • 在.NET windows窗体中向TableLayoutPanel添加动态控件

    我想在单击按钮时动态地将控件添加到面板 但我想整理一下位置 例如 我想要两个并排的文本框宽度相等 占用面板的相等空间 见下图 正如您在上图中看到的 单击按钮时 将添加控件 但我在使用 TableLayoutPanel 时遇到问题 请参阅下面
  • 从 Silverlight 中的文件夹加载资源“.resx”

    我有一个多语言应用程序 客户想要按照他的意愿编辑 Resources resx 文件 我创建了 silverlight 项目并添加了一些文件 资源 resx 资源 en US resx1 资源 uk UA resx2 他们都有构建操作 嵌入
  • C# 从mp4文件中提取mp3文件

    有没有简单的方法从 mp4 文件中提取 mp3 文件 我已经尝试过更改文件扩展名 但这不允许我编辑 mp3 描述 谢谢你 Use Xabe FFmpeg https xabe net product xabe ffmpeg 它是免费的 非商
  • 结构体指针运算符猜想(理论)

    结构体指针的使用非常频繁 因此有一个特殊的运算符 gt 下面的表达式是等价的 x y x gt y 将此运算符简单地视为如下定义的预处理器宏是否公平 define x gt x 为什么或者为什么不 或者它从一开始就被编码为运算符 这有何不同
  • 如何在其他项目中添加NLog类库项目

    我已经用 C 创建了一个控制台项目 在该项目中我使用 NLog 进行日志记录 当我运行该项目时 它成功登录到多个目标 例如控制台 文件 EventLog 以及 Sentinal 但是 当我将此项目作为类库并尝试添加对另一个项目的引用时 它不
  • 使用泛型类型实例化抽象类的对象

    我正在创建一个具有泛型类型的函数 并且该泛型类型是我需要实例化的抽象类型 这段代码会更清楚地解释它 public
  • IIS7.5 WCF 服务 - HTTP 错误 401.3(即使在添加 IIS_IUSRS 后)

    我们有使用 NT Authority Network Service 的网站 Response Write WindowsIdentity GetCurrent Name 该网站使用托管在 IIS 7 5 中的 WCF 服务 当我们浏览服务
  • 隐藏 AppBar 中的省略号

    当您在 UWP 应用中创建 AppBar 或 CommandBar 时 控件侧面附近总会隐藏一个省略号 如下所示 我不想在我的应用程序中使用它 但我没有在其中找到任何方法 属性AppBar这会帮助我摆脱它 这应该是可能的 因为许多默认的 W
  • 使用 lambda 从数组中选择每隔一个元素[重复]

    这个问题在这里已经有答案了 C 4 0 如何使用 lambda 表达式完成以下操作 int a new int 8 0 1 2 3 4 5 6 7 Now fetch every second element so that we get
  • 如何在 MVC 中点击链接的主视图中渲染部分视图?

    我有像下面这样的控制器操作方法将从数据库返回所有详细信息 public ActionResult Index BusDataContext db new BusDataContext List

随机推荐