【问题标题】:Scala Function.tupled and Function.untupled equivalent for variable arity, or, calling variable arity function with tupleScala Function.tupled 和 Function.untupled 等效于变量 arity,或者,使用元组调用变量 arity 函数
【发布时间】:2015-10-07 12:42:51
【问题描述】:

昨晚我试图做一些关于接受和调用泛型函数的事情(即类型在调用站点是已知的,但可能因调用站点而异,因此定义应该是跨arities的通用函数)。

例如,假设我有一个函数f: (A, B, C, ...) => Z。 (其实fs这样的有很多,我事先不知道,所以无法确定A, B, C, ..., Z的类型和数量。)

我正在努力实现以下目标。

  1. 如何使用(A, B, C, ...) 的实例一般地调用f?如果事先知道f 的签名,那么我可以做一些涉及Function.tupled f 或类似的事情。

  2. 如何定义与f 具有相同签名的另一个函数或方法(例如,某些objectapply 方法)?也就是说,当且仅当f(a, b, c, ...) 类型检查时,我如何定义g(a, b, c, ...) 类型检查的g?为此,我正在研究 Shapeless 的 HList。据我目前所知,HList 至少解决了“表示任意数量的参数列表”问题,而且,Shapeless 将解决与元组之间的转换问题。但是,我仍然不确定我是否理解这将如何与泛型 arity 的函数相匹配,如果有的话。

  3. 如何定义具有相关类型签名的另一个函数或方法到f?现在想到的最大的例子是一些h: (A, B, C, ...) => SomeErrorThing[Z] \/ Z

我记得前段时间看过一个关于 Shapeless 的会议演示。虽然演示者没有明确地展示这些东西,但他们所展示的东西(围绕抽象/泛化元组的各种技术 vs HLists)让我相信使用相同的工具可以实现与上述类似的事情。

提前致谢!

【问题讨论】:

  • 我相信 Shapeless 会帮助你做到这一点。不幸的是,我现在没有时间摆弄这个。
  • 我的印象也是,大致上,这类似于我看到的 Shapeless 所做的,但我不太确定如何。

标签: scala types shapeless


【解决方案1】:

是的,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)

注意适当的静态返回类型。现在如何工作:

FnToProduct 类型类证明某些类型 FFunctionN(对于某些 N),可以将其转换为从某些 HList 到原始输出类型的函数。 HList 函数(准确地说是Function1)是实例的Out 类型成员,或FnToProduct.Aux 助手的第二个类型参数。

FnFromProduct 反其道而行之——有证据表明,一些F 是从HList 到某种输出类型的Function1,可以将其转换为该输出类型的某种元数的函数。

在我们的wrap 方法中,我们使用FnToProduct.AuxFnToProduct 实例的Out 约束为F,这样我们可以引用HList 参数列表和@987654345 @result 类型在我们的FnFromProduct 实例的类型中。实现非常简单——我们只需将实例应用到适当的位置。

这可能看起来很复杂,但是一旦您在 Scala 中使用过这种泛型编程一段时间,它就会或多或少地变得直观,我们当然很乐意回答有关您使用的更具体的问题案例。

【讨论】:

  • 感谢您阐明创建最终产品的各个部分!
  • 有点后续,出于好奇:是什么限制了FI 之间的关系?换句话说,是什么阻止了wrap 与不兼容的类型一起使用,例如(A, B)(A, B, C) =&gt; D?是不是我无法为不排队的类型获取 FnToProduct / FnFromProduct 的实例?是什么阻止我意外或以其他方式创建这样的类型?换句话说,FnToProduct / FnFromProduct 的“正确”(或传统上可接受的)实例有什么区别?
  • Shapeless 只会提供这些类型类的有效实例。我想您可以提供自己的无效类,但任何(非密封)类型类都是这种情况。为什么这些类型类不密封是一个很好的问题——这可能只是因为考虑到 Shapeless 的代码生成方式,这会带来不便。在任何情况下,您通常不必担心意外创建此类类型类的无效实例(并且根本不应该定义您自己的实例)。
  • 对于许多无形的类型类,能够方便地定义自己的实例,例如如果一个人有自己的“类函数”类,并且希望能够与此方法一起使用。
  • @lmm 在那种情况下我可能会定义我自己的类型类——无论如何你都必须复制很多 Shapeless 的 arity-level 样板。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
  • 2021-01-15
  • 2013-01-25
  • 1970-01-01
  • 2010-11-25
相关资源
最近更新 更多