我注意到Option
,OptionT
,fs2.Stream
之类的容器具有以下方法:
def collect[B](f: PartialFunction[A, B])(implicit F: Functor[F]): OptionT[F, B] =
OptionT(F.map(value)(_.collect(f)))
所以我很好奇是否存在类似Collectable
类型的类:
trait Collectable[F[_]] {
def collect[A, B](fa: F[A])(pf: PartialFunction[A, B]): F[B]
}
这对我来说似乎很有用,实现起来也很简单,但是无论如何,cats/scalaz
中已经包含类似功能的东西了吗?
答案 0 :(得分:3)
Foldable类型类似乎非常接近您想要的类型。它具有方法collectFirst
,具有以下签名:
def collectFirst[A, B](fa: F[A])(pf: PartialFunction[A, B]): Option[B] =
和一个奇怪的实现:
foldRight(fa, Eval.now(Option.empty[B])) { (a, lb) =>
// trick from TraversableOnce,
// used to avoid calling both isDefined and apply (or calling lift)
val x = pf.applyOrElse(a, sentinel)
if (x.asInstanceOf[AnyRef] ne sentinel) Eval.now(Some(x.asInstanceOf[B]))
else lb
}.value
其中sentinel
是一个奇怪的小函数,总是返回自身:
private val sentinel: Function1[Any, Any] =
new scala.runtime.AbstractFunction1[Any, Any]{
def apply(a: Any) = this
}
最后两个代码段应该提供一些动力,使它们不会多次重新实现collectFirst
。