Складная "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,

Другие вопросы по тегам