2009-12-17 3 views
5

Supposons que cette fonction:Est-il possible de reculer dans l'autre sens à Scala?

def autoClosing(f: {def close();})(t: =>Unit) = { 
    t 
    f.close() 
} 

et cet extrait:

val a = autoClosing(new X)(_) 
a { 
println("before close") 
} 

est-il possible de curry la première partie? Quelque chose comme:

val a = autoClosing(_) { println("before close") } 

pour que je puisse envoyer les objets sur lesquels doivent être effectuées à proximité, et ont le même bloc exécuté sur eux?

Répondre

10

Oui, l'extrait que vous avez donné fonctionne, à condition que vous donniez le type du caractère fictif.

Par conséquent, le code que vous recherchez est:

val a = autoClosing(_: {def close();}) { println("before close") } 

qui compile et fonctionne comme prévu :).

Quelques notes:

  • Vous pouvez vous rendre la vie plus facile si vous définissez un alias de type pour un type AnyRef ayant une méthode close, quelque chose comme type Closeable = AnyRef {def close()}, ou une interface appropriée.
  • L'extrait de code autoClosing(_: Closeable){ ... } est en réalité équivalent à la fonction anonyme étendue suivante: c: Closeable => autoClosing(c){ ... }. Le caractère générique est juste un raccourci pour une fonction partiellement appliquée. Vous devez donner le type de _ car le type inferer ne peut malheureusement pas déduire le type dans ce cas.

Hope it helps,

- Flaviu Cipcigan

+0

Type de verbeux. Mersi :) – Geo

+0

De rien. Ajout d'un couple de notes pour développer ma réponse :). Malheureusement, le type inferer ne peut pas déduire le type du caractère générique ici. –

6

Sinon, vous pouvez retourner les paramètres:

def flip[A1, A2, B](f: A1 => A2 => B): A2 => A1 => B = x1 => x2 => f(x2)(x1) 

Dans votre cas:

val a = flip(autoClosing){ println("before close") } 

Edit: J'ai ajouté un soutien-gorge bureaux pour aider l'analyseur humain:

def flip[A1, A2, B](f: (A1 => (A2 => B))): (A2 => (A1 => B)) = { 
    x1 => (x2 => f(x2)(x1)) 
} 

flip convertit une fonction (A1 => (A2 => B)) à (A2 => (A1 => B)).

scala> def x(x1 : Int)(x2 : Long) = 1.0 * x1/x2 
x: (Int)(Long)Double 

scala> val f = flip(x) 
f: (Long) => (Int) => Double = <function> 

scala> val g = f(1) 
g: (Int) => Double = <function> 

scala> val h = g(2) 
h: Double = 2.0 

scala> x(1)(2) 
res0: Double = 0.5 
+0

Pouvez-vous expliquer ce monstre un peu? :) – Geo

+0

J'ai ajouté quelques accolades et un exemple de code pour voir l'application partielle en action. J'espère que cela t'aides. –

3

Je suis heureux de voir autant de gens répondre aux questions de Scala de nos jours. Cependant, il est plus difficile pour moi de trouver quelque chose. Voici une alternative à Flaviusolution.

val a: {def close();} => Unit = autoClosing(_) { println("before close") } 

Bien sûr, la bonne solution est de définir autoClosing d'une manière compatible avec la façon dont vous allez l'utiliser.

+0

Je suis heureux à ce sujet aussi :). J'abandonne Ruby pour Scala ... il y a tout ce que je voulais dans une langue. – Geo