我试图理解自由单体的概念,我在第一句话上就被绊住了。猫科医生 指出
自由单体是一种结构,它允许你建立一个单体。从任何一个Functor
我的困惑主要在于,在 "释放 "ADT的过程中,并没有使用/created的任何漏斗,以实现 "自由"。KVStoreA
. 没有实现ADT的functor或类似的东西。但是,在文档中,对 Free[S[_],A]
说 S
我必须是一个漏斗者。
某个漏斗的自由操作单子
S
.
自由单体应该基于的那个漏斗在哪里?
问题是,Free monad可以用几种不同的方式来使用。为了使用其中一种方式,你需要假设你有一些漏斗器 S[_]
,它将有一些 Functor[S]
定义的,你将解除 S[*]
到 Free[S, *]
通过允许某种形式的扩展到原来的 S
:
Free[S, A] = S[A] or A
这不是有效的Scala! 它的实际实现方式是使用 ADT. 这只是作为一种理念的解释。
这样,如果你有 S[A]
而你 map
它 f: A => B
您可以使用 Functor[S]
并接受 S[B]
. 但如果你 flatMap
它 f: A => Free[S, B]
......你仍然可以用以下方法来计算 Functor[S]
并接受 S[Free[S, B]]
. 这就是下面这段代码的作用。记住 Free[S, A] = S[A] or A
你可以看到,这将变成 S[S[S[...]]]
如果不是因为这样,它可以无限地嵌套下去 or A
一部分 Free[S, A]
这将让我们在某个时间点停止。
当然我们不会一次计算完毕,Free通常使用trampoline一次只计算一件事,所以我们不会一次就有大量的嵌套结束。
sealed abstract class Free[S[_], A] extends Product with Serializable {
// ...
}
object Free extends FreeInstances {
/**
* Return from the computation with the given value.
*/
final private[free] case class Pure[S[_], A](a: A) extends Free[S, A]
/** Suspend the computation with the given suspension. */
final private[free] case class Suspend[S[_], A](a: S[A]) extends Free[S, A]
/** Call a subroutine and continue with the given function. */
final private[free] case class FlatMapped[S[_], B, C](c: Free[S, C], f: C => Free[S, B]) extends Free[S, B]
...
}
这个trampoline的表示方法实现了与
S[A] or A
但它允许一步一步地运行计算。它还表明Free[S, *]
是S[*]
代数pure
和flatMap
操作(对S不做任何假设),这就证明了Free是一个合理的 自由代数.
实际上,在我们决定运行计算之前,我们只有懒惰评估的数据结构。运行它的一种方法是调用 free.run
你 在猫咪中定义为 "免费"。 - 它将使用蹦蹦床来评估这个巢穴的每一个,一次一个,但随后它将使用 Comonad[S]
来提取值--因此我们会在走的时候去掉嵌套。Comonad[S]
也是 Functor[S]
这就是为什么我们不需要单独提供它来做所有这些。map
s.
但这是一种运行方式。另一种方式是假设我们记录的是... map
, flatMap
和 pure
操作使用 Free
. 为此,我们不需要 Functor[S]
根本没有。我们可以决定 run
用事 Comonad[S]
但我们也可以决定一些其他的事情。如果我们翻译成 S[_]
对某些 M[_]
但我们知道,这 M[_]
有 Monad[M]
? 在这种情况下,我们就不必使用 Functor[S]
根本不可能! 我们将运行翻译 S ~> M
然后,在其上绘制地图或平面地图,并在其上绘制 S
里面的内容会用同样的 S ~> M
机制。这就是 foldMap
是否 - 它要求我们提供一个自然的转变 S ~> M
和实例 Monad[M]
和 Functor[S]
是完全没有必要的。虽然在概念上我们仍然可以认为 S
作为一个漏斗器,我们不需要依赖任何漏斗器的属性,而不是以 Functor[S]
.
所以最后回答你的问题--当我们还在 "记录操作 "的阶段时,我们不必假设,Free S
是一个漏斗,所以我们不需要用 Functor[S]
. 当我们想解释 Free[S, A]
到一些东西中--这就是可能真正需要 functor 的地方,例如,如果我们想运行 Free[S, A]
变成 A
. 但对于一些解释,例如 foldMap
(这是我认为最流行的解释之一),这是不需要的,因为我们把 S
作为一个纯数据。