[英]Will using Scala in a more functional way (scalaz) incur a performance/maintainability penalty?
我目前正在研究一個小項目(< 10k loc),該項目主要是純粹的,但依賴於可變優化,主要基於迭代器和一些數據結構重用以進行重型計算。
我想學習更多的函數式編程並希望獲得更多的類型安全性,例如將可變計算包裝到 state 變壓器單子等中。 為此,存在 scalaz 庫。
當通過使用所有花哨的功能性東西在更大范圍內抽象我的計算時,我會引入我不會擺脫的性能殺手嗎? 就像我的計算在 Monads 中被包裹得很深?
考慮到 Scala 的有限類型推斷,這是否可行? 我目前正在與非常大的類型簽名作斗爭(可能是因為我不知道如何正確擺脫它們)。 我想更多的“功能”會引入更多這樣的樣板代碼。
我不是在質疑函數式方法是好是壞。 問 Haskell 這個問題是沒有意義的。 我質疑對 Scala 這樣做是否明智。
(但這將是一個不同的問題)
以下代碼描述了對類型參數化輸入 object ( DiscreteFactorGraph[VariableType, FactorType[VariableType]]
) 的迭代計算。 您可以使用createInitialState
構造計算advanceState
並使用 AdvanceState 對其執行計算,最后使用marginals
從中提取一些信息。
我希望在計算期間保留因子圖 object (及其參數類型)的類型,以便marginals
的最終應用產生正確類型的DiscreteMarginals[VariableType]
。 我認為目前我只需要在計算類型(即TState
)中保留變量類型,因此不使用攜帶因子類型。 但在不同的地方,我什至需要DiscreteFactorGraph
的類型是可變的,所以我傾向於在未來需要更多的類型信息通過計算。
我一直在擺弄這部分,我希望有更好的解決方案。 目前我有一個非常實用的方法,其中只有這三個功能。 但我必須通過它們鏈接類型。 或者,我可以將其定義為 class 並使用所有這些類型參數化 class,因此我不必為每種方法重復類型參數。
object FloodingBeliefPropagationStepper extends SteppingGraphInferer {
def marginals[V <: DiscreteVariable, F <: DiscreteFactor[V]](state: FloodingBeliefPropagationStepper.TState[V,F]): DiscreteMarginals[V] =
BeliefPropagation.marginals(state._1, state._2)
def advanceState[V <: DiscreteVariable, F <: DiscreteFactor[V]](state: FloodingBeliefPropagationStepper.TState[V,F]): FloodingBeliefPropagationStepper.TState[V,F] = {
val graph = state._1
(graph,
BeliefPropagation.computeFactorMessages(
graph,
BeliefPropagation.computeVariableMessages(graph, state._2, graph.variables),
graph.factors))
}
def createInitialState[V <: DiscreteVariable, F <: DiscreteFactor[V]](graph: DiscreteFactorGraph[V, F],
query: Set[V],
random: Random): FloodingBeliefPropagationStepper.TState[V,F] = {
(graph,
BeliefPropagation.computeFactorMessages(
graph,
BeliefPropagation.createInitialVariableMessages(graph, random),
graph.factors))
}
type TState[V <: DiscreteVariable, F <: DiscreteFactor[V]] = (DiscreteFactorGraph[V,F],Map[(F,V),DiscreteMessage])
}
將計算包裝到 monads、applicatives、functors 和其他函數式 vodoo 中會產生一些開銷。 但是,將您的計算包裝到過程、方法、對象中也是如此。
問題的核心是,計算必須有多小,以便包裝開始變得明顯。 在不了解您項目的一些細節的情況下,沒有人會告訴您這一點。 然而,由於 Scala 的混合特性,您不必一直使用 go 單子。 很有可能將類似 scalaz 的樣式用於更高級別的計算組合,並在性能需要時使用本地包含的可變 state。
由於我不知道您的類型簽名的性質,因此 scalaz 是否會通過泛化計算來幫助您,或者您是否必須圍繞 Scala 對部分類型構造函數應用程序的有限支持進行鍵入。
如果您的類型簽名 go 失控,我建議您嘗試在 package object 中聲明類型別名並使用它們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.