5

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の非同期コールバックを作成する簡単なシステムを使用できるようになります。

4

2 に答える 2

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

これは、任意のアリティの関数で機能します。

そのため、Shapeless を使用せずに同等のことを行うことはほぼ確実に大きな頭痛の種になりますが、Scala でも可能です。

于 2012-07-16T05:10:25.580 に答える
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)

ラップしたい関数が異なる数の引数を持つ可能性がある場合、残念ながら、異なるアリティごとにラップ関数を1回定義する必要があります:-(

于 2012-07-15T23:47:09.200 に答える