加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 从两个HLists创建所有对的HList

发布时间:2020-12-16 09:10:49 所属栏目:安全 来源:网络整理
导读:我在 Scala中使用无形的,我想编写一个函数allPairs,它将使用两个HLists并返回所有对元素的HList.例如: import shapeless._val list1 = 1 :: "one" :: HNilval list2 = 2 :: "two" :: HNil// Has value (1,2) :: (1,"two") :: ("one",2) :: ("one","two") ::
我在 Scala中使用无形的,我想编写一个函数allPairs,它将使用两个HLists并返回所有对元素的HList.例如:

import shapeless._
val list1 = 1 :: "one" :: HNil
val list2 = 2 :: "two" :: HNil
// Has value (1,2) :: (1,"two") :: ("one",2) :: ("one","two") :: HNil
val list3 = allPairs(list1,list2)

有什么想法怎么办?

另外,我想强调我正在寻找一个功能,而不是内嵌的代码块.

解决方法

您不能在这里(如其他答案建议)使用一个理解或map和flatMap与函数文字的组合,因为HList上的这些方法需要 higher rank functions.如果只有两个静态类型的列表,这很容易:

import shapeless._

val xs = 1 :: 'b :: 'c' :: HNil
val ys = 4.0 :: "e" :: HNil

object eachFirst extends Poly1 {
  implicit def default[A] = at[A] { a =>
    object second extends Poly1 { implicit def default[B] = at[B](a -> _) }
    ys map second
  }
}

val cartesianProductXsYs = xs flatMap eachFirst

这给了我们以下(适当类型):

(1,4.0) :: (1,e) :: ('b,4.0) :: ('b,e) :: (c,4.0) :: (c,e) :: HNil

编写一个使用HList参数执行此操作的方法很棘手.以下是一个简单的例子,说明它是如何完成的(有一些比较通用的机器).

我首先要注意的是,我们可以想到找到两个普通列表的笛卡儿积分是“提升”一个函数,它接受两个参数,并将它们作为一个元组返回到应用程序的列表中.例如,你可以写the following in Haskell:

import Control.Applicative (liftA2)

cartesianProd :: [a] -> [b] -> [(a,b)]
cartesianProd = liftA2 (,)

我们可以写一个对应于(,)的多态二进制函数:

import shapeless._

object tuple extends Poly2 {
  implicit def whatever[A,B] = at[A,B] { case (a,b) => (a,b) }
}

并再次定义我们的示例列表的完整性:

val xs = 1 :: 'b :: 'c' :: HNil
val ys = 4.0 :: "e" :: HNil

现在我们将致力于一种名为liftA2的方法,这将使我们能够写下列内容:

liftA2(tuple)(xs,ys)

并得到正确的结果.名称liftA2有点误导,因为我们真的没有一个应用函数实例,由于它不是通用的 – 我正在使用名为flatMap的方法和在HList上映射的模型,并且可以接受某些建议更好.

现在我们需要一个类型类,它将允许我们使用Poly2,部分地应用于某个东西,并且通过一个HList映射所得的一元函数:

trait ApplyMapper[HF,A,X <: HList,Out <: HList] {
  def apply(a: A,x: X): Out
}

object ApplyMapper {
  implicit def hnil[HF,A] = new ApplyMapper[HF,HNil,HNil] {
    def apply(a: A,x: HNil) = HNil
  }
  implicit def hlist[HF,XH,XT <: HList,OutH,OutT <: HList](implicit
    pb: Poly.Pullback2Aux[HF,OutH],am: ApplyMapper[HF,XT,OutT]
  ) = new ApplyMapper[HF,XH :: XT,OutH :: OutT] {
    def apply(a: A,x: XH :: XT) = pb(a,x.head) :: am(a,x.tail)
  }
}

而现在一个类型的帮助解除的类:

trait LiftA2[HF,Y <: HList,Out <: HList] {
  def apply(x: X,y: Y): Out
}

object LiftA2 {
  implicit def hnil[HF,Y <: HList] = new LiftA2[HF,Y,HNil] {
    def apply(x: HNil,y: Y) = HNil
  }

  implicit def hlist[
    HF,Out1 <: HList,Out2 <: HList,Out <: HList
  ](implicit
    am: ApplyMapper[HF,Out1],lift: LiftA2[HF,Out2],prepend : PrependAux[Out1,Out2,Out]
  ) = new LiftA2[HF,Out] {
    def apply(x: XH :: XT,y: Y) = prepend(am(x.head,y),lift(x.tail,y))
  }
}

最后我们的方法本身:

def liftA2[HF,Out <: HList](hf: HF)(x: X,y: Y)(implicit
  lift: LiftA2[HF,X,Out]
) = lift(x,y)

这就是所有现在的liftA2(元组)(xs,ys)的作品.

scala> type Result =
     |   (Int,Double) :: (Int,String) ::
     |   (Symbol,Double) :: (Symbol,String) ::
     |   (Char,Double) :: (Char,String) :: HNil
defined type alias Result

scala> val res: Result = liftA2(tuple)(xs,ys)
res: Result = (1,e) :: HNil

就像我们想要的那样.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读