Skip to content

Instantly share code, notes, and snippets.

@yujikiriki
Last active August 29, 2015 14:04
Show Gist options
  • Save yujikiriki/3d1b98342de4ddc78c44 to your computer and use it in GitHub Desktop.
Save yujikiriki/3d1b98342de4ddc78c44 to your computer and use it in GitHub Desktop.
Hay alguna forma de hacerlo mejor?
case class OrderIncomeReportEntry( month: String, value: Double )
private def sumValues( entries: List[ OrderIncomeReportEntry ] ): List[OrderIncomeReportEntry] = {
val byMonth: Map[ String, List[ OrderIncomeReportEntry ] ] = entries.groupBy( e => e.month )
byMonth.foldLeft( List[OrderIncomeReportEntry]() ) {
( list, value ) =>
val sum = value._2.foldLeft( 0.0 )( ( acc, oire ) => acc + oire.value )
list.+:( OrderIncomeReportEntry( value._1, sum ) )
}
}
Rpta: [{"order":{"month":"08"},"value":200.0},{"order":{"month":"01"},"value":100.0}]
@yujikiriki
Copy link
Author

Señores, me tomó más de 6 meses ponerme al día para poder dar una respuesta al post laaaaaaargo de Vilá. Sin embargo, algunas observaciones de lo que me respondió a la solución propuesta en ese momento:

Lo primero es que pensando la implementación del Monoid me detuve en la >definición del elemento identidad y se me hizo feo eso de poner en el mes un string cualquiera ("" en el caso de Juan Pablo). Claro, uno sabe según la forma en la que se define el append puede no importar ese valor en tanto uno lo ignore (por eso es que Juan Pablo puso b.month y no a.month). Además ¿que significa en el dominio el OrderIncomeReportEntry identidad? ¿No debería ser una entidad que tenga sentido instanciar en cualquier contexto y no solamente para hacer calculos?

Dado el escenario propuesto, pienso que el monoide al tener efecto sólo sobre el campo "value" omite, sin sacrificar la semántica del problema, el campo "month".

Siendo así, creo que en vez de concentrarse en modelar en un ADT los meses como en su ejemplo final

sealed abstract class Month(name: String)
case object January extends Month("January")
case object February extends Month("February")
// etc, ...
case class OrderIncomeReportEntry[M<:Month]( month: M, value: Double )

yo me habría concentrado en modelar el campo "value" como un ADT. Algo así:

case class Money(value: Double)

case class OrderIncomeReportEntry( month: String, value: Money)

y haber creado el monoide sobre Money:

trait Monoid[T] {
  def zero: T
  def op(t1: T, t2: T): T
}

implicit def MoneyAdditionMonoid = new Monoid[Money] {
    def zero = zeroMoney
    def append(m1: Money, m2: Money) = Money(m1.value + m2.value)
}

La cosa que me queda en duda y que no se si se podría hacer es que, dado que partimos de un OrderIncomeReportEntry poder meter dentro de un lense sobre OrderIncomeReportEntry esa suma de Moneys.

Otra opción podría ser crear un tipo genérico "sumable" y crearle su monoide, que la final de cuentas termina siendo nada más que un Monoid[Double] o algo así...

Por otro lado y viendo su propuesta de semigrupos, dado que monoide es "hijo" de semigrupo y que monoide sólo agrega identidad a semigrupo, es tentador dejarlo en términos de semigrupo; solución que quizás sea la que más me convence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment