【问题标题】:Will using Scala in a more functional way (scalaz) incur a performance/maintainability penalty?以更实用的方式(scalaz)使用 Scala 会导致性能/可维护性损失吗?
【发布时间】:2011-08-17 07:41:48
【问题描述】:

我目前正在从事一个小型项目(

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

问题一

当通过使用所有花哨的功能性东西在更大规模上抽象我的计算时,我会引入我无法摆脱的性能杀手吗?就像我的计算在 Monads 中被包裹得很深?

问题二

考虑到 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])
}

【问题讨论】:

  • 你能举一个或几个你的大字体签名的例子吗?
  • 你的类型签名是无法管理的,因为你选择了像FloodingBeliefPropagationStepper.TState这样长得令人难以置信的名字。如果您追求高性能解决方案,使用DiscreteVariable 而不是Int 或类似的可能会导致最大的性能损失(除非您实际上需要对变量做很少的事情)。到目前为止,代码看起来像是为了最大化抽象而不是性能而编写的。那么你真的应该对性能有多担心呢?
  • @Rex DiscreteVariable 只是对变量本身的描述,不保存任何状态(用于保存计算状态的具体数据结构是在“问题规范”的较低级别创建的" 由图表描述)。实际上,您正在查看一个抽象类,并且计算处于较低级别,例如BeliefPropagation
  • @ziggystar - 好的,在这种情况下,很难判断使用 Scalaz 是否会对性能产生负面影响,因为您没有提供有关正在执行哪种计算的任何详细信息。因此,答案是“也许”。
  • 作为编写大量高性能代码的人,我可以向您保证,如果您不小心地将数据打包成可以可变计算的原始类型,您的代码在大多数情况下都会执行与 C++ 之类的相比较差。斯卡拉兹也不例外。不过,我还不能评论 Scalaz 与非 Scalaz 函数式不可变样式的相对性能,这就是为什么这是评论而不是答案。

标签: performance scala scalaz


【解决方案1】:

关于问题一:

将计算包装到 monads、applicatives、functors 和其他函数式 vodoo 中会产生一些开销。但是,将您的计算包装到过程、方法、对象中也是如此。

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

关于问题二:

由于我不知道您的类型签名的性质,因此 scalaz 是否可以通过泛化计算来帮助您,或者您是否必须绕开 Scala 对部分类型构造函数应用程序的有限支持。

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

【讨论】:

  • 我也想把函数式的东西只应用到更高的层次,但想知道这是否可能。感谢您向我保证。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-02
  • 1970-01-01
  • 1970-01-01
  • 2020-03-25
  • 2012-04-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多