как вызвать фильтр на обоих секвенсорах - PullRequest
0 голосов
/ 25 февраля 2020

Я бы хотел создать метод, который бы использовал вектор или последовательность некоторого типа, скажем, Int, и вызывал фильтр для него.

Например:

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
  }

Ответы [ 2 ]

2 голосов
/ 25 февраля 2020

Это предлагаемый тип typeclas .
Мой совет будет использовать определенные c типы, такие как 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)

Кстати, стоит упомянуть, что такой класс типов уже существует у кошек

1 голос
/ 25 февраля 2020

TraversableLike.filter возвращает Repr, то есть тип, передаваемый в качестве параметра второго типа в TraversableLike. Вам нужно F[A] там вместо A. Это компилируется для меня:

implicit class SharedOps2[A,F[A]<:TraversableLike[A,F[A]]](xs: F[A])(implicit ev: OneOf[F[A], Seq[A] ::: Vector[A] ::: HSNil]) {
  def filter(x: A): F[A] = xs.filter({ a: A => a == x })
}

Обратите внимание, также тип a изменен на A, потому что это тип внутри F[A] collection.

fiddle

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...