是否可以编写Scala函数以使其获得任何函数并返回其参数被反转?

时间:2018-04-23 22:27:22

标签: scala higher-order-functions

我知道这在lisp中是微不足道的,但是Scala有一个强大的类型系统让我怀疑这样的功能是否可行。 如果不可能,宏怎么样? Scala宏可以这样做吗?

PS:这是Clojure中的函数:

 (fn [f](fn f* [& args] (apply f (reverse args))))

1 个答案:

答案 0 :(得分:5)

主要的困难是你必须找出具有反向参数的函数的类型,并且如果没有通用的宏,就不可能做到这一点。

但是因为Scala只支持多达22个参数的函数,所以你可以为所有可能的arities函数编写或生成23个实现。以下是3个参数的函数示例:

def reverse[A, B, C, R](f: (A, B, C) => R): (C, B, A) => R = 
  (c, b, a) => f(a, b, c)

使用宏虽然可以通用方式执行。最简单的解决方案可能是使用shapeless库,它是在内部使用宏实现的。这是一个无形的示例实现:

import shapeless._
import shapeless.ops.function._
import shapeless.ops.hlist._

def reverseArgs[Func, Args <: HList, Res, RevArgs <: HList](f: Func)(implicit
  // Convert the function to a function from a single HList argument.
  fnToProduct: FnToProduct.Aux[Func, Args => Res], 
  // Compute the type of the reversed arguments HList.
  r1: Reverse.Aux[Args, RevArgs],
  // Get the function to reverse the reversed arguments back.
  reverse: Reverse.Aux[RevArgs, Args],
  // Convert the function of a single HList argument to a normal function
  fnFromProduct: FnFromProduct[RevArgs => Res]
): fnFromProduct.Out = {
  fnFromProduct((args: RevArgs) => fnToProduct(f)(reverse(args)))
}

以下是它的工作原理:

scala> val f = reverseArgs((i: Int, d: Double, s: String) => (i + d).toString + s)
f: (String, Double, Int) => String = shapeless.ops.FnFromProductInstances$$anon$4$$Lambda$1191/2014583896@4d7933e7

scala> f("a", 1.5, 2)
res1: String = 3.5a