2013-05-07 11 views
15

暗黙的なパラメータを持つメソッドを関数に変換できますか?暗黙のパラメータを持つ関数を部分的に適用する

trait Tx 

def foo(bar: Any)(implicit tx: Tx) {} 

foo _ // error: could not find implicit value for parameter tx: Tx 

私は何とかそれはプレーンなコールwithSelection(deleteObjects)で動作させることができ、好ましく場合、以下のことを実現しようとしています:私はしかし、それは扱っていない、this questionを見つけ

trait Test {  
    def atomic[A](fun: Tx => A): A 

    def selection: Iterable[Any] 

    def withSelection(fun: Iterable[Any] => Tx => Unit) { 
    val sel = selection 
    if (sel.nonEmpty) atomic { implicit tx => 
     fun(sel)(tx) 
    } 
    } 

    object deleteAction { 
    def apply() { 
     withSelection(deleteObjects) // ! 
    } 
    } 

    def deleteObjects(xs: Iterable[Any])(implicit tx: Tx): Unit 
} 

私が見る限りでは、方法から機能を持ち上げる。

答えて

6

インプリシットはメソッドに対してのみ機能します。しかし、関数をwithSelectionに渡す必要があります。あなたは、関数内でメソッドをラップすることによって周りに取得することができます:

withSelection(a => b => deleteObjects(a)(b)) 

foo _が定義された暗黙のパラメータリストでfooでは動作しませんので、直接deleteObjectsを渡すために、そのことは不可能。

4

私の知る限りでは、暗黙的な解決は使用サイトで行われなければならず、カルトを除去することはできません。私自身の失望の瞬間は、自分のコードで'ExecutionContext 'の拡散を回避しようとしたときでした。

私が検討してきた一つの妥協した

type Async[A] = ExecutionContext => Future[A] 

def countFiles(root: String): Async[Int] = implicit ec => 
    // ... 

'implicit'は、関数内でのみ保持している - 私たちは、呼び出しで妥協する必要があります。

implicit class AsyncExt[A](async: Async[A]) { 
    def invoke()(implicit ec: ExecutionContext) = async(ec) 
} 

implicit val ec = ... 
countFiles("/").invoke() 

別の妥協 - 私は選択して後悔するために住んでいた:

class AsyncFileCounter(ec: ExecutionContext) { 
    def countFiles(root: String): Future[A] = ... 
} 

class FileCounter { 
    def async(implicit ec: ExecutionContext) = new AsyncFileCounter(ec) 
} 

これは、産ま):次のよう

implicit val ec = ... 
val counter = new FileCounter 
counter.countFiles("/") // <-- nope 

あなたの状況に応じて、
implicit val ec = ... 
val counter = new FileCounter 
counter.async.countFiles("/") // yep! 

、これは我慢である可能性があります。あなたは'def async 'を使ったところで'def transactional'を追加することができます。

しかし、これは継承を複雑にし、割り当てオーバーヘッドが発生するため、後悔します(ただし、これはJITされなくてはなりません)。

要点は、関数を呼び出すためのより明示的な断片的な方法 - 単独でカリングするよりエレガントではないもの - が必要であるということです。

+2

あなたの2番目のケース(FileCounter)について、暗黙の変換 '暗黙のdef counterToAsync(c:FileCounter):AsyncFileCounter = c.async'を定義できませんでしたので、' counter.countFiles( "/") '? –

+0

ニース!私の場合、暗黙的な変換は、包含するオブジェクトに存在する同様のシグニチャーを持つ同期メソッドによって無効にされます。しかし、それは間違いなく良い定型的な回避策です!私はエスケープ解析がAsyncオブジェクトのヒープ割り当てを実際に排除していることを実際に検証する必要があります。 – nadavwr

+0

私は、同期メソッドは 'Future [A]'を返さず単に 'A'を返さないので、コンパイラがあなたにそれを伝えることができるので、異なる署名を持つと言いたいと思います。非同期呼び出しが必要なスコープを区切り、そこで暗黙の変換をインポートするだけです。ヒープ割り当てを避けるため、私はそれに賭けることはできません... –

関連する問題