【问题标题】:Is there a boilerplate-free way to convert HLists to an argument list?是否有一种无样板的方法可以将 HLists 转换为参数列表?
【发布时间】:2014-11-19 22:11:15
【问题描述】:

根据this question,Spray 使用 sbt-boilerplate 生成ApplyConverter 实例,这些实例隐式地将A :: B :: ... :: HNil => R 转换为更传统的(A, B, ...) => R,以便于使用。这个问题是一年多前提出的;现在可以使用例如宏或 Shapeless 的新功能来完成此操作,从而不需要外部代码生成步骤吗?

【问题讨论】:

  • IMO 样板应该是无形的一部分。我在邮件中once asked a similar question,但没有跟进。因此,如果您需要该功能,再次询问可能是有意义的。
  • 我很困惑......这几乎从一开始就是 shapeless 的一部分......我错过了什么?
  • @MilesSabin 首先让我感谢 shapeless 以及您为它所做的所有工作,我认为它是一个很棒的 Scala 库!但是我想知道如果没有“外部代码生成”是否可能一种不依赖于每个FunctionN 的单独实例的方法。据我所知,shapeless 仍在使用模板生成其 FnFromProduct 实例。
  • 我想这取决于您所说的“外部代码生成”是什么意思。作为 shapeless 的用户,您不必求助于任何形式的代码生成。代码生成在内部用于无形,当然,镜像 Scala 标准库和编译器中的代码生成......鉴于当前定义 Scala 函数类型的方式(即完全不相关),这是不可避免的。解决这个问题的明智方法是假设 Scala 变体将 curried 函数类型作为主要类型......但我认为这可能不会很快发生。
  • 所以我想我在问两个不同的问题:第一,这是否可能与 shapeless 一起使用,答案是肯定的,但第二,这在 vanilla Scala 中是否可能没有代码重复,答案是否定的。我认为 Miles 的回答更直接地回答了我的问题,所以我将其作为答案,但我也不认为 lmm 的回答是错误的。

标签: scala macros spray shapeless hlist


【解决方案1】:

这已经包含在 shapeless 中很长时间了。在 shapeless 2.0.0 中,您可以执行以下操作,

scala> import shapeless._, syntax.std.function._
import shapeless._
import syntax.std.function._

scala> val f1: (Int, String, Boolean) => Int = (i, s, b) => i+s.length+(if(b) 1 else 0)
f1: (Int, String, Boolean) => Int = <function3>

scala> val pf1 = f1.toProduct
pf1: Int :: String :: Boolean :: HNil => Int = <function1>

scala> pf1(23 :: "foo" :: true :: HNil)
res0: Int = 27

scala> val pf2: (Int :: String :: HNil) => Int = l => l.head+l.tail.head.length
pf2: Int :: String :: HNil => Int = <function1>

scala> val f2 = pf2.fromProduct
f2: (Int, String) => Int = <function2>

scala> f2(23, "foo")
res1: Int = 26

(REPL 结果类型渲染已整理以提高可读性)。

【讨论】:

    【解决方案2】:

    我认为在纯 Scala 中无法做到这一点,因为无法笼统地谈论 FunctionN 接口。在宏观层面这是可能的,但不是以利用可用的 AST 表示的方式;执行此操作的宏可能会简化为(有效地)进行字符串操作 - 在这种情况下,与 sbt-boilerplate 相比几乎没有优势。

    即使它确实成为可能,Spray 也是一个相当基础的库,需要与其他库一起使用(因此它会继续针对旧版本的 Scala 和 Akka 构建版本)——这只会变得更加重要,如果当 Play 被移植到在 Spray 之上运行时。因此,我预计 Spray 引入对 Shapeless 2 的硬依赖(与 Shapeless 1 不兼容)还需要一段时间,在此之前,我想他们会尝试保持喷雾路由的 shapeless2 构建的代码尽可能接近尽可能为 shapeless1 构建以方便维护。

    【讨论】:

    • 仅供参考:实际上,spray 可能不会再有这样的重大更新了。相反,新的开发工作将主要集中在 akka-http。在 akka-http 的路由部分,完全删除了对 shapeless2 的依赖,DSL 现在基于 Scala 元组而不是 HLists。也就是说,问题仍然完全一样,需要像以前一样生成样板。
    • 顺便说一句。为什么那行不通:“在宏观层面上这是可能的,但不是以利用可用的 AST 表示的方式”。在宏观层面,您可以访问所有类型,因此您可以进行任何类型的计算。
    • 太糟糕了,我希望他们重新考虑。 HLists 比 Scala 元组好得多,我有依赖于这种差异的生产 Spray 代码。至于您的问题,宏级别可以访问类型,但对不同 FunctionN 接口之间的关系一无所知。所以宏必须使用字符串操作来获得正确的FunctionN。不是宏做不到,而是宏做不到比文本处理器更好。
    • 我认为您不必在宏中使用FunctionN 接口。匿名函数有一个 AST 元素,您只需传入正确数量的参数。也就是说,我想我明白你在说什么:在某种程度上你需要做一种愚蠢的翻译(最好直接在编译器中完成)。
    • 关于元组的改变:我不认为它像你想象的那么糟糕。我们所做的(实际上是我进行了更改)是消除了对 shapeless 的硬依赖,这本身就是一件好事(少一个依赖,你可以与之发生冲突)。这并不意味着不再支持 HLists。这个想法是会有一个可选的连接器模块,它提供了足够的帮助器来重新启用以前可以通过直接 HList 支持实现的模式。这很有效,因为对于 shapeless,使用 HList、元组或案例类都没有关系。
    猜你喜欢
    • 2016-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-31
    • 2010-11-28
    • 2019-08-06
    相关资源
    最近更新 更多