最近简要介绍了Haskell,对于monad本质上是什么,简单,简洁,实用的解释是什么?
我发现我遇到的大多数解释都是相当难以接近的,缺乏实际细节.
谁首先说了以下几点?
monad只是endofunctors类别中的幺半群,问题是什么?
在一个不太重要的注意事项上,这是真的,如果是这样,你能给出一个解释(希望有一个可以被没有Haskell经验的人理解的那个)吗?
这些天有很多关于单子的讨论.我已经阅读了一些文章/博客文章,但我不能用他们的例子来完全掌握这个概念.原因是monad是一个函数式语言概念,因此这些例子都是我没有使用过的语言(因为我没有深入使用过函数式语言).我无法深入掌握语法以完全遵循这些文章......但我可以告诉它有一些值得理解的东西.
但是,我非常了解C#,包括lambda表达式和其他功能特性.我知道C#只有一部分功能特性,所以monad不能用C#表示.
但是,肯定有可能传达这个概念吗?至少我希望如此.也许您可以将C#示例作为基础,然后描述C#开发人员希望他可以从那里做什么,但不能,因为该语言缺乏函数式编程功能.这太棒了,因为它会传达monad的意图和好处.所以这就是我的问题:你可以给一个C#3开发人员提供monad的最佳解释是什么?
谢谢!
(编辑:顺便说一下,我知道SO上至少有3个"什么是monad"问题.然而,我遇到了同样的问题......所以这个问题需要imo,因为C#-developer焦点.谢谢.)
Java 8流是否类似于RxJava observables?
Java 8流定义:
新
java.util.stream
包中的类提供Stream API以支持对元素流的功能样式操作.
可能重复:
什么是monad?
我想我明白'也许莫纳德'是什么,但我不确定其他类型.
在开始阅读之前:这个问题不是关于理解monad,而是关于识别Java类型系统的限制,这会限制Monad
接口的声明.
在我的努力去理解单子我读这个由埃里克利珀SO-答案上询问单子简单的解释问题.在那里,他还列出了可以在monad上执行的操作:
- 有一种方法可以获取未放大类型的值并将其转换为放大类型的值.
- 有一种方法可以将非放大类型的操作转换为符合之前提到的功能组合规则的放大类型的操作
- 通常有一种方法可以将未放大的类型从放大类型中取出.(对于monad而言,这最后一点并非绝对必要,但通常情况下存在这样的操作.)
在阅读了关于monads的更多信息后,我将第一个操作识别为return
函数,将第二个操作识别为bind
函数.我无法找到第三个操作的常用名称,因此我将其称为unbox
函数.
为了更好地理解monad,我继续尝试Monad
用Java 声明一个通用接口.为此,我首先看了上面三个函数的签名.对于Monad M
,它看起来像这样:
return :: T1 -> M<T1>
bind :: M<T1> -> (T1 -> M<T2>) -> M<T2>
unbox :: M<T1> -> T1
Run Code Online (Sandbox Code Playgroud)
该return
函数不在实例上执行M
,因此它不属于该Monad
接口.相反,它将实现为构造函数或工厂方法.
此外,我现在省略了unbox
接口声明中的函数,因为它不是必需的.对于接口的不同实现,将具有该功能的不同实现.
因此,Monad
接口仅包含该bind
功能.
让我们尝试声明接口:
public interface Monad {
Monad bind();
}
Run Code Online (Sandbox Code Playgroud)
有两个缺点:
bind
函数应返回具体实现,但它只返回接口类型.这是一个问题,因为我们在具体的子类型上声明了unbox操作.我将此称为问题1.bind
函数应该将函数检索为参数.我们稍后会解决这个问题.这解决了问题1:如果我对monads的理解是正确的,那么bind
函数总是会返回一个与调用它的monad具有相同具体类型的新monad.所以,如果我有一个Monad
被调用的接口的实现M …
可能重复:
什么是monad?
您如何用非编程术语描述monad?是否有一些概念/事物在编程之外(在所有编程之外,而不仅仅是FP),可以说是以一种重要的方式行事或像monad一样?
澄清问题:它是关于monad类型类的优点(而不是它没有统一类的实例).
在阅读了许多参考文献(见下文)之后,我得出的结论是,实际上,monad类只能解决一个问题,即大而重要的问题:关于具有上下文的类型的函数的"链接".因此,着名的句子"monad是可编程的分号".实际上,monad可以被视为具有辅助操作的函数数组.
我坚持monad 类之间的区别,被理解为其他类型的通用接口; 以及这些其他类型实例化类(因此,"monadic类型").
我理解monad类本身只解决了运算符的链接,因为主要是它只要求它的类型实例具有bind >>=
和return
,并且告诉我们它们必须如何表现.作为奖励,编译器非常有助于编码为monadic do
类型提供符号.
另一方面,实例化monad类的每个单独类型解决了每个具体问题,但不仅仅是作为Monad的实例.例如,Maybe
解决"函数如何返回值或错误",State
解决"如何使用全局状态的函数",IO
解决"如何与外部世界交互"等等.所有这些类都在上下文中封装了一个值.
但不久之后,我们需要对这些上下文类型进行连锁操作.也就是说,我们需要以特定的顺序组织对这些类型的函数的调用(对于这样一个问题的例子,请阅读你可能已经发明了monad的多值函数的例子).
如果每个类型都是monad类的实例,那么你就解决了链接的问题.为了使链接起作用,你需要>>=
具有它所具有的确切签名,而不是其他.(见这个问题).
因此,我猜你下次定义上下文数据类型T来解决问题时,如果你需要对函数的调用进行排序(在T的值上),可以考虑将T作为一个实例Monad
(如果你需要"选择链接",如果你可以从do
符号中受益).为了确保你做得对,检查T是否符合monad法则
然后,我向Haskell专家提出两个问题:
人们说“ monad是计算模型”的确切含义是什么?从完整性的意义上讲,这意味着计算吗?如果是这样,怎么办?
澄清:这个问题不是要解释单子,而是人们在此上下文中对“计算模型”的含义以及它与单子的关系。有关此短语的典型用法,请参阅此答案的结尾。
在我对图灵机的理解中,递归函数理论,lambda微积分等都是计算模型,我完全看不出monad与它之间的关系。
Erik Meijer喜欢指出每个LINQ函数实际上都可以由SelectMany实现; 其他一切都只是一种便利.
这就是Eric Lippert在回答有关monad的问题时所说的,但我听说Erik Meijer在其他关于LINQ和Rx的视频中这样说.(简单地说,Erik Meijer是创建LINQ和Rx的人)
我想知道如何用SelectMany实现一些最常用的LINQ函数? 暂时忽略性能,让我们专注于优雅和简洁.
monads ×8
haskell ×6
c# ×2
c#-3.0 ×1
generics ×1
glossary ×1
java ×1
java-8 ×1
java-stream ×1
lambda ×1
linq ×1
monoids ×1
observable ×1
rx-java ×1
terminology ×1
type-systems ×1