gpt4 book ai didi

scala - HList 的通用解压

转载 作者:行者123 更新时间:2023-12-03 05:08:57 25 4
gpt4 key购买 nike

我遇到以下 Scala 问题:

编写一个函数来获取 HList 列表

List(23 :: “a” :: 1.0d :: HNil, 24 :: “b” :: 2.0d :: HNil)    # this is list of hlists

并返回列表的 HList

List[Int](23, 24) :: List[String](“a”, “b") :: List[Double](1.0d, 2.0d) :: HNil # this is hlist of lists

这有点像通用的 unzipN。任意 HList 都可能吗?

谢谢。

最佳答案

有很多方法可以解决这个问题,定义一个自定义类型类(如 Nikita 的答案)是一个非常好的方法。不过,我个人认为以下方法更清晰一些。首先,让我们将任何由幺半群组成的异构列表变成幺半群:

import shapeless._
import scalaz._, Scalaz._

implicit object hnilMonoid extends Monoid[HNil] {
val zero = HNil
def append(f1: HNil, f2: => HNil) = HNil
}

implicit def hconsMonoid[H: Monoid, T <: HList: Monoid] = new Monoid[H :: T] {
val zero = Monoid[H].zero :: Monoid[T].zero
def append(f1: H :: T, f2: => H :: T) =
(f1.head |+| f2.head) :: (f1.tail |+| f2.tail)
}

我正在使用ScalazMonoid ,尽管您可以很容易地编写自己的 - 它只是一个类型类,它见证类型具有带有标识元素的类似加法的操作。对于这个示例列表(任何列表)至关重要的是串联下的幺半群,其中空列表作为单位元素。

接下来是一个简单的多态函数,它将您在列表中提供的任何内容包装起来:

object singleton extends Poly1 { implicit def anything[A] = at[A](List(_)) }

然后我们将它们结合在一起:

def unzipN[L <: HList, Out <: HList](hlists: List[L])(implicit
mapper: ops.hlist.Mapper.Aux[singleton.type, L, Out],
monoid: Monoid[Out]
): Out = hlists.map(_ map singleton).suml

现在我们可以定义我们的示例:

val myList = List(23 :: "a" :: 1.0d :: HNil, 24 :: "b" :: 2.0d :: HNil)

我们就完成了:

scala> println(unzipN(myList))
List(23, 24) :: List(a, b) :: List(1.0, 2.0) :: HNil

通过这种方法,大多数机制都非常通用,并且很容易直观地了解每个步骤的作用。考虑以下简化示例:

val simple = List(1 :: "a" :: HNil, 2 :: "b" :: HNil)

现在simple.map(_ map singleton)如下:

List(List(1) :: List("a") :: HNil, List(2) :: List("b") :: HNil)

但我们知道如何“添加” List[Int] :: List[String] :: HNil 类型的东西,感谢我们位于顶部的幺半群机器。因此,我们可以使用 Scalaz 的 suml 计算列表的总和。 ,我们就完成了。

这一切都使用 Shapeless 2.0,但在 1.2 中看起来非常相似。

关于scala - HList 的通用解压,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21442473/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com