2011-09-05 15 views
11

he encontrado este patrón unas cuantas veces en mi código:invocación condicional de un método en el Scala

if (doIt) 
    object.callAMethod 
    else 
    object 

Me pregunto si podría haber una forma sintácticamente más agradable a escribir el código anterior, especialmente para evitar la repetición de la variable object. Algo así como:

// using the Scalaz "pipe" operator 
    // and "pimping" f: T => T with a `when` method 
    object |> (_.callAMethod).when(doIt) 

Desafortunadamente la línea anterior falla porque la inferencia de tipos requiere un tipo de parámetro para (_.callAMethod).

Mi mejor enfoque por ahora es la siguiente:

implicit def doItOptionally[T](t: =>T) = new DoItOptionally(t) 
    class DoItOptionally[T](t: =>T) { 
     def ?>(f: T => T)(implicit doIt: Boolean = true) = 
     if (doIt) f(t) else t 
    } 

    implicit val doIt = true 
    object ?> (_.callAMethod) 

No es muy bueno porque tengo que declarar una implicit val pero esto vale la pena si hay varias llamadas encadenadas:

 object ?> (_.callAMethod) ?> (_.callAnotherMethod) 

¿Alguien tiene una ¿mejor idea? ¿Me estoy perdiendo algo de magia Scalaz aquí?

Respuesta

16
class When[A](a: A) { 
    def when(f: A => Boolean)(g: A => A) = if (f(a)) g(a) else a 
} 
implicit def whenever[A](a: A) = new When(a) 

Ejemplo:

scala> "fish".when(_.length<5)(_.toUpperCase) 
res2: java.lang.String = FISH 
+0

No pensé de invertir el estado y la función, gracias! – Eric

+0

También observo que un sustantivo va mejor aquí que un operador porque el '.' necesita ser utilizado después de' "fish" '. – Eric

2

No puedo hacer ningún comentario sobre su respuesta @Rex Kerr, pero de una manera más concisa que hacer eso sería:

implicit class When[A](a: A) { 
    def when(f: A => Boolean)(g: A => A) = if (f(a)) g(a) else a 
} 

sólo poner el implicit antes la clase le permite omitir la función implícita por completo.

0

Si representa su callAMethod como un endomorfismo, entonces puede usar la funcionalidad monoide. Algo así como:

object |> valueOrZero(doIt, Endo(_.callAMethod)) 

(puede ser que necesite un parámetro de tipo en la Endo)

Cuestiones relacionadas