4

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

4

2 回答 2

3

这已经包含在 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 结果类型渲染)。

于 2014-11-20T19:37:51.723 回答
0

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

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

于 2014-11-19T23:00:04.547 回答