List 是如何成为 monad 的?
How is List a monad?
我认为我对 Monad 和 monadic 操作有基本的了解,但在理解如何将 monadic 类型的神奇功能添加到基础类型上仍然有点困惑(希望这是有道理的)。
例如,我 was reading 关于 List[T]
如何成为 monad。但是,如果我 flatMap
和 map
在 for
理解中顺序地处理一些列表,那么 flatMap
和 map
是否真的提供了 monadic 魔法?
如果我创建一个 List<String>
那么如何添加 monadic 魔法?还是 List<T>
在 Scala 中总是一个 monad,因为它恰好是该语言已经为其提供内置 monadic 支持的那些容器之一?
Monad
是一个 概念 而不是 class 或特征。
因此 List[T]
满足 monad https://en.wikipedia.org/wiki/Monad_(functional_programming) 的所有要求,它可以被称为 monadic
。
说白了就是monad,因为它具备monad提供的所有功能和能力,所以它是monad。
如果你想要更多的保证并更明确地表达成为一个单子你可以使用Scalaz
。
link 展示了如何并详细介绍了 monad 法则:http://eed3si9n.com/learning-scalaz/Monad+laws.html
你完全正确 flatMap
和 map
提供 "monadic magic." 幸运的是或不幸的是(取决于你看到了多少糟糕的代码)在编程。再多的抽象也无法使您(或其他人)免于最终编写出您想要的代码。抽象 "just" 让您可以重复使用以前编写的代码并阐明您对问题的想法。那么 monad 只是一个概念、一个想法、一个抽象等等。
在 Scala 的情况下,这实际上就是编译器对 for
推导所做的,它变成了一系列 flatMap
、map
、withFilter
,和 filter
语句。
一个 monad(在 Scala 中)可以被认为只是一个标签,你碰巧有一个类型构造函数 T[_]
和两个函数 1
def f0[A](x: T[A], f: X => T[A]): T[A]
def f1[A](x: A): T[A]
按照惯例,当他们看到这种现象时,Scala 社区会调用 f0
flatMap
并且通常使它成为一种方法,以便 x
始终是父 class 而不是单独的参数。还有一个约定叫 f1
point
或 pure
(参见 scalaz
或 cats
)。 f1
通常也是一种方法,这样它就不会显式地接受参数而只是使用其父 class 作为 x
.
每当有人说 "such-and-such" 是一个单子时,总会有一个隐含的 f0
和 f1
说话者希望听众推断出来。严格来说,“List
是一个单子”是对术语的轻度滥用。它是 List
的简写,连同函数 (xs: List[A], f: A => List[A]) => xs.map(f).flatten
(形成 f0
)和 (x: A) => List(x)
(形成 f1
)形成一个 monad。或者稍微不那么迟钝,List
连同列表上的标准 flatMap
和 List.apply
构造函数形成一个 monad。
因此从来没有任何魔法。作为 class 将某物化为 Monad
的一部分,您必须提供 flatMap
和 pure
.
的概念
有很多方法可以将这种抽象的 monad 转化为代码。天真的方法(即没有第三方库的 Scala)只是就 f0
和 f1
(例如 flatMap
)的通用名称达成一致,并仅命名具有适当名称的方法类型签名那些名字。这基本上就是 scalac
期望你为 for
理解做的事情。您可以更进一步,尝试使用 trait
或 abstract class
将事物形式化。也许称它为 Monad
是为了可爱并拥有类似以下的东西:
trait Monad[A] {
def flatMap(f: A => Monad[A]): Monad[A]
def pure(x: A): Monad[A]
}
然后你可以将任何扩展这个 Monad
的东西称为 monad 思想的实现(你可以想象像 class List[A] extends Monad[A]
这样的东西)。
由于各种实际原因,结果证明这不太令人满意,因此您最终得到了通常的解决方案,看起来像(挥手消除了许多其他复杂性)
trait Monad[F[_]] {
def flatMap[A](f: A => F[A]): F[A]
def pure[A](x: A): F[A]
}
由 implicit
s 实施。
脚注:
- 还有一些 laws/conventions 管理他们的互动。这些定律存在的实际原因是让程序员的生活保持理智,这样他们就知道当有人告诉他们这些函数是 "monadic." 时会发生什么 "monadic."但我不会在这里深入研究它们,因为它们在其他地方有充分的解释。
从纯粹的角度来看,List
可能不是一个monad。至少那是我基于左身份规则的看法:
unit(x).flatMap(f) == f(x)
如果 List
支持左恒等式规则,则下列情况应为真:
List(2).flatMap(e => e*e) == 4
但事实并非如此,如果您尝试上面的代码,编译器会在您编码时呕吐。
我认为我对 Monad 和 monadic 操作有基本的了解,但在理解如何将 monadic 类型的神奇功能添加到基础类型上仍然有点困惑(希望这是有道理的)。
例如,我 was reading 关于 List[T]
如何成为 monad。但是,如果我 flatMap
和 map
在 for
理解中顺序地处理一些列表,那么 flatMap
和 map
是否真的提供了 monadic 魔法?
如果我创建一个 List<String>
那么如何添加 monadic 魔法?还是 List<T>
在 Scala 中总是一个 monad,因为它恰好是该语言已经为其提供内置 monadic 支持的那些容器之一?
Monad
是一个 概念 而不是 class 或特征。
因此 List[T]
满足 monad https://en.wikipedia.org/wiki/Monad_(functional_programming) 的所有要求,它可以被称为 monadic
。
说白了就是monad,因为它具备monad提供的所有功能和能力,所以它是monad。
如果你想要更多的保证并更明确地表达成为一个单子你可以使用Scalaz
。
link 展示了如何并详细介绍了 monad 法则:http://eed3si9n.com/learning-scalaz/Monad+laws.html
你完全正确 flatMap
和 map
提供 "monadic magic." 幸运的是或不幸的是(取决于你看到了多少糟糕的代码)在编程。再多的抽象也无法使您(或其他人)免于最终编写出您想要的代码。抽象 "just" 让您可以重复使用以前编写的代码并阐明您对问题的想法。那么 monad 只是一个概念、一个想法、一个抽象等等。
在 Scala 的情况下,这实际上就是编译器对 for
推导所做的,它变成了一系列 flatMap
、map
、withFilter
,和 filter
语句。
一个 monad(在 Scala 中)可以被认为只是一个标签,你碰巧有一个类型构造函数 T[_]
和两个函数 1
def f0[A](x: T[A], f: X => T[A]): T[A]
def f1[A](x: A): T[A]
按照惯例,当他们看到这种现象时,Scala 社区会调用 f0
flatMap
并且通常使它成为一种方法,以便 x
始终是父 class 而不是单独的参数。还有一个约定叫 f1
point
或 pure
(参见 scalaz
或 cats
)。 f1
通常也是一种方法,这样它就不会显式地接受参数而只是使用其父 class 作为 x
.
每当有人说 "such-and-such" 是一个单子时,总会有一个隐含的 f0
和 f1
说话者希望听众推断出来。严格来说,“List
是一个单子”是对术语的轻度滥用。它是 List
的简写,连同函数 (xs: List[A], f: A => List[A]) => xs.map(f).flatten
(形成 f0
)和 (x: A) => List(x)
(形成 f1
)形成一个 monad。或者稍微不那么迟钝,List
连同列表上的标准 flatMap
和 List.apply
构造函数形成一个 monad。
因此从来没有任何魔法。作为 class 将某物化为 Monad
的一部分,您必须提供 flatMap
和 pure
.
有很多方法可以将这种抽象的 monad 转化为代码。天真的方法(即没有第三方库的 Scala)只是就 f0
和 f1
(例如 flatMap
)的通用名称达成一致,并仅命名具有适当名称的方法类型签名那些名字。这基本上就是 scalac
期望你为 for
理解做的事情。您可以更进一步,尝试使用 trait
或 abstract class
将事物形式化。也许称它为 Monad
是为了可爱并拥有类似以下的东西:
trait Monad[A] {
def flatMap(f: A => Monad[A]): Monad[A]
def pure(x: A): Monad[A]
}
然后你可以将任何扩展这个 Monad
的东西称为 monad 思想的实现(你可以想象像 class List[A] extends Monad[A]
这样的东西)。
由于各种实际原因,结果证明这不太令人满意,因此您最终得到了通常的解决方案,看起来像(挥手消除了许多其他复杂性)
trait Monad[F[_]] {
def flatMap[A](f: A => F[A]): F[A]
def pure[A](x: A): F[A]
}
由 implicit
s 实施。
脚注:
- 还有一些 laws/conventions 管理他们的互动。这些定律存在的实际原因是让程序员的生活保持理智,这样他们就知道当有人告诉他们这些函数是 "monadic." 时会发生什么 "monadic."但我不会在这里深入研究它们,因为它们在其他地方有充分的解释。
从纯粹的角度来看,List
可能不是一个monad。至少那是我基于左身份规则的看法:
unit(x).flatMap(f) == f(x)
如果 List
支持左恒等式规则,则下列情况应为真:
List(2).flatMap(e => e*e) == 4
但事实并非如此,如果您尝试上面的代码,编译器会在您编码时呕吐。