Memo

Memo エフェクトはコストがかかる計算のキャッシュを可能にする。計算結果は与えられたキーにひもづけて「保存」され、同じキーに対する次の計算では以前に計算された値が返される。これらの計算をインタープリターで解釈するには、Cache を提供しなければいけない。

import cats.Eval
import cats.implicits._
import org.atnos.eff._, memo._
import org.atnos.eff.syntax.memo._
import org.atnos.eff.syntax.eval._
import org.atnos.eff.syntax.eff._

type S = Fx.fx2[Memoized, Eval]

var i = 0

def expensive[R :_memo]: Eff[R, Int] =
  memoize("key", { i += 1; 10 * 10 })

(expensive[S] >> expensive[S]).runMemo(ConcurrentHashMapCache()).runEval.run === 100

"there is only one invocation" <==> (i === 1)

> there is only one invocation <=> true

このライブラリには、Memo エフェクトをサポートするためのキャッシュ実装が 2 つある。

キャッシュサイズの上限、キャッシュエビクションポリシー(上限まで来たときに古いキャッシュを追い出すなど)、といった機能が欲しいなら、Caffeine のような他のより良いキャッシュ実装を使うこともできる。Cache インターフェースを実装すればよい。

trait Cache {
  def memo[V](key: AnyRef, value: =>V): V
}