可以说我有以下免费的单子定义:
sealed trait SetOpsA[A]
case class AllSetNames() extends SetOpsA[Set[String]]
case class IdsFromSet(setName: String) extends SetOpsA[Set[String]]
object SetOps {
type SetOps[A] = Free[SetOpsA, A]
def allSetNames(): SetOps[Set[String]] =
liftF[SetOpsA, Set[String]](AllSetNames())
def idsFromSet(setName: String): SetOps[Set[String]] =
liftF[SetOpsA, Set[String]](IdsFromSet(setName))
}
现在我想检索所有集合名称,然后为每个集合名称执行 idsFromSet 操作。
我会这样描述它:
val prog = for {
allSetNames <- allSetNames()
setName <- allSetNames
ids <- idsFromSet(setName)
} yield ids
但这是不可能的,因为单子不能混入理解中。所以在'setName <- allSetNames'这一行上,编译器抱怨它被赋予了一个Set并且它想要一个Free。
通过环顾四周,单子变压器似乎是要走的路。但是有了这些信息,我真的迷失了,因为我能找到的带有 monad 转换器的示例似乎与我的示例相距太远,或者解释太抽象而无法在此示例中实现。因此,我们将不胜感激。
编辑:我更进一步,可以通过这样做来实现我的结果(我也意识到我想要扁平的 id,而不是 id 的集合):
val prog = for {
allSetNames <- allSetNames()
ids <- allSetNames.toList.traverseU(idsFromSet)
} yield ids.flatten