10
votes

Scala - Currying et arguments par défaut

J'ai une fonction avec deux listes de paramètres que j'essaye de s'appliquer partiellement et d'utiliser avec Currying. La deuxième liste de paramètres contient des arguments qui ont toutes des valeurs par défaut (mais pas implicites). Quelque chose comme ceci: xxx pré>

MAINTENANT, ce qui suit est bien: p> xxx pré>

maintenant si je définis: p>

class Test2(val a: Int) {
   def apply(b: Int = 2, c: Int = 3) { println(a + ", " + b + ", " + c); }
}

def test2(a: Int) = new Test2(a);
def partial2 = test2(1); // Note no underscore

test2(1)(2, 3);
test2(1)(2);
test2(1)(c=3);
test2(1)();

partial2(2, 3)
partial2(2);
partial2(c=3);
partial2();


3 Réponses :


6
votes

Le moteur d'inférence de type donne à partiel le type de ce qui vient ensuite; I.e., l'expansion de l'ETA Test (1) _ . Vous pouvez voir par ex. Dans la région, que partiel a type (int, int) => unité , alors que test a type (A: int) ( B: INT, C: INT) unité . Le résultat de l'expansion ETA est une fonction , qui ne porte aucun nom d'argument avec celui-ci (car il est possible de définir la fonction avec des paramètres anonymes).

Pour résoudre ce problème, vous devez définir partiel comme suit: xxx

peut-être que vous voudrez peut-être facturer les valeurs par défaut où les deux Test et partiel peut les atteindre pour s'assurer qu'ils restent égaux. Mais je ne connais aucun truc pour éviter de répéter les noms des paramètres sans introduire des frais généraux supplémentaires comme la création de nouveaux objets, etc.


7 commentaires

L'objet fonction contient des noms d'arguments, mais ce sont les noms d'arguments définis dans Fonction2 Vous pouvez réellement appeler l'exemple donné par @desperate de cette façon: partial (V1 = 2, v2 = 3) .


Je pensais que cela fallait faire avec le compilateur ne créant pas de nouvelles classes pour des fonctions telles que celles-ci mais en utilisant la fonction "générique "2 à la place. Sinon, cela aurait pu stocker toutes les informations dont il a besoin dans les annotations. Tout le point était d'éviter de répéter des noms d'arguments / liste, cependant :(


@Moritz, je me rends compte que, mais ce n'est pas utile du tout quand on veut préserver des noms appropriés. Ceci est vraiment une déficience si ce n'est pas un défaut de la langue. Je n'ai jamais compris pourquoi Scala tente de réutiliser la fonction pré-créée classes au lieu de les générer au besoin. Je sais que cela générerait plus de cours, mais ce serait à la fois la bonne chose à faire et utile à la fin. Sur une note latérale, je vais essayer de générer un nouvel objet similaire à celui de la fonction, avec «Appliquer» la méthode ...


@Desperate Je n'ai pas dit que c'était utile - cela pourrait même être nocif si vos paramètres avaient les mêmes noms dans un ordre différent. Scala génère en fait une sous-classe de des cas de fonctionnement comme ceci, mais qui renvoie un sous-type spécialisé ici ferait une surcharge assez délicate.


C'est le meilleur que je puisse faire moi-même jusqu'à présent: CLASS TEST2 (VAL A: INT) {DEF Appliquer (B: INT = 2, C: INT = 3) {PrintLN (A + "," + B + "," + c); }} def test2 (A: int) = nouveau test2 (a); DEF partielle2 = Test2 (1); // NOTE Aucun test de soulignement2 (1) (2, 3); Test2 (1) (2); test2 (1) (c = 3); test2 (1) (); partielle2 (2, 3) partielle2 (2); partielle2 (c = 3); partielle2 (); De cette façon ça marche ...


@ Désespéré / @ apprenant cool! Veuillez le poster comme une réponse aussi, ce sera plus lisible.


Je veux ... mais je ne suis pas encore autorisé (moins de 24h puisque j'ai posté la question)



2
votes

Suivi de votre commentaire, voici un moyen plus compact pour l'écrire:

 java.lang.Object{def apply(b: Int,c: Int): Unit; def apply$default$1: 
 Int @scala.annotation.unchecked.uncheckedVariance; def apply$default$2: Int 
 @scala.annotation.unchecked.uncheckedVariance}


0 commentaires

4
votes

C'est le meilleur que je puisse faire moi-même jusqu'à présent: xxx

de cette façon fonctionne ...


0 commentaires