我正在学习函数式编程,并且有一些(可能很明显,但不适合我:))关于monad的问题。每个monad都是一个应用函子。应用仿函数又可以定义为高级类型,如下所示(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)
相同?是应用仿函数法还是其他原因?你能解释一下吗?
答案 0 :(得分:8)
它遵循Traversable算子的定律。
首先,要意识到_.foldMap(nt)
本身就是从MyFree
到Id
的自然转换。此外,通过对自由monad的含义的定义,它必须是 monad同态 1 (对于任何nt
)。< / p>
让我们从您的
开始reverseApList(lst).foldMap(nt)
也可以写成
lst.sequence.foldMap(nt)
现在我们将应用naturality law of Traversable functors,_.foldMap(nt)
作为自然转换nat
。为了适用它,我们的自然变换必须是 applicative homomorphism ,由the two extra conditions表示。但我们已经知道,我们的自然变换是一个单子同态,它比应用同态更强(保留更多的结构)。因此,我们可以继续适用这项法律并获得
lst.map(_.foldMap(nt)).sequence : Id[List[Int]]
现在只使用链接的scalaz文件中的规则,可证明(尽管以迂回方式),最后sequence
到Id
实际上是无操作。我们得到
lst.map(_.foldMap(nt)) : List[Id[Int]]
这是我们想要展示的内容。
1 :自然变换h: M ~> N
是monad同态,如果它保留了monadic结构,即它是否满足
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)))