无形过滤器选项列表 [英] shapeless filter a list of options

查看:57
本文介绍了无形过滤器选项列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 shapeless 的新手,并尝试解决以下问题.我有不同长度的元组,以 Option[(R[A], A)] 作为元素,并希望对元组进行某种过滤,以便它只产生 Some.请注意,我在编译时没有 Some 或 None ,只有 Option .我想我有一个递归问题,但无法描述它.我有如下想法(我已经将元组转换为 HList:

I am new to shapeless and try to tackle the following problem. I have tuples of different length with Option[(R[A], A)] as elements and would like to kind of filter the tuple so that it results only in Some. Notice that I don't have Some or None at compile time but only Option. I think I have kind of a recursive problem but cannot describe it. I have something like the following in mind (where I have already converted the tuple into an 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 的输入问题?

There are two things I don't know, how do I turn an HList back into a tuple and how can I overcome the typing for T?

推荐答案

在 Shapeless 中,可以通过 shapeless.Generic 将 case 类转换为 HLists,反之亦然.在 Scala 中,Tuple 是 case 类.但是有标准的方式

In Shapeless converting case classes to HLists and vice versa can be done via shapeless.Generic. And in Scala Tuples are case classes. But there is standard way

(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)

When you can't express something with a method you create a type class (I don't know your actual type instead of 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))

您可以再尝试一种类型类

You can try one more type class

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) 产生找不到隐式值for parameter" 但是 隐式地[Reduce[Option[(R[Int], Int)] :: Option[(R[String], String)] :: HNil, HNil]] 编译.如果我们明确替换

Now reduce((Option(R(1), 2), Option(R("S"), "s")).productElements, HNil) produces "could not find implicit value for parameter" but implicitly[Reduce[Option[(R[Int], Int)] :: Option[(R[String], String)] :: HNil, HNil]] compiles. If we substitute explicitly

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)

这篇关于无形过滤器选项列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆