简体   繁体   English

Scala Function.tupled和Function.untupled等效于变量arity,或调用变量arity函数与元组

[英]Scala Function.tupled and Function.untupled equivalent for variable arity, or, calling variable arity function with tuple

I was trying to do some stuff last night around accepting and calling a generic function (ie the type is known at the call site, but potentially varies across call sites, so the definition should be generic across arities). 昨晚我试图做一些接受和调用泛型函数的东西(即类型在调用站点已知,但可能在调用站点之间有所不同,因此定义应该是跨arities的通用)。

For example, suppose I have a function f: (A, B, C, ...) => Z . 例如,假设我有一个函数f: (A, B, C, ...) => Z (There are actually many such f s, which I do not know in advance, and so I cannot fix the types nor count of A, B, C, ..., Z .) (实际上有很多这样的f s,我事先并不知道,因此我无法修复A, B, C, ..., Z的类型和数量。)

I'm trying to achieve the following. 我正在努力实现以下目标。

  1. How do I call f generically with an instance of (A, B, C, ...) ? 如何使用(A, B, C, ...)的实例一般调用f If the signature of f were known in advance, then I could do something involving Function.tupled f or equivalent. 如果事先知道f的签名,那么我可以做一些涉及Function.tupled f或等价的东西。

  2. How do I define another function or method (for example, some object 's apply method) with the same signature as f ? 如何使用与f相同的签名定义另一个函数或方法(例如,某个objectapply方法)? That is to say, how do I define a g for which g(a, b, c, ...) type checks if and only if f(a, b, c, ...) type checks? 也就是说,我怎么定义一个g针对g(a, b, c, ...)类型检查,当且仅当f(a, b, c, ...)类型检查? I was looking into Shapeless's HList for this. 我正在研究Shapeless的HList From what I can tell so far, HList at least solves the "representing an arbitrary arity args list" issue, and also, Shapeless would solve the conversion to and from tuple issue. 从目前为止我所知, HList至少解决了“代表任意arity args列表”的问题,而且,Shapeless将解决与元组问题的转换。 However, I'm still not sure I understand how this would fit in with a function of generic arity, if at all. 但是,我仍然不确定我是否理解这将如何适应通用arity的功能,如果有的话。

  3. How do I define another function or method with a related type signature to f ? 如何定义与相关类型签名给另一个函数或方法f The biggest example that comes to mind now is some h: (A, B, C, ...) => SomeErrorThing[Z] \\/ Z . 现在想到的最大例子是一些h: (A, B, C, ...) => SomeErrorThing[Z] \\/ Z

I remember watching a conference presentation on Shapeless some time ago. 我记得前一段时间在Shapeless上观看过一次会议。 While the presenter did not explicitly demonstrate these things, what they did demonstrate (various techniques around abstracting/genericizing tuples vs HList s) would lead me to believe that similar things as the above are possible with the same tools. 虽然演示者没有明确地演示这些内容,但是他们所做的演示(围绕抽象/泛化元组与HList的各种技术)会让我相信使用相同的工具可以实现与上述类似的东西。

Thanks in advance! 提前致谢!

Yes, Shapeless can absolutely help you here. 是的,Shapeless绝对可以帮到你。 Suppose for example that we want to take a function of arbitrary arity and turn it into a function of the same arity but with the return type wrapped in Option (I think this will hit all three points of your question). 例如,假设我们想要获取任意arity的函数并将其转换为相同arity的函数,但返回类型包含在Option (我认为这将触及您问题的所有三个点)。

To keep things simple I'll just say the Option is always Some . 为了简单起见,我只想说Option总是Some This takes a pretty dense four lines: 这需要相当密集的四行:

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)))

We can show that it works: 我们可以证明它有效:

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)

Note the appropriate static return types. 请注意适当的静态返回类型。 Now for how it works: 现在它是如何工作的:

The FnToProduct type class provides evidence that some type F is a FunctionN (for some N ) that can be converted into a function from some HList to the original output type. FnToProduct类型类提供证据,证明某些类型FFunctionN (对于某些N ),可以将其转换为从某个HList到原始输出类型的函数。 The HList function (a Function1 , to be precise) is the Out type member of the instance, or the second type parameter of the FnToProduct.Aux helper. HList函数(准确地说是Function1 )是实例的Out类型成员,或者是FnToProduct.Aux帮助器的第二个类型参数。

FnFromProduct does the reverse—it's evidence that some F is a Function1 from an HList to some output type that can be converted into a function of some arity to that output type. FnFromProduct执行相反的操作,证明某些F是从HList到某种输出类型的Function1 ,可以转换为该输出类型的某个arity函数。

In our wrap method, we use FnToProduct.Aux to constrain the Out of the FnToProduct instance for F in such a way that we can refer to the HList parameter list and the O result type in the type of our FnFromProduct instance. 在我们的wrap方法,我们用FnToProduct.Aux来约束Out的的FnToProduct例如F在这样,我们可以参考的方式HList参数列表和O在我们的类型结果类型FnFromProduct实例。 The implementation is then pretty straightforward—we just apply the instances in the appropriate places. 然后实现非常简单 - 我们只是在适当的位置应用实例。

This may all seem very complicated, but once you've worked with this kind of generic programming in Scala for a while it becomes more or less intuitive, and we'd of course be happy to answer more specific questions about your use case. 这可能看起来都很复杂,但是一旦你在Scala中使用这种通用编程一段时间它变得或多或少变得直观,我们当然乐于回答有关你的用例的更具体的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM