бесформенный фильтр список опций - PullRequest
0 голосов
/ 27 ноября 2018

Я новичок в бесформенном и пытаюсь решить следующую проблему.У меня есть кортежи разной длины с Option [(R [A], A)] в качестве элементов, и я хотел бы отфильтровать кортеж так, чтобы он приводил только к Some.Обратите внимание, что у меня нет Some или None во время компиляции, а только Option.Думаю, у меня рекурсивная проблема, но я не могу ее описать.Я имею в виду что-то вроде следующего (где я уже преобразовал кортеж в HList:

def performFinalStep[A1](t: Tuple1[A1]) = ???
def performFinalStep[A1, A2](t: Tuple2[A1, A2]) = ???
...

def reduce[T <: HList, A <: HList](l: Option[(R[A], A)] :: T, acc: A) = {
  case h :: HNil => performFinalStep(toTuple(h :: acc))
  case h :: t => reduce(t, h :: acc) //does not work as it is not known if T's head is Option[(R[A], A)]
}

reduce((Option(R(1), 2), Option(R("S", "s"))).productElements, HNil)

Есть две вещи, которые я не знаю, как мне превратить HList обратно в кортеж икак я могу преодолеть набор текста для T?

1 Ответ

0 голосов
/ 28 ноября 2018

В Shapeless преобразование классов наблюдения в HLists и наоборот может быть выполнено через shapeless.Generic.А в Scala Tuple есть тематические классы.Но есть стандартный способ

(1 :: "a" :: true :: HNil).tupled // (1,a,true)

import shapeless.ops.hlist.Tupler
def toTuple[L <: HList](l : L)(implicit tupler: Tupler[L]): tupler.Out = l.tupled

Когда вы не можете выразить что-либо с помощью метода, вы создаете класс типов (я не знаю ваш фактический тип вместо Nothing)

case class R[A](a: A)

trait Reduce[L <: HList, Acc <: HList] {
  def apply(l: L, acc: Acc): Nothing
}

object Reduce {
  implicit def singletonCase[A, Acc <: HList](implicit
    tupler: Tupler[Option[(R[A], A)] :: Acc]): Reduce[Option[(R[A], A)] :: HNil, Acc] =
    (l, acc) => l match {
      case h :: HNil => performFinalStep(toTuple(h :: acc))
    }

  implicit def notSingletonCase[H, T <: HList, Acc <: HList](implicit
    reduce: Reduce[T, H :: Acc]): Reduce[H :: T, Acc] =
    (l, acc) => l match {
      case h :: t => reduce(t, h :: acc)
    }
}

def reduce[L <: HList, Acc <: HList](l: L, acc: Acc)(implicit 
  r: Reduce[L, Acc]): Nothing  = r(l, acc)

Следующая проблема

Error:(39, 27) overloaded method value performFinalStep with alternatives:
  [A1, A2](t: (A1, A2))Nothing <and>
  [A1](t: (A1,))Nothing
 cannot be applied to (tupler.Out)
        case h :: HNil => performFinalStep(toTuple(h :: acc))

Вы можете попробовать еще один класс типов

trait PerformFinalStep[P <: Product] {
  def apply(t: P): Nothing
}

object PerformFinalStep {
  implicit def tuple1[A1]: PerformFinalStep[Tuple1[A1]] = t => ???
  implicit def tuple2[A1, A2]: PerformFinalStep[Tuple2[A1, A2]] = t => ???
  // ...
}

def performFinalStep[T <: Product](t: T)(implicit 
  pfs: PerformFinalStep[T]) = pfs(t)

trait Reduce[L <: HList, Acc <: HList] {
  def apply(l: L, acc: Acc): Nothing
}

object Reduce {
  implicit def singletonCase[A, Acc <: HList, P <: Product](implicit
    tupler: Tupler.Aux[Option[(R[A], A)] :: Acc, P],
    pfs: PerformFinalStep[P]): Reduce[Option[(R[A], A)] :: HNil, Acc] =
    (l, acc) => l match {
      case h :: HNil => performFinalStep(toTuple(h :: acc))
    }

  implicit def notSingletonCase[H, T <: HList, Acc <: HList](implicit
    reduce: Reduce[T, H :: Acc]): Reduce[H :: T, Acc] =
    (l, acc) => l match {
      case h :: t => reduce(t, h :: acc)
    }
}

def reduce[L <: HList, Acc <: HList](l: L, acc: Acc)(implicit 
  r: Reduce[L, Acc]): Nothing  = r(l, acc)

Теперь reduce((Option(R(1), 2), Option(R("S"), "s")).productElements, HNil) производит "не удалось найти неявное значение для параметра", но implicitly[Reduce[Option[(R[Int], Int)] :: Option[(R[String], String)] :: HNil, HNil]] компилируется,Если мы подставим явно

reduce((Option(R(1), 2), Option(R("S"), "s")).productElements, HNil)(
  implicitly[Reduce[Option[(R[Int], Int)] :: Option[(R[String], String)] :: HNil, HNil]]
)

, у нас будет

Error:(52, 82) type mismatch;
 found   : Reduce[Option[(R[Int], Int)] :: Option[(R[String], String)] :: shapeless.HNil,shapeless.HNil]
 required: Reduce[Option[(R[Int], Int)] :: Option[(R[String], String)] :: shapeless.HNil,shapeless.HNil.type]
Note: shapeless.HNil >: shapeless.HNil.type, but trait Reduce is invariant in type Acc.
You may wish to define Acc as -Acc instead. (SLS 4.5)
  reduce((Option(R(1), 2), Option(R("S"), "s")).productElements, HNil)(implicitly[Reduce[Option[(R[Int], Int)] :: Option[(R[String], String)] :: HNil, HNil]])

Так что вы должны назвать его как

reduce((Option(R(1), 2), Option(R("S"), "s")).productElements, HNil : HNil)
...