2009-12-15 7 views
19

Tant que nous avons un PartialFunction[X,R] il est très facile de le convertir en une fonction retournant Option[R], par exemple.Comment faire pour convertir X => Option [R] en fonction partielle [X, R]

def pfToOptf[X, R](f: PartialFunction[X,R])(x: X) = 
    if (f.isDefinedAt(x)) Some(f(x)) 
    else None 

Cependant, si la tâche est contraire suppose que j'ai une fonction f obtenir X comme argument et le retour Option[R] en conséquence. Et je veux en faire un PartialFunction[X,R]. Quel est le meilleur moyen?

Ce que je suis venu avec des regards assez laid à mon goût:

def optfToPf[X,R](f: X => Option[R]) : PartialFunction[X,R] = { 
    object extractor { 
     def unapply(x: X): Option[R] = f(x) 
    } 

    { case extractor(r) => r } 
} 

Y at-il une meilleure façon que je manqué?

+0

duplication possible de [Inverse de la méthode de levée de PartialFunction] (http://stackoverflow.com/questions/5902266/inverse-of-partialfunctions-lift-method) –

+0

@ToddOwen Je suis simplement curieux de savoir ce que "avant" signifie vous dans la phrase "cette question a déjà été posée". Veuillez simplement comparer les dates des deux questions. –

+0

Fermer le vote rétracté. Désolé, ce n'était pas une question de "avant", mais plutôt le fait que l'autre question semblait avoir reçu une meilleure réponse (avec 28 votes). Mais maintenant je remarque que Thayne a donné la même réponse ici. –

Répondre

27

Je sais que c'est un vieux fil, mais si quelqu'un d'autre vient à travers cela, Function.unlift fait exactement cela.

12

Que diriez-vous ceci:

Welcome to Scala version 2.8.0.r19650-b20091114020153 (Java HotSpot(TM) Client VM, Java 1.6.0_17). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> def optfToPf[X,R](f: X => Option[R]): PartialFunction[X,R] = x => f(x) match { 
    |  case Some(r) => r 
    | } 
optfToPf: [X,R](f: (X) => Option[R])PartialFunction[X,R] 

scala> 
+0

Oh !! Apparemment, j'ai besoin de réinitialiser mon cerveau en quelque sorte :) Merci beaucoup! –

+1

Cela devrait être fourni comme une conversion implicite dans 'Predef' – HRJ

5

Je suppose que vous pouvez passer outre appliquer et isDefinedAt à la main, mais je ferais la façon dont vous trouvez laid.

def optfToPf[X,R](f: X => Option[R]) = new PartialFunction[X,R] { 
    def apply(x: X): R = f(x).get 
    def isDefinedAt(x: X): Boolean = f(x) != None 
} 

Test:

scala> val map = Map(1 -> 2) 
map: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2) 

scala> map(1) 
res0: Int = 2 

scala> def mapOpt(key: Int) = map.get(key) 
mapOpt: (key: Int)Option[Int] 

scala> mapOpt(1) 
res1: Option[Int] = Some(2) 

scala> mapOpt(2) 
res2: Option[Int] = None 

scala> val mapPf = optfToPf(mapOpt _) 
mapPf: java.lang.Object with PartialFunction[Int,Int] = <function1> 

scala> mapPf.isDefinedAt(2) 
res3: Boolean = false 

scala> mapPf.isDefinedAt(1) 
res4: Boolean = true 

scala> mapPf(1) 
res5: Int = 2 

scala> mapPf(2) 
java.util.NoSuchElementException: None.get 
+1

Ensuite, je pense que je préfère substituer' apply' et 'isDefinedAt' après tout. –

+0

Merci! Bien que maintenant je suis sous l'impression que le besoin d'écrire ce code de "conversion" me signale un problème, alors j'essaie de réfléchir de façon plus approfondie. Le plus petit problème que je vois 'f (x)' sera appelé deux fois (dans le cas de 'Some') dans n'importe quelle implémentation. –

+0

Oui, il est appelé deux fois. Vous pourriez mettre en cache le résultat, mais ce serait gênant, et pas vraiment ce qui se passe dans une fonction partielle. –