La production d'une fonction partiellement appliquée de procédé de type dans une option

StackOverflow https://stackoverflow.com/questions/7354768

Question

Supposons que j'écris une interface graphique

entrer image description ici

class Kitteh (val age: Int) {
  require (age < 5)
  def saveMeow(file: File) = { /* implementation */ }
  def savePurr(file: File) = { /* implementation */ }
}

Le cadre a un champ pour le Kitteh actuel, qui est un Option parce qu'il pourrait ne pas avoir encore été défini, ou l'utilisateur peut avoir tenté de créer un un invalide:

var currentKitteh: Option[Kitteh] = None

Maintenant, je veux créer un Kitteh en toute sécurité lorsque l'utilisateur clique Créer

val a = ... // parse age from text box
currentKitteh = try { Some(new Kitteh(a)) } catch { case _ => None }

GUI Mon a deux boutons qui font des choses semblables. En psedocode, ils doivent à la fois

if (currentKitteh.isDefined) {
  if (file on the disk already exists) {
    bring up a dialog box asking for confirmation
    if (user confirms)
       << execute method on currentKitteh >>
  }
}
else bring up warning dialog

Ne vous inquiétez pas au sujet du détail: le point est que parce qu'il ya duplication de code, je veux créer une méthode commune que je peux appeler des deux boutons. La seule différence est la méthode sur la Kitteh qui doit exécuter.

Maintenant, si currentKitteh n'était pas un Option, la méthode commune pourrait avoir une signature comme

def save(filename: String, f:(File => Unit)) {

que je pourrais appeler, par exemple

save("meow.txt", currentKitteh.saveMeow _)

mais comme il est en fait une option, comment pourrais-je mettre en œuvre cette?

Je pourrais vérifier si currentKitteh est défini, et faire un .get avant d'appeler la méthode save pour chaque bouton, mais est-il une autre façon, en laissant cette vérification dans la méthode save? En d'autres termes, étant donné un Option[A], il est possible de spécifier une fonction partielle d'une méthode sur le (éventuellement nulle) objet A?

(espérons que cette question est logique, par exemple alambiquée malgré)

modifier : Question bonus: si, au lieu de Option[Kitteh], je Either[Throwable, Kitteh]

mise à jour : Ligne supplémentaire ajouté à pseudocode pour faire apparaître de dialogue d'avertissement. Idéalement, la méthode save doit toujours être appelé afin que l'utilisateur est averti s'il n'y a pas Kitteh valide pour sauver

Était-ce utile?

La solution

Cela ressemble à la meilleure option pour moi:

currentKitteh foreach { c => save("meow.txt", c.saveMeow _) }

Si vous faites à plusieurs reprises, vous pouvez abstraire,

def currentSaveMeow(file: String) = currentKitteh foreach { c =>
  save(file, c.saveMeow _)
}
currentSaveMeow("meow.txt")

Je suppose que pour répondre à votre question initiale, vous pouvez aussi pousser la logique dans l'argument de la fonction,

save("meow.txt", file => currentKitten.foreach(_.saveMeow(file)))

La sémantique est un peu différent avec cette version.

Mise à jour . Si k: Option[Kitteh] est remplacé par k: Either[Throwable, Kitteh], alors qu'en est-k.right foreach { c => ... }? Vous pouvez également utiliser k.right map ... si vous souhaitez conserver des informations d'erreur.


En réponse à la question modifiée, voici une autre possibilité d'abstraction,

def save(filename: String, f: (Kitteh, File) => Unit)

save a la responsabilité de déballer currentKitteh. Appel save comme ça,

save("meow.txt", (k, f) => k.saveMeow(f))

ou comme celui-ci,

save("meow.txt", _ saveMeow _)

Autres conseils

Vous pouvez mapper une fonction et getOrElse votre fonction échouer:

def save = 
  o map {s => () => "saved a kitteh! " + s} getOrElse {() => "oh noes, no kittehs!"}

vous simplement:

save()

Vous pourriez définir une classe BadKitteh et ont produit que des messages d'erreur. Ensuite, utilisez simplement currentKitty.getOrElse (badkitty) si vous en avez besoin.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top