是否会以更具功能性的方式使用Scala(scalaz)会导致性能/可维护性损失?

时间:2011-08-17 07:41:49

标签: performance scala scalaz

我目前正在开发一个小型项目(< 10k loc),它主要是纯粹的,但依赖于主要基于迭代器的可变优化和用于重载计算的一些数据结构重用。

我想学习更多功能性编程,并希望获得更多的类型安全性,例如将可变计算包装到状态变换器monad等中。为此目的,存在scalaz库。

问题一

当通过使用所有奇特的功能来大规模地抽象我的计算时,我会介绍我不会摆脱的性能杀手吗?就像我的计算被蒙纳德的膝盖深深地包裹起来一样?

问题二

考虑到Scala的有限类型推断,它是否可行?我目前正在与非常大的类型签名(可能因为我不知道如何正确摆脱它们)。我认为更多“功能性”将会引入更多这样的样板代码。

声明

我不会质疑功能方法是好还是坏。向Haskell提出这个问题毫无意义。我在质疑Scala是否合情合理。

根据要求编辑:项目中大型签名的示例

(但这是一个不同的问题)

以下代码描述了对类型参数化输入对象(DiscreteFactorGraph[VariableType, FactorType[VariableType]])的迭代计算。您可以使用createInitialState构造一个计算对象,并使用advanceState对其进行计算,最后使用marginals从中提取一些信息。

我希望在计算过程中保留因子图对象的类型(及其参数类型),以便marginals的最终应用程序生成正确类型的DiscreteMarginals[VariableType]。我认为目前我只需要在计算类型(TState)中保留变量类型,因此不使用携带因子类型。但是在不同的地方我甚至需要DiscreteFactorGraph的类型是可变的,所以我往往需要在将来通过计算提供更多的类型信息。

我很喜欢这部分,我希望有更好的解决方案。目前我有一个非常实用的方法,只有那三个功能。但我必须通过它们链接类型。或者,我可以将它定义为一个类,并使用所有这些类型对类进行参数化,因此我不必为每个方法重复类型参数。

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])
}

1 个答案:

答案 0 :(得分:5)

关于问题一:

通过将计算包装到monad,applicatives,functor和其他功能性vodoo中会有一些开销。但是将计算包装到过程,方法和对象中也是如此。

问题的核心是,计算必须有多小,以便包装开始变得明显。如果不了解项目的某些细节,那就是没人会告诉你的。然而,由于Scala的混合性质,你不必一直走下monad。很有可能将类似scalaz的样式用于计算的更高级别的组合,并使用性能需要的本地包含的可变状态。

关于问题二:

由于我不知道你的类型签名的性质,如果scalaz会通过推广计算来帮助你,或者你将不得不键入Scala对部分类型构造函数应用程序的有限支持。

如果您的类型签名失控,我建议您尝试在包对象中声明类型别名并使用它们。