Stile codice per i metodi di analisi in Scala?

4

Dire che ho una classe con più parametri:

case class Foo(a: String, b: String, c: String, d: String, ... )

Ora dì che voglio analizzare un'istanza di Foo da Map[String, String] :

// returns either the parsed Foo as Right, or error message as Left
// example: Map("a" -> "1", "b" -> "2" ... ) returns Foo("1", "2", ... )
def parse(fromMap: Map[String, String]): Either[String, Foo]

I nomi delle chiavi sono irrilevanti; questo non è un tipo di domanda di riflessione.

La mia implementazione è simile a questa:

fromMap.get("a") match {
    case None => Left("couldn't find a")
    case Some(a) => fromMap.get("b") match {
        ...
                                case Some(last) => Right(Foo(a, ... , last))
    }
}

Ma quando ci sono molti parametri, il rientro è troppo estremo e questo rende difficile capire la logica del metodo (potrebbe essere un po 'più complesso di una semplice ricerca di mappe).

Riesci a pensare a un codice più leggibile per tale caso d'uso?

    
posta Eyal Roth 23.05.2016 - 19:23
fonte

1 risposta

6

Potresti creare il tuo metodo personalizzato per estrarre i valori di Map come un'istanza di Either e usarli in a for comprehension:

implicit final class MapOps[A, B](self: Map[A, B]) {
  def getAsEither(key: A): Either[String, B] = {
    self.get(key) match {
      case Some(value) => Right(value)
      case _ => Left(s"Key not found: $key")
    }
  }
}

case class Foo(a: String, b: String, c: String, d: String)

def parse(input: Map[String, String]): Either[String, Foo] = {
  for {
    a <- input.getAsEither("a").right
    b <- input.getAsEither("b").right
    c <- input.getAsEither("c").right
    d <- input.getAsEither("d").right
  } yield Foo(a, b, c, d)
}

Questo potrebbe essere accorciato un po '(tutte quelle chiamate di .right potrebbero essere rimosse) ma richiederebbe l'implementazione corretta di Either (es. Scala'z \/ o % co_dei gatti )

    
risposta data 23.05.2016 - 20:28
fonte

Leggi altre domande sui tag