Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 类型列表上的类型级别映射_Scala_Shapeless_Type Level Computation - Fatal编程技术网

Scala 类型列表上的类型级别映射

Scala 类型列表上的类型级别映射,scala,shapeless,type-level-computation,Scala,Shapeless,Type Level Computation,我有一个助手函数: def findByType[T: ClassTag](xs: Seq[Any]) = xs.find(classTag[T].runtimeClass.isInstance).map(_.asInstanceOf[T]) 我现在使用的是: val foo = findByType[Foo](xs) val bar = findByType[Bar](xs) val baz = findByType[Baz](xs) trait Sifter[L <: HLis

我有一个助手函数:

def findByType[T: ClassTag](xs: Seq[Any]) =
  xs.find(classTag[T].runtimeClass.isInstance).map(_.asInstanceOf[T])
我现在使用的是:

val foo = findByType[Foo](xs)
val bar = findByType[Bar](xs)
val baz = findByType[Baz](xs)
trait Sifter[L <: HList] extends DepFn1[Seq[Any]] {
  type Out <: HList
}

object Sifter {
  type Aux[L <: HList, Out0 <: HList] = Sifter[L] { type Out = Out0 }

  implicit def emptySized: Aux[HNil, HNil] = new Sifter[HNil] {
    type Out = HNil
    def apply(xs: Seq[Any]) = HNil
  }

  implicit def otherSized[H, T <: HList, OutT <: HList](implicit
    typeable: Typeable[H],
    sifter: Aux[T, OutT]
  ): Aux[H :: T, Seq[H] :: OutT] = new Sifter[H :: T] {
    type Out = Seq[H] :: OutT
    def apply(xs: Seq[Any]) = xs.flatMap(typeable.cast) :: sifter(xs)
  }

  def sift[L <: HList](xs: Seq[Any])(implicit sifter: Sifter[L]): sifter.Out =
    sifter(xs)
}
然而,这里有一些重复;我想要的是(伪代码):

我的选择是什么?我可以保持原样,但如果有什么简单的方法可以让它变干的话,我很想听一听

import scala.reflect.{ClassTag, classTag}
val List(foo, bar, baz) = List(classTag[Foo], classTag[Bar], classTag[Baz]).map(ct => findByType(xs)(ct))

当然,现在您正在丢失类型信息-
foo
bar
baz
都将具有类型
选项[Any]
,如果您确实必须这样做,可以使它更干净、更安全:

import shapeless._

def findByType[T](xs: Seq[Any])(implicit t: Typeable[T]) =
  xs.flatMap(t.cast).headOption
请注意,与您的实现不同,此实现不会对标准库的许多泛型类型给出错误答案:

scala> findByType[List[String]](Seq(List(1), List("a"), 'foo))
res3: Option[List[String]] = Some(List(a))
Vs

(不过,您仍然需要小心,因为这在用户定义的泛型上不起作用。)

它还可以让你做一些整洁的事情,比如:

val foo = findByType[Foo](xs)
val bar = findByType[Bar](xs)
val baz = findByType[Baz](xs)
trait Sifter[L <: HList] extends DepFn1[Seq[Any]] {
  type Out <: HList
}

object Sifter {
  type Aux[L <: HList, Out0 <: HList] = Sifter[L] { type Out = Out0 }

  implicit def emptySized: Aux[HNil, HNil] = new Sifter[HNil] {
    type Out = HNil
    def apply(xs: Seq[Any]) = HNil
  }

  implicit def otherSized[H, T <: HList, OutT <: HList](implicit
    typeable: Typeable[H],
    sifter: Aux[T, OutT]
  ): Aux[H :: T, Seq[H] :: OutT] = new Sifter[H :: T] {
    type Out = Seq[H] :: OutT
    def apply(xs: Seq[Any]) = xs.flatMap(typeable.cast) :: sifter(xs)
  }

  def sift[L <: HList](xs: Seq[Any])(implicit sifter: Sifter[L]): sifter.Out =
    sifter(xs)
}

这基本上是您想要的类型安全版本。

关于丢失类型信息的好观点;我想特拉维斯的解决方案也能解决这个问题;为了理解筛选器示例,我必须更深入地研究依赖类型!但除此之外,这就是我所寻找的(虽然我的用例太小,无法保证额外的15行复杂性,但我会记住这一点,以备将来参考)。
scala> val myStuff: Seq[Any] = List(1, List('a', 'b'), "foo", 'bar)
myStuff: Seq[Any] = List(1, List(a, b), foo, 'bar)

scala> val myInts :: myCharLists :: myStrings :: HNil =
     |   Sifter.sift[Int :: List[Char] :: String :: HNil](myStuff)
myInts: Seq[Int] = List(1)
myCharLists: Seq[List[Char]] = List(List(a, b))
myStrings: Seq[String] = List(foo)