16

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

我想学习更多的函数式编程并希望获得更多的类型安全性,例如通过将可变计算包装到状态转换器单子等中。为此,存在 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])
}
4

1 回答 1

5

关于问题一:

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

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

关于问题二:

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

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

于 2011-08-17T08:27:06.337 回答