Scala 单子是什么?
我想我已经基本掌握了单子和单子运算,但仍然有点难以理解单子类型的神奇特性是如何添加到底层类型的(希望这是有意义的) 例如,我了解了Scala 单子是什么?,scala,monads,Scala,Monads,我想我已经基本掌握了单子和单子运算,但仍然有点难以理解单子类型的神奇特性是如何添加到底层类型的(希望这是有意义的) 例如,我了解了列表[T]是如何成为单子的。但是,如果我在一个理解的中连续地flatMap和map在一些列表上,那么它不是真的提供了一元魔力吗 如果我创建一个列表,那么一元魔法是如何添加的?或者列表在Scala中总是一个单子,因为它恰好是语言已经提供内置单子支持的容器之一?单子是一个概念,而不是一个类或特征。 因为List[T]满足了单子的所有要求,所以它可以称为monadic。 简
列表[T]
是如何成为单子的。但是,如果我在一个理解的中连续地flatMap
和map
在一些列表上,那么它不是真的提供了一元魔力吗
如果我创建一个列表
,那么一元魔法是如何添加的?或者列表
在Scala中总是一个单子,因为它恰好是语言已经提供内置单子支持的容器之一?单子
是一个概念,而不是一个类或特征。
因为List[T]
满足了单子的所有要求,所以它可以称为monadic
。
简单地说,它是单子,因为它具有单子提供的所有功能和能力,所以它是单子
如果你想要更多的保证,更明确地表达你是一个单子,你可以使用Scalaz
。
这个链接展示了如何并提供了一个关于单子定律的详细信息:你完全正确地认为flatMap
和map
提供了“单子魔法”。幸运或不幸的是(取决于你见过多少糟糕的代码)编程中没有魔法。再多的抽象也不能让你(或其他人)最终编写出你想要的代码。抽象“只是”让您可以重用以前编写的代码,并澄清您对问题的想法。一个单子就是一个概念,一个想法,一个抽象,等等
在Scala的情况下,这是编译器为理解而对所做的工作,它变成了一系列flatMap
、map
、with filter
和filter
语句
monad(在Scala中)可以被认为只是一个现象的标签,其中碰巧有一个类型构造函数T[\u]
和两个函数1
按照惯例,当Scala社区看到这种现象时,会调用f0
flatMap
,通常将其作为一个方法,以便x
始终是父类,而不是单独的参数。还有一种惯例是调用f1
point
或pure
(请参见scalaz
或cats
)f1
通常也是一种方法,因此它不会显式地接受参数,而只是将其父类用作x
每当有人说“某某”是单子时,说话者总是希望听者推断出隐含的f0
和f1
。严格地说,“List
是单子”是对术语的轻度滥用。它是List
以及(xs:List[A],f:A=>List[A])=>xs.map(f)的简写形式。扁平化(形成f0
)和(x:A)=>List(x)
(形成f1
)形成单子。或者稍微不那么迟钝,List
以及列表上的标准flatMap
和列表。应用
构造函数形成单子
因此,从来没有任何魔法。作为将某物分类为单子的一部分,您必须提供平面图和纯
的概念
有很多方法可以将单子的这种抽象转化为代码。最简单的方法(即没有第三方库的Scala)是只为f0
和f1
(例如flatMap
)商定一个通用名称,然后只命名具有适当类型签名的方法。这本质上就是scalac
希望您为理解所做的。您可以更进一步,尝试使用特征
或抽象类
对事物进行形式化。也许叫它Monad
,让它看起来可爱点,并有如下特点:
trait Monad[A] {
def flatMap(f: A => Monad[A]): Monad[A]
def pure(x: A): Monad[A]
}
然后,您可以将任何扩展这个Monad
的东西称为Monad思想的实现(您可以想象像类列表[A]扩展Monad[A]
)
出于各种实际原因,结果证明这并不令人满意,因此您最终得到的通常解决方案类似于(挥手告别许多其他复杂性)
通过implicit
s实现
脚注:
以及一些管理其相互作用的法律/惯例。这些定律存在的实际原因是为了让程序员的生活变得理智,这样当有人告诉他们这些函数是“一元函数”时,他们就知道会发生什么。正是这些定律使得对诸如一元函数之类的结构进行推理变得如此有用,但我不会在这里深入探讨它们,因为它们在别处已经得到了充分的解释
从纯角度来看,List
可能不是单子。至少这是我基于左身份规则的看法:
unit(x).flatMap(f) == f(x)
如果左标识规则由List
支持,则以下内容应为真:
List(2).flatMap(e => e*e) == 4
但事实并非如此,如果您尝试上面的代码,编译器在编写代码时会呕吐。列表作为数据结构不是单子,但Scala的列表实现了flatMap这一事实赋予了它单子的超能力。它还需要满足,左单位和右单位定律,才能成为单子。没有魔法。只有法律。我想你会喜欢这个链接@hasumedia,谢谢你的评论和链接。希望这有帮助:我们可以把“Scala列表”叫做monad,对吗?因为Scala中的List实现了两个方法,它们构成了monad定义。谢谢。这是明信片。您的示例失败,因为e=>e*e
没有正确的类型flatMap
函数参数。也就是说,您正在传递一个Int=>Intunit(x).flatMap(f) == f(x)
List(2).flatMap(e => e*e) == 4