以更实用的方式使用Scala (scalaz)会导致性能/可维护性损失吗?



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

我想学习更多的函数式编程,并希望获得更多的类型安全,例如,通过将可变计算包装到状态转换单子等。为此,存在scalaz库。

一个问题

当我通过使用所有花哨的函数来抽象更大规模的计算时,我是否会引入无法摆脱的性能杀手?就像我的计算被单子包裹到膝盖上一样?

问题2

考虑到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])
}
关于问题一:

将计算打包到单子、应用程序、函子和其他函数中会有一些开销。但是将你的计算包装到过程、方法、对象中也是如此。

问题的核心是,计算必须有多小,这样包装才开始引人注目。没有人会在不了解项目细节的情况下告诉你这些。然而,由于Scala的混合特性,您不必一直使用单子。对于计算的高级组合,可以使用类似scalazy的样式,并在性能需要时使用本地包含的可变状态。

关于问题二:

由于我不知道你的类型签名的本质,如果scalaz将帮助你泛化计算,或者如果你将不得不绕过Scala对部分类型构造函数应用程序的有限支持,那么

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

最新更新