2

これは shapeless ライブラリで可能かもしれないと考えています。

shapeless を使用して匿名クラスをクロージャーに変換しています。これにはhlistedfromFnHListerAuxトレイトの使用が必要です。

やりたいことは、渡されたダミー関数を取り除き、 と同じ型シグネチャを持つこの関数の周りにクロージャを返すことだけFです。非同期で実行される匿名クラスがなければ、これは簡単です。これを回避する方法はありますか?

def async[F, A <: HList, R](
  shell: Shell,
  success: F,
  failure: FunctionTypes.Failure,
  dummy: F)(implicit h: FnHListerAux[F, A => R],
            u: FnUnHListerAux[A => R, F]): F =
{ (args: A) =>

  require(shell != null, "Shell cannot be null")
  require(shell.getDisplay() != null, "The shell must have a display")

  val display = shell.getDisplay()
  display.asyncExec(new Runnable() {
    def run(): Unit = {
      try {
        success.hlisted(args)
      } catch {
        case e: Throwable =>
          failure(e)
      }
    }
  })

  dummy.hlisted(args)
}.unhlisted
4

1 に答える 1

3

少し単純化することから始めましょう。関数があるとしますf。事前にアリティかどうかはわかりませんし、何が返ってくるかは気にしません。いくつかの機能でラップして、同じ引数タイプの関数を取得したいと思います。また、この結果の関数が何を返すかは気にしないので、を返すこともできますUnit

次のような関数の束(まあ、22)を書くことができます:

def wrap[A](f: A => Unit): A => Unit = ???
def wrap[A, B](f: (A, B) => Unit): (A, B) => Unit = ???
def wrap[A, B, C](f: (A, B, C) => Unit): (A, B, C) => Unit = ???

しかし、あなたはしたくありません。

Shapelessは、この問題をより一般的に解決するのに間違いなく役立ちます。

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

それは私たちに与えます:

scala> def f(i: Int, s: String) { println(s * i) }
f: (i: Int, s: String)Unit

scala> val wf = wrap(f _)
wf: (Int, String) => Unit = <function2>

scala> wf(3, "ab")
Before!
ababab
After!

Scalaのすべてがaであり、特性がそれらの戻りタイプで共変であるため、fそれ以外のものを返す可能性がUnitあり、これは引き続き機能することに注意してください。UnitFunctionN

このアプローチをコードに適用すると、次のようになります。

def async[F, A <: HList](
  shell: Shell, success: F, failure: FunctionTypes.Failure
)(
  implicit h: FnHListerAux[F, A => Unit], u: FnUnHListerAux[A => Unit, F]
): F = { (args: A) =>
  require(shell != null, "Shell cannot be null")
  require(shell.getDisplay() != null, "The shell must have a display")

  val display = shell.getDisplay()
  display.asyncExec(new Runnable() {
    def run(): Unit = {
      try {
        success.hlisted(args)
      } catch {
        case e: Throwable =>
          failure(e)
      }
    }
  })
}.unhlisted

必要ありませんdummy

于 2012-07-18T09:39:47.863 に答える