Scala函数转换

raf*_*afl 6 closures functional-programming scala

假设我有一个函数采用一个参数

def fun(x: Int) = x
Run Code Online (Sandbox Code Playgroud)

基于此,我想生成一个具有相同调用约定的新函数,但是在委托给原始函数之前,它将对其参数应用一些转换.为此,我可以

def wrap_fun(f: (Int) => Int) = (x: Int) => f(x * 2)
wrap_fun(fun)(2) // 4
Run Code Online (Sandbox Code Playgroud)

一个人怎么可能做同样的事情,除了任何arity的函数只有参数的一部分来共同应用转换?

def fun1(x: Int, y: Int) = x
def fun2(x: Int, foo: Map[Int,Str], bar: Seq[Seq[Int]]) = x

wrap_fun(fun1)(2, 4) // 4
wrap_fun(fun2)(2, Map(), Seq()) // 4
Run Code Online (Sandbox Code Playgroud)

wrap_fun上述调用的定义如何工作?

Fra*_*ank 6

像往常一样,在Scala中,还有另一种方法可以实现您想要做的事情.

这是基于第一个论点与以下内容的compose讨论Function1:

def fun1(x : Int)(y : Int) = x
def fun2(x : Int)(foo : Map[Int, String], bar : Seq[Seq[Int]]) = x

def modify(x : Int) = 2*x
Run Code Online (Sandbox Code Playgroud)

作为REPL的结果类型显示您将:

fun1: (x: Int)(y: Int)Int
fun2: (x: Int)(foo: Map[Int,String], bar: Seq[Seq[Int]])Int
modify: (x: Int)Int
Run Code Online (Sandbox Code Playgroud)

而不是包装的功能fun1fun2,你compose这些,在技术上,他们现在都Function1对象.这允许您进行如下调用:

(fun1 _ compose modify)(2)(5)
(fun2 _ compose modify)(2)(Map(), Seq())
Run Code Online (Sandbox Code Playgroud)

两者都将返回4.当然,语法不是那么好,因为你必须添加_区分fun1的应用程序与函数对象本身(compose在这种情况下你要在其上调用方法).

因此,Luigi认为它一般不可能的论点仍然有效,但如果你可以自由地讨论你的功能,你可以用这种方式做到这一点.


Mil*_*bin 6

这可以通过相当直接的方式使用无形的设施进行抽象而不是功能,

import shapeless._
import HList._
import Functions._

def wrap_fun[F, T <: HList, R](f : F)
  (implicit
    hl :   FnHListerAux[F, (Int :: T) => R],
    unhl : FnUnHListerAux[(Int :: T) => R, F]) =
      ((x : Int :: T) => f.hlisted(x.head*2 :: x.tail)).unhlisted

val f1 = wrap_fun(fun _)
val f2 = wrap_fun(fun1 _)
val f3 = wrap_fun(fun2 _)
Run Code Online (Sandbox Code Playgroud)

示例REPL会话,

scala> f1(2)
res0: Int = 4

scala> f2(2, 4)
res1: Int = 4

scala> f3(2, Map(), Seq())
res2: Int = 4
Run Code Online (Sandbox Code Playgroud)

请注意,您不能立即应用包装函数(如在问题中)而不是通过指定的val(如上所述),因为包装函数的显式参数列表将与隐式参数列表混淆wrap_fun.我们可以在问题中找到最接近表单的apply方法是将方法明确命名如下,

scala> wrap_fun(fun _).apply(2)
res3: Int = 4

scala> wrap_fun(fun1 _).apply(2, 4)
res4: Int = 4

scala> wrap_fun(fun2 _).apply(2, Map(), Seq())
res5: Int = 4
Run Code Online (Sandbox Code Playgroud)

这里明确提到从第二个应用程序(带有显式参数列表的转换函数)apply的第一个应用程序(wrap_fun以及它的隐式参数列表)的语法标记.