2017-10-11 7 views
0

に一度だけの機能とキャッシュ値を実行し、私はそれが実行されていない場合、私はそれはいくつかの方法を実行し、その結果を返したい、このRUNONCE関数を呼び出すので、Scalaの

def runOnce(request: Request): Future[Result] = { 
} 

のような機能を持っています。それが実行されている場合、私はそれが元の結果を返すだけです(入って来る要求は同じになります)。

私は最初のケースで行うにはどのように

lazy val hydratedModel = hydrateImpl(request) 

future for efficient filtering 
def fetchHydratedModel(): Future[HydratedModelRequest] = { 
    hydratedModel 
} 

のように何のparamを持っていない場合、私はそれを行うことができますか?

+0

は機能が本当に今までに一度1 'request'でより多くを呼び出すことでしょうか?あなたが望むもののテクニックはメモ化と呼ばれますが、要求にそれを適用することは私にとっては非常に奇妙なようです。 memoizationについては、[Scalaでメモを取る一般的な方法はありますか?](https://stackoverflow.com/questions/16257378/is-there-a-generic-way-to-memoize-in-scala) – Suma

+0

あなたは本当ですか機能が必要ですか?それは名前とコールバリュー評価戦略による呼び出しと関係があります。 – Pavel

答えて

0

あり、あなたのセットアップに応じてこれを行うには良い方法がありそうですが、簡単な解決策は、requestが実際に各呼び出しで同じである場合は、別のオプションを必要とするだろう、次の

private var model: Option[Future[HydratedModelRequest]] = None 

def runOnce(request: Request): Future[Request] = { 
    if (model.isEmpty) { 
    model = hydrateImpl(request) 
    } 

    model.get 
} 

を行うことです暗黙のうちに要求が遅れて遅延します。

implicit val request: Request 
lazy val hydratedRequest: Future[HydratedModelRequest] = hydrateImpl(request) 
1

機能メモ化であるこの問題に対する一般的な解決策は、あります。 純関数(副作用がない - 純粋でない関数では機能しないもの)の場合、関数呼び出しの結果は、同じ引数値のセットに対して常に同じでなければなりません。したがって、最適化は、最初の呼び出しで値をキャッシュし、後続の呼び出しで値を戻すことです。

あなたは(単一の引数を持つ純粋な機能のためのメモ化クラス)以下のようなものでこれを達成することができます:

/** Memoize a pure function `f(A): R` 
* 
* @constructor Create a new memoized function. 
* @tparam A Type of argument passed to function. 
* @tparam R Type of result received from function. 
* @param f Pure function to be memoized. 
*/ 
final class Memoize1[A, R](f: A => R) extends (A => R) { 

    // Cached function call results. 
    private val result = scala.collection.mutable.Map.empty[A, R] 

    /** Call memoized function. 
    * 
    * If the function has not been called with the specified argument value, then the 
    * function is called and the result cached; otherwise the previously cached 
    * result is returned. 
    * 
    * @param a Argument value to be passed to `f`. 
    * @return Result of `f(a)`. 
    */ 
    def apply(a: A) = result.getOrElseUpdate(a, f(a)) 
} 

/** Memoization companion */ 
object Memoize1 { 

    /** Memoize a specific function. 
    * 
    * @tparam A Type of argument passed to function. 
    * @tparam R Type of result received from function. 
    * @param f Pure function to be memoized. 
    */ 
    def apply[A, R](f: A => R) = new Memoize1(f) 
} 

あなたはmemoizingしている機能がhydrateImplであると仮定すると、あなたがして定義することができますし、以下のように(それはvalないdefなりますのでご了承願います)runOnceを使用します。

val runOnce = Memoize1(hydrateImpl) 
runOnce(someRequest) // Executed on first call with new someRequest value, cached result subsequently.