是的,Shapeless 绝对可以帮助你。例如,假设我们想要采用任意数量的函数,并将其转换为具有相同数量但返回类型包含在内的函数Option
(我认为这将满足您问题的所有三点)。
为了简单起见,我只想说Option
总是Some
。这需要相当密集的四行:
import shapeless._, ops.function._
def wrap[F, I <: HList, O](f: F)(implicit
ftp: FnToProduct.Aux[F, I => O],
ffp: FnFromProduct[I => Option[O]]
): ffp.Out = ffp(i => Some(ftp(f)(i)))
我们可以证明它是有效的:
scala> wrap((i: Int) => i + 1)
res0: Int => Option[Int] = <function1>
scala> wrap((i: Int, s: String, t: String) => (s * i) + t)
res1: (Int, String, String) => Option[String] = <function3>
scala> res1(3, "foo", "bar")
res2: Option[String] = Some(foofoofoobar)
请注意适当的静态返回类型。现在为how有用:
The FnToProduct
类型类提供了某些类型的证据F
is a FunctionN
(对于一些N
)可以将某些转换为函数HList
到原始输出类型。这HList
函数(一个Function1
,准确地说)是Out
实例的类型成员,或实例的第二个类型参数FnToProduct.Aux
helper.
FnFromProduct
反之亦然——这证明有些F
is a Function1
从一个HList
某些输出类型可以转换为该输出类型的某种数量的函数。
In our wrap
方法,我们使用FnToProduct.Aux
来约束Out
of the FnToProduct
实例为F
这样我们就可以参考HList
参数列表和O
结果类型为我们的类型FnFromProduct
实例。那么实现就非常简单了——我们只需将实例应用到适当的位置即可。
这可能看起来非常复杂,但是一旦您在 Scala 中使用这种泛型编程一段时间,它就会变得或多或少直观,我们当然很乐意回答有关您的用例的更具体的问题。