В настоящее время я работаю над небольшим проектом (<10k loc), который в основном чистый, но полагается на изменяемые оптимизации, в основном основанные на итераторах и повторном использовании некоторых структур данных для сложных вычислений.
Я бы хотел немного изучить функциональное программирование и повысить безопасность типов, например, обертывание изменяемых вычислений в монады преобразователей состояний и т.п. Для этой цели существует библиотека scalaz.
При абстрагировании моих вычислений в более крупном масштабе с использованием всех причудливых функциональных вещей, я введу убийцы производительности, от которых я не избавлюсь? Например, когда мои вычисления по колено в монадах?
Возможно ли это вообще с учетом ограниченного вывода типов в Scala? В настоящее время я борюсь с очень большими подписями типа (возможно, потому, что я не знаю, как правильно от них избавиться). Я полагаю, что переход к более «функциональному» приведет к появлению еще большего количества такого шаблонного кода.
Я не сомневаюсь, хорош или плох функциональный подход. Задавать этот вопрос для Haskell бессмысленно. Я сомневаюсь, имеет ли смысл делать это для Scala.
(но это был бы другой вопрос)
Следующий код описывает итеративное вычисление на объект ввода с параметризацией типа ( DiscreteFactorGraph [VariableType, FactorType [VariableType]]
). Вы можете создать объект вычисления с помощью createInitialState
и выполнить вычисления с помощью advanceState
и, наконец, извлечь из него некоторую информацию с помощью маргиналов
.
Мне нужен тип объекта факторного графа (и его типы параметров) должны быть сохранены во время вычислений, чтобы окончательное применение маргиналов
давало правильный тип 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])
}