Domanda

Ho trovato questo modello di un bel paio di volte nel mio codice:

  if (doIt)
    object.callAMethod
  else
    object

Mi chiedo se ci potrebbe essere un modo sintatticamente più piacevole di scrivere il codice di cui sopra, in particolare al fine di 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 concatenati:

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

Qualcuno ha un'idea migliore? Mi sto perdendo un po 'di magia Scalaz qui?

È stato utile?

Soluzione

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

Altri suggerimenti

Non posso commentare sul tuo risposta @Rex Kerr, ma una concisa altro modo per farlo sarebbe:

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

Basta mettere il implicit prima della classe consente di omettere la funzione implicita del tutto.

Se rappresentate tuo callAMethod come un endomorfismo quindi è possibile utilizzare la funzionalità monoide. Qualcosa di simile:

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

(potrebbe essere necessario un parametro di tipo sul Endo)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top