2016-12-29 18 views
3

我有兩個monad實例val a: M[A]val b: M[B]。在下面的代碼情況下會有任何性能差異嗎?應用函數vs monad在Scala中構成性能

def f: (A, B) => C 

val applicativeCombine = (a |@| b)(f) 

val monadCombine = 
    for { 
    aa <- a 
    bb <- b 
    } yield f(aa, bb) 

...還是它取決於?

+0

您應該添加一個'scalaz'標記,因爲從問題本身不清楚'| @ |'是從哪裏來的。 –

回答

4

如果ab是返回期貨和執行一些計算昂貴的操作方法,該applicativeCombine版本將並行運行它們而monadCombine不會,這意味着|@|可能接近兩倍的速度。

如果ab是期權,另一方面,甚至期貨沒有被做計算量很大的工作,它有可能是for版本可能會更快,因爲它的脫糖形式涉及一對夫婦少分配:

scala> import scalaz._, Scalaz._ 
import scalaz._ 
import Scalaz._ 

scala> import scala.reflect.runtime.universe._ 
import scala.reflect.runtime.universe._ 

scala> showCode(reify((Option(1) |@| Option(2))(_ + _)).tree) 
res0: String = Scalaz.ToApplyOps(Option.apply(1))(Scalaz.optionInstance).|@|(Option.apply(2)).apply(((x$1, x$2) => x$1.+(x$2)))(Scalaz.optionInstance) 

scala> showCode(reify(for { a <- Option(1); b <- Option(2) } yield a + b).tree) 
res1: String = Option.apply(1).flatMap(((a) => Option.apply(2).map(((b) => a.+(b))))) 

(但是,這是不太可能在大多數程序中有意義的差異。)

如果這是貓和ab是eithers和你有「錯誤」的進口,從而使你得到FlatMapSyntaxEitherInstances而不是EitherSyntax|@|版本可能會再次更快,因爲for版本將導致至少一些額外的Unapply實例和一些其他的東西。

所以簡短的答案是肯定的,這取決於,如果你真的關心性能,你需要爲你的特定用例做仔細的基準測試。

儘管更喜歡應用版本的最佳理由與性能沒有任何關係,但它是您要執行的計算的更精確表示。你的ab不相互依賴,但for-compprehension表示他們這樣做。有關更多討論,請參閱我的回答here