解释自由 monad 列表与解释列表的自由 monad

Interpreting a list of free monads vs. interpreting a free monad of a list

我正在学习函数式编程并且有一些(可能很明显,但对我来说不是:))关于 monad 的问题。每个 monad 都是一个应用函子。 Applicative functor 又可以定义为更高种类的类型,如下所示(pure 方法省略):

trait ApplicativeFunctor[F[_]]{
   def ap[A](fa: F[A])(f: F[A => B]): F[B]
}

据我了解,这个类型类意味着我们可以取 F[A]F[B] 的两个值和一个函数 (A, B) => C 并构造 F[C]

这个属性使我们能够构造列表反转函数:

def reverseApList[F[_]: ApplicativeFunctor, A](lst: List[F[A]]): F[List[A]] 

让我们有

trait SomeType[A]

现在考虑

type MyFree[A] = Free[SomeType, A] 
val nt: NaturalTransformation[SomeType, Id]
val lst: List[MyFree[Int]]

问题: 为什么 lst.map(_.foldMap(nt))reverseApList(lst).foldMap(nt) 相同?它是遵循适用函子定律还是有其他原因?能解释一下吗?

它遵循 Traversable 函子的定律。

首先,要认识到 _.foldMap(nt) 本身就是从 MyFreeId 的自然转换。此外,根据自由单子的定义,它必须是 单子同态1(对于任何 nt).

让我们从您的

开始
reverseApList(lst).foldMap(nt)

也可以写成

lst.sequence.foldMap(nt)

现在我们要应用 naturality law of Traversable functors, with _.foldMap(nt) as the natural transformation nat. For it to be applicable, our natural transformation has to be an applicative homomorphism, which is expressed by the two extra conditions。但是我们已经知道我们的自然变换是单子同态,它比应用同态更强(保留更多结构)。因此,我们可能会继续应用此法律并获得

lst.map(_.foldMap(nt)).sequence : Id[List[Int]]

现在仅使用链接的 scalaz 文件中的定律就可以证明(尽管以迂回的方式)最后 sequenceId 实际上是 no-op。我们得到

lst.map(_.foldMap(nt))          : List[Id[Int]]

这就是我们想要展示的。


1 :自然变换 h: M ~> N 是单子同态,如果它保留单子结构,即如果它满足

  • 对于任何 a: A:
    h(Monad[M].point[A](a)) = Monad[N].point[A](a)
  • 对于任何 ma: M[A]f: A => M[B]:
    h(ma.flatMap(f)) = h(ma).flatMap(a => h(f(a)))