这个问题并不意味着火焰诱饵!可能很明显,我最近一直在关注Scalaz。我正在尝试理解为什么我需要库提供的一些功能。这是:
import scalaz._
import Scalaz._
type NEL[A] = NonEmptyList[A]
val NEL = NonEmptyList
我在我的函数中放了一些println语句来查看发生了什么(除了:如果我试图避免这样的副作用,我会怎么做?)。我的职责是:
val f: NEL[Int] => String = (l: NEL[Int]) => {println("f: " + l); l.toString |+| "X" }
val g: NEL[String] => BigInt = (l: NEL[String]) => {println("g: " + l); BigInt(l.map(_.length).sum) }
然后我通过 cokleisli 合并它们并传入NEL[Int]
val k = cokleisli(f) =>= cokleisli(g)
println("RES: " + k( NEL(1, 2, 3) ))
这是什么印刷品?
f: NonEmptyList(1, 2, 3)
f: NonEmptyList(2, 3)
f: NonEmptyList(3)
g: NonEmptyList(NonEmptyList(1, 2, 3)X, NonEmptyList(2, 3)X, NonEmptyList(3)X)
RES: 57
RES值是最终NEL中(String)元素的字符数。我发生了两件事:
对于像 retronym 这样的可爱的人来解释这个强大的图书馆实际上是如何工作的,这个问题是一个简单的恳求。
答案 0 :(得分:18)
要了解结果,您需要了解Comonad[NonEmptyList]
实例。 Comonad[W]
本质上提供了三个函数(Scalaz中的实际接口有点不同,但这有助于解释):
map: (A => B) => W[A] => W[B]
copure: W[A] => A
cojoin: W[A] => W[W[A]]
因此,Comonad
为某个容器W
提供了一个接口,该容器具有一个独特的“head”元素(copure
)以及一种暴露容器内部结构的方式,以便我们每个元素获得一个容器(cojoin
),每个元素的头部都有一个给定的元素。
NonEmptyList
实现此方法的方法是copure
返回列表的头部,cojoin
返回列表列表,此列表位于头部和所有尾部这个清单的尾部。
示例(我将NonEmptyList
缩短为Nel
):
Nel(1,2,3).copure = 1
Nel(1,2,3).cojoin = Nel(Nel(1,2,3),Nel(2,3),Nel(3))
=>=
函数是coKleisli组合。你如何构成两个函数f: W[A] => B
和g: W[B] => C
,除了W
是Comonad
之外,对它们一无所知?输入类型f
和输出类型g
不兼容。但是,您可以map(f)
获取W[W[A]] => W[B]
,然后使用g
撰写。W[A]
。现在,给定cojoin
,您可以W[W[A]]
将k
提供给该功能。因此,唯一合理的组合是函数k(x) = g(x.cojoin.map(f))
,它执行以下操作:
g(Nel(1,2,3).cojoin.map(f))
= g(Nel(Nel(1,2,3),Nel(2,3),Nel(3)).map(f))
= g(Nel("Nel(1,2,3)X","Nel(2,3)X","Nel(3)X"))
= BigInt(Nel("Nel(1,2,3)X","Nel(2,3)X","Nel(3)X").map(_.length).sum)
= BigInt(Nel(11,9,7).sum)
= 27
所以对于你的非空列表:
{{1}}
答案 1 :(得分:9)
Cojoin也定义为scalaz.Tree和scalaz.TreeLoc。这可以是exploited来查找从树的根到每个叶节点的所有路径的流。
def leafPaths[T](tree: Tree[T]): Stream[Stream[T]]
= tree.loc.cojoin.toTree.flatten.filter(_.isLeaf).map(_.path)
使用coKleisli箭头组合,我们可以这样做,例如:
def leafDist[A] = (cokleisli(leafPaths[A]) &&& cokleisli(_.rootLabel))
=>= (_.map(s => (s._2, s._1.map(_.length).max)))
leafDist
接受一个树并返回一个树的副本,每个节点都注明了它与叶子的最大距离。