2011-09-05 20 views
11

ho trovato questo modello un bel paio di volte nel mio codice:condizionale invocazione di un metodo in Scala

if (doIt) 
    object.callAMethod 
    else 
    object 

mi chiedo se ci potrebbe essere un modo sintatticamente più piacevole di scrivere il codice di cui sopra, soprattutto per evitare la ripetizione della variabile object. Qualcosa di simile:

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

Purtroppo la linea di cui sopra non riesce perché l'inferenza di tipo richiede un tipo di parametro per (_.callAMethod).

Il mio approccio migliore per ora è questo:

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) 

Non è fantastico, perché devo dichiarare un implicit val ma questo ripaga se ci sono diverse chiamate incatenate:

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

Qualcuno ha un migliore idea? Mi sto perdendo della magia degli Scalaz qui?

risposta

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) 

Esempio:

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

Non ho pensato di invertire la condizione e la funzione, grazie! – Eric

+0

Ho anche notato che un sostantivo va meglio qui di un operatore perché il '.' deve essere usato dopo" "pesce" '. – Eric

2

Non posso commentare la risposta @Rex Kerr ma un modo più conciso per farlo potrebbe essere:

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

Basta mettere la prima implicit la classe ti consente di omettere interamente la funzione implicita.

0

Se rappresenti il ​​tuo callAMethod come endomorfismo, puoi utilizzare la funzionalità monoid. Qualcosa di simile:

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

(potrebbe essere necessario un parametro di tipo sul Endo)

Problemi correlati