首页 > 解决方案 > 如何在 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
  }

标签: scala

解决方案


这是建议的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)

顺便说一句,值得一提的是,这种类型类已经存在于猫中


推荐阅读