问题
Ive found myself in the situation a couple of times where i have a reducer / combine fn like so:
def combiner(a: String, b: String): Either[String, String] = {
(a + b).asRight[String]
}
Its a dummy implementation but the fn can fail so it returns an either. I then I have a list of values I want to pass through this with reduce / fold. The best I can come up with (assuming the List's type is a monoid) is this:
def combine(items: Vector[String]) = {
items.foldLeft(Monoid[String].empty.asRight[String]) { case (acc, value) =>
acc.flatMap( accStr => combiner(accStr, value))
}
}
Its a bit clumsy and as its a fairly generic pattern I suspect there's a better way to do it using cats.
回答1:
You might want to take a look at foldM. Your code would then look approximately like this:
Foldable[Vector].foldM(items, "")(combiner)
The foldM
method has the signature
def foldM[G[_], A, B](fa: F[A], z: B)(f: (B, A) ⇒ G[B])(implicit G: Monad[G]): G[B]
so in your case, the type(-constructor) parameters would unify as follows:
G[X] = Either[String, ?]
A = String
B = String
F[X] = Vector[X]
so that f: (A, B) => G[B]
would become f: (String, String) => Either[String, String]
, which is exactly the type of combiner
when it's converted into a function.
来源:https://stackoverflow.com/questions/56451987/reduce-fold-over-list-of-monoid-but-reducer-returns-either