【问题标题】:Function that retrieves element from HList (while preserving its type)从 HList 中检索元素的函数(同时保留其类型)
【发布时间】:2018-11-20 07:34:48
【问题描述】:

我有这种类型,它将通过 shapeless 生成:

type hlistt = STUDENT.type :: AUTO_LOANS.type :: HNil

基本上,我有一堆扩展特征的案例对象,因此我设法创建了一个方法,该方法将所有案例对象的实例作为 HList 提供给我

然后使用import shapeless.ops.hlist.Lastinit我写了一个方法来检索HList中的一个节点,如果值等于字符串“student”:

def getLast(hl:hlistt) = {
  val last0=Last[hlistt]
  val la=last0(hl)

  if (la.value == "student") la
  else init(hl)
}

问题是,如果我调用此方法,我将无法从 HList 中获取正确的节点类型。

getLast(STUDENT :: AUTO_LOANS :: HNil)

该方法有效并返回节点但类型为关闭:

Product with Serializable = STUDENT :: HNil

我是否需要一些 Witness/Aux 隐式来返回正确的类型?

【问题讨论】:

  • 这不是重现您描述的结果的正确代码。一方面,所发布的getLast() 不是递归的。
  • @jwvh 好点 - 我在深夜(我的时间)写了这篇文章,最初是在考虑递归 fn。我的意思是把init(hl) 包装成getLast(init(hl))

标签: scala shapeless hlist


【解决方案1】:

laAUTO_LOANS.type 类型,init(hl)STUDENT.type :: HNil 类型,所以

if (la.value == "student") la
else init(hl)

Any(或Product with Serializable)类型。

如果您想从不同的分支返回不同类型的值,您需要Poly

import shapeless.{Poly1, Witness}

object myPoly extends Poly1 {
  implicit def studentCase: Case.Aux[Witness.`"student"`.T, STUDENT.type] = 
    at(_ => STUDENT)
  implicit def autoLoansCase: Case.Aux[Witness.`"auto-loans"`.T, AUTO_LOANS.type] = 
    at(_ => AUTO_LOANS)
}

import shapeless.syntax.singleton._
println(
  myPoly("student".narrow)
) // STUDENT

println(
  myPoly("auto-loans".narrow)
) // AUTO_LOANS

// println(
//   myPoly("abc".narrow)
// )  // doesn't compile

如果字符串在编译时已知,则此方法有效。

【讨论】:

    【解决方案2】:

    我不太确定你想做什么。给定:

    type hlistt = STUDENT.type :: AUTO_LOANS.type :: HNil
    

    Last[hlistt] 将解析为AUTO_LOANS.type(如果分支为真) 而init 将解析为STUDENT :: HNil(如果分支为假)

    这些类型的 LUB(最小上限)将是 Product with Serializable,这就是您看到它的原因。

    如果您想检查 hlist 成员的运行时属性,您必须通过使用适当的机制派生适当的类型绑定和结果类型来处理它们。在这种情况下,shapeless 已经给出了。

    https://scalafiddle.io/sf/fdtn3cz/0

    这是你想要的吗?

    编辑: 我也刚读过

    我有这种动态生成的类型:

    “动态”到底是什么意思?因为除非您可以指定一些编译时属性,否则 shapeless 可能不是您正在寻找的解决方案。

    【讨论】:

    • 你已经非常接近我想要的了。你知道我为什么不能这样做吗:if(last(hlist).value == "student") Some(last(hlist)) else getLastOrNone(init(hlist)) 并为HNil 添加一个案例。我得到类型不匹配。我正在尝试遍历 HList 并按值而不是按类型查找节点。
    • 问题在于,您在编译时不知道函数的输出类型是什么,因为它取决于运行时值。您使用HList 的动机是什么?
    • 我想在您的示例代码中保留CarStudent 的类型。我遇到的实际问题是给定一个字符串“学生”或“汽车”,以获得正确的单身人士,即学生或汽车。我在这些单例类型上定义了类型类,这就是为什么我非常努力地保留类型。我也在考虑制作一些“汽车”->汽车,“学生”->学生的映射,所以当我收到一个文本时,我可以用它作为获取适当类型的键
    • 从技术上讲,我猜你可以制定一个从某个 hlist A :: B :: C :: HNilA :+: B :+: C :+: Unit :+: CNil 的函数,并找到某个谓词多函数的第一个匹配项或返回 Unit。但是因为您基于运行时值,所以我认为您不能直接这样做。该函数的返回类型是什么?因此,正如 Dmytro 所说,它更倾向于解决方案。
    • 是的,这是我的障碍:不知道该方法的类型是什么:(
    猜你喜欢
    • 2020-07-23
    • 1970-01-01
    • 2019-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多