scala - 如何在 Seq 和 Vector 上调用过滤器
问题描述
我想创建一个方法,它采用某种类型的向量或序列,比如 Int,并在其上调用 filter。
例如:
implicit class SharedOps[F](xs: F)(implicit ev: OneOf[F, Seq[Int] ::: Vector[Int] ::: HSNil]) {
def filter(x: Int):F = xs.filter({a:Int => a == x})
}
OneOf 基本上检查 F 是 Seq[Int] 还是 Vector[Int]
棘手的部分是我希望过滤器返回与输入相同的类型(例如 Seq[Int] 或 Vector[Int]),但编译器抱怨
error: type mismatch;
found : scala.this.Function1[scala.this.Int,scala.this.Boolean]
required: scala.this.Int
def filter(x: Int):F = xs.filter({a:Int => a == x})
不知何故,编译器忘记了我从一个集合开始,并认为 xs 是一个单一的东西。
所以我改变了设计:
implicit class SharedOps2[A,F[A]<:TraversableLike[A,A]](xs: F[A])(implicit ev: OneOf[F[A], Seq[Int] ::: Vector[Int] ::: HSNil]) {
def filter(x: A): F[A] = xs.filter({ a: Int => a == x })
}
现在编译器抱怨: A 类型的表达式不符合预期的 F[A] 类型
不知道如何从这里拿走它。在这一点上,我想避免无形的副产品。
为了完整起见,这里是 OneOf 代码:
sealed trait HSubset // HList
@implicitNotFound("No member of type class HSubset in scope for ${H}")
trait :::[+H, +T <: HSubset] extends HSubset // HCons ::
sealed trait HSNil extends HSubset // HNil
@implicitNotFound("No member of type class BelongsTo in scope for ${T}")
trait BelongsTo[T, U <: HSubset]
object BelongsTo {
implicit def baseCase[H, U <: HSubset]: BelongsTo[H, H ::: U] = null
implicit def recursiveCase[H, U <: HSubset, T](implicit ev: T BelongsTo U): T BelongsTo (H ::: U) = null
}
@implicitNotFound("No member of type class SubsetOf in scope for ${U} ${T}")
trait SubsetOf[U <: HSubset, T <: HSubset]
object SubsetOf {
implicit def baseCase[U1, U <: HSubset](implicit s: U1 BelongsTo U): SubsetOf[U1 ::: HSNil, U] = null
implicit def recursiveCase[U <: HSubset, T1, T <: HSubset](implicit ev1: T1 BelongsTo U, ev2: T SubsetOf U): (T1 ::: T) SubsetOf U = null
}
trait OneOf[T, U <: HSubset]
object OneOf {
implicit def baseCase[U <: HSubset, T](implicit s: T BelongsTo U): T OneOf U = null
implicit def recursiveCase[T, Ev <: HSubset, Target <: HSubset](implicit ev1: T OneOf Ev, ev2: Ev SubsetOf Target): T OneOf Target = null
}
解决方案
这是建议的typeclas。
我的建议是使用特定类型,例如List
&Vector
而不是Seq
.
trait Filter[F[_]] {
def filter[A](fa: F[A])(p: A => Boolean): F[A]
}
object Filter {
implicit final val VectorFilter: Filter[Vector] =
new Filter[Vector] {
override final def filter[A](vector: Vector[A])(p: A => Boolean): Vector[A] =
vector.filter(p)
}
implicit final val SeqFilter: Filter[Seq] =
new Filter[Seq] {
override final def filter[A](seq: Seq[A])(p: A => Boolean): Seq[A] =
seq.filter(p)
}
}
object syntax {
object filter {
implicit class FilterOps[F[_], A](private val fa: F[A]) extends AnyVal {
@inline
final def filter(p: A => Boolean)(implicit ev: Filter[F]): F[A] =
ev.filter(fa)(p)
}
}
}
import syntax.filter._
def foo[F[_] : Filter](xs: F[Int]): F[Int] =
xs.filter(i => (i % 2) == 0)
您可以使用如下:
foo(Vector(1, 2, 3))
// res: Vector[Int] = Vector(2)
foo(List(1, 2, 3))
// could not find implicit value for evidence parameter of type ammonite.$sess.cmd0.Filter[List]
foo(Seq(1, 2, 3))
// res: Seq[Int] = List(2)
顺便说一句,值得一提的是,这种类型类已经存在于猫中
推荐阅读
- http - 有没有办法在网站上查询大小写不正确的网址?
- react-admin - DateTimeInput 将空对象发送到 graphql 端点
- javascript - 如何在渲染之前将属性添加到通过 props- 传递的 HTML 标签?
- c# - SaveChanges 方法在 EntityFramework 中如何工作?
- haskell - 在 Haskell 中作为参数的自然变换
- python - 嵌套 for 循环仅在第一次迭代时运行
- html - Firefox 在 ::after 元素中截断文本
- ruby-on-rails - Rails/SimpleForm:如何为两组嵌套属性指定参数?
- uwp - 获取根存储文件夹中的所有存储文件和所有子存储文件夹中的所有项目
- r - 我如何在 R 中制作核矩阵