Functional programming strongly suggests to separate data from behaviours (functions). However, I can't see the benefit of this for an algorithm's implementation intrinsically tied with particular settings data.
For example, suppose there's a trait LagrangeAlgorithmOOP
with immutable data being the algorithmic settings, problem specification and dependencies on helpers. The trait's methods all use this data to find a problem solution. Their implementation is specific to the algorithm's type. Almost none of would make sense as a stand-alone function.
Specifically, suppose we refactor
trait LagrangeAlgorithOOP {
val settings: SettingsLagrange
val problem: ConstrainedProblem
val innerMinimiser: Minimiser
val penaltiesFunction: ConstraintPenaltiesFunction
def iteration( s: StateLagrange): Either[String, StateLagrange]
def lagrangeFunction( lams: Lambdas, pens: Penalties): AugmentedLagrangianFunction
def estimateLambdas( pens: Penalties, las: Lambdas, cons: ConstraintValues): Option[Lambdas]
def updatePenaltiesHistory( h: HistoryLagrange): HistoryLagrange
}
into this
case class LagrangeData(settings: SettingsLagrange,
problem: ConstrainedProblem,
innerMinimiser: Minimiser,
penaltiesFunction: ConstraintPenaltiesFunction)
trait LagrangeAlgorithmFUN {
def iteration(d: LagrangeData, s: StateLagrange): Either[String, StateLagrange]
def lagrangeFunction(d: LagrangeData, lams: Lambdas, pens: Penalties): Lagrangian
def estimateLambdas(d: LagrangeData, pens: Penalties, old: Lambdas, cons: ConstraintValues): Option[Lambdas]
def updatePenaltiesHistory(d: LagrangeData, h: HistoryLagrange): HistoryLagrange
}
The latter case introduces a data class and an extra parameter into each method. (Instead, I could use a Reader monad, which would, however, also require monad transformers.)
Questions:
- What is the best refactoring of this algorithm to an FP style?
- Could some half-way approach work better: eg, to leave some of the data fields in the trait?
- Is there much difference between the original and refactored versions?
- What is the benefit of refactoring to FP-style in this case?
Note: I agree with many points in the related post Why is "tight coupling between functions and data" bad?. Still I'm not sure how this applies to immutable settings data that is intrinsic to the functions implementing the algorithm.
repeat (o.iteration(s))
and the "FP" - style functionrepeat (iteration(d, s))
, whereo: LagrangeAlgorithm
,s: State
andd: LagrangeData
. If there is no essential difference, then both code snippets in the post are essentially equivalent, aren’t they?