La programmazione funzionale suggerisce strongmente di separare i dati dai comportamenti (funzioni). Tuttavia, non riesco a vedere il vantaggio di questo per un'implementazione di un algoritmo intrinsecamente legata a particolari dati delle impostazioni.
Ad esempio, supponiamo che esista un tratto LagrangeAlgorithmOOP
con dati immutabili come le impostazioni algoritmiche, le specifiche del problema e le dipendenze dagli helper. I metodi del tratto usano tutti questi dati per trovare una soluzione al problema. La loro implementazione è specifica per il tipo dell'algoritmo. Quasi nessuno di questi avrebbe senso come funzione autonoma.
Specificamente, supponiamo di avere un refactoring
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
}
in questo
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
}
Il secondo caso introduce una classe di dati e un parametro aggiuntivo in ciascun metodo. (Invece, potrei usare una monade Reader, che tuttavia richiederebbe anche trasformatori monad).
Domande:
- Qual è il miglior refactoring di questo algoritmo per uno stile FP?
- È possibile che un approccio a metà strada funzioni meglio: ad esempio, per lasciare alcuni dei campi dati nel tratto?
- C'è molta differenza tra le versioni originale e refactored?
- Qual è il vantaggio del refactoring in stile FP in questo caso?
Nota: sono d'accordo con molti punti nel post correlato Perché" accoppiamento stretto tra funzioni e dati "è errato? . Ancora non sono sicuro di come questo si applica ai dati delle impostazioni immutabili che sono intrinseci alle funzioni che implementano l'algoritmo.