Складная "foldMap", которая принимает частичную функцию: foldCollect?
Скажем, у меня есть следующий объект:
case class MyFancyObject(a: String, b: Int, c : Vector[String])
И что мне нужно, чтобы получить один Vector[String]
содержащий все буквы "с", которые соответствуют данной частичной функции.
Например:
val xs = Vector(
MyFancyObject("test1",1,Vector("test1-1","test1-2","test1-3")),
MyFancyObject("test2",2,Vector("test2-1","test2-2","test2-3")),
MyFancyObject("test3",3,Vector("test3-1","test3-2","test3-3")),
MyFancyObject("test4",4,Vector("test4-1","test4-2","test4-3"))
)
val partialFunction1 : PartialFunction[MyFancyObject,Vector[String]] = {
case MyFancyObject(_,b,c) if b > 2 => c
}
Что мне нужно получить, это: Vector("test3-1","test3-2","test3-3","test4-1","test4-2","test4-3")
,
Я решил это, сделав следующее:
val res1 = xs.foldMap{
case MyFancyObject(_,b,c) if b > 2 => c
case _ => Vector.empty[String]
}
Однако это сделало меня любопытным. То, что я здесь делаю, казалось довольно обычной и естественной вещью: для каждого элемента складной коллекции попытайтесь применить частичную функцию и, если это не получится, по умолчанию использовать Monoid
"s empty
(Vector.empty
в моем случае). Я искал в библиотеке, и я не нашел ничего, что уже делало это, поэтому я добавил этот метод расширения в свой код:
implicit class FoldableExt[F[_], A](foldable : F[A]) {
def foldCollect[B](pF: PartialFunction[A, B])(implicit F : Foldable[F], B : Monoid[B]) : B = {
F.foldMap(foldable)(pF.applyOrElse(_, (_ : A) => B.empty))
}
}
Мой вопрос здесь:
Есть ли какая-то причина, по которой такой метод не был бы уже доступен? Это не общий и достаточно общий сценарий, или я что-то упустил?
1 ответ
Я думаю, что если вам действительно нужна частичная функция, вы не хотите, чтобы она просачивалась наружу, потому что ее не очень приятно использовать. Лучше всего, если вы хотите повторно использовать свой partialFunction1
это к lift
это сделать его полной функцией, которая возвращает Option
, Затем вы можете предоставить ваш случай по умолчанию в том же месте, где вы используете свою частичную функцию. Вот подход:
val res2 = xs.foldMap(partialFunction1.lift).getOrElse(Vector.empty)
foldMap(partialFunction1.lift)
возвращается Some(Vector(test3-1, test3-2, test3-3, test4-1, test4-2, test4-3))
, Это именно то, что у вас есть в res1
, но завернутый в Option
,