2012-07-15 62 views
5

我正在尝试做一些我不确定Scala的类型系统是否允许我这样做的事情。在Scala中创建从泛型闭包

我基本上想创建一个通用定义的闭包,并返回该闭包,同时执行一个内部的相同类型的函数。

例如:

val f = async[(str:String, i:Int, b:BigInt) => Unit]({ (String, Int, BigInt) => 
    // Code here... 
}) 

// 'f' would have a type of (String, Int, BigInt) => Unit and would wrap the passed anonymous function 

的定义理论例如:

def async[T](
    shell: Shell, 
    success: T, 
    failure: (Throwable) => Unit): T = { 
     new T { 
      val display = shell.getDisplay() 
      display.asyncExec(new Runnable() { 
      def run(): Unit = { 
       try { 
       success(_) 
       } catch { 
       case e:Throwable => 
        failure(e) 
       } 
      } 
      }) 
     } 
    } 

这则让我有创造SWT异步回调的一个简单的系统,同时保持SWT出来的我商业逻辑。

+0

可能的重复[斯卡拉泛型 - 为什么我不能在泛型类中创建参数化对象?](http://stackoverflow.com/questions/5336648/scala-generics-why-i-cant-create-parametrised- object-inside-generic-class) – 2012-07-15 23:49:14

+0

我不认为它是100%重复的,因为即使我用apply方法创建了一个类型为T的类,我仍然需要接受由T提供的适当参数。 ,类型擦除可能会使这个特定的问题无法解决。 – Hakkar 2012-07-16 02:24:16

回答

9

您可以用Shapeless库做到这一点更一般我们定义wrap如下:

import shapeless._, Functions._ 

def wrap[F, A <: HList, R](f: F)(implicit 
    h: FnHListerAux[F, A => R], 
    u: FnUnHListerAux[A => R, F] 
): F = { (args: A) => 
    println("Before f") 
    val result = f.hlisted(args) 
    println("After f") 
    result 
}.unhlisted 

然后可以像这样使用它:

scala> val sum: (Int, Int) => Int = _ + _ 
sum: (Int, Int) => Int = <function2> 

scala> val wrappedSum = wrap(sum) 
wrappedSum: (Int, Int) => Int = <function2> 

scala> wrappedSum(100, 1) 
Before f 
After f 
res0: Int = 101 

这适用于任何arity的函数。

所以在Scala中是可能的,尽管做一些没有无形体的东西几乎肯定会让人头疼。

+0

这看起来非常有趣!它不会导致任何(显着的)运行时开销,例如,通过使用反射? – 2012-07-16 06:54:43

+0

不,没有反射。运行时间开销,但不应该过多 – 2012-07-16 07:00:12

+0

谢谢,这正是我想要的,这可能会成为将匿名类转换为匿名函数的非常有用的模式。 – Hakkar 2012-07-16 21:15:37

2

如何沿着这些路线的东西:

scala> def wrap[T1, T2, T3, R](f: (T1, T2, T3) => R) = { 
| (v1: T1, v2: T2, v3: T3) => 
|  println("Before f") 
|  val r = f(v1, v2, v3) 
|  println("After f") 
|  r 
| } 
wrap: [T1, T2, T3, R](f: (T1, T2, T3) => R)(T1, T2, T3) => R 

scala> def foo(x: String, y: Int, z: BigInt) = (x, y, z) 
foo: (x: String, y: Int, z: BigInt)(String, Int, BigInt) 

scala> val wrapped = wrap(foo _) 
wrapped: (String, Int, BigInt) => (String, Int, BigInt) = <function3> 

scala> wrapped("foo", 42, 12345) 
Before f 
After f 
res0: (String, Int, BigInt) = (foo,42,12345) 

如果你想换行可以有争论,那么你将很不幸,有一次定义您的包裹功能为每个不同的元数不同数量的功能: - (

+0

感谢您的回答。不同数量的参数部分是不幸的:(尽管如此,你可以强制这个监听器采用一个单独的元组,并通过这种类型的方式来绕过这个限制,能够转发泛型类型是非常棒的。我不确定Scala是否有这样的功能:/。 – Hakkar 2012-07-16 02:19:30