La différence sémantique a été expliqué assez bien dans la réponse liée à la Plastie Grove.
En termes de fonctionnalités, il ne semble pas beaucoup de différence, si. Regardons quelques exemples pour vérifier que. Tout d'abord, une fonction normale:
scala> def modN(n: Int, x: Int) = ((x % n) == 0)
scala> modN(5, _ : Int)
res0: Int => Boolean = <function1>
Nous obtenons donc un partiellement appliquée <function1>
qui prend un Int
, car nous avons déjà donné le premier entier. So far So good. Maintenant, pour lancer:
scala> def modNCurried(n: Int)(x: Int) = ((x % n) == 0)
Avec cette notation, vous pensez naïvement attendons la suite du travail:
scala> modNCurried(5)
<console>:9: error: missing arguments for method modN;
follow this method with `_' if you want to treat it as a partially applied function
modNCurried(5)
Donc les multiples paramètres de la liste de notation ne semble pas vraiment à créer un curry de fonction (assumingly pour éviter une surcharge inutile), mais attend que vous pour indiquer explicitement que vous voulez au curry (la notation a quelques autres avantages en tant que bien):
scala> modNCurried(5) _
res24: Int => Boolean = <function1>
Ce qui est exactement la même chose que nous avons eu avant, donc pas de différence ici, sauf pour la notation. Un autre exemple:
scala> modN _
res35: (Int, Int) => Boolean = <function2>
scala> modNCurried _
res36: Int => (Int => Boolean) = <function1>
Cela démontre comment partiellement l'application d'une fonction "normale" des résultats dans une fonction qui prend tous les paramètres, tandis que partiellement l'application d'une fonction avec plusieurs paramètre listes crée une chaîne de fonctions, un par liste de paramètres qui, de retour d'une nouvelle fonction:
scala> def foo(a:Int, b:Int)(x:Int)(y:Int) = a * b + x - y
scala> foo _
res42: (Int, Int) => Int => (Int => Int) = <function2>
scala> res42(5)
<console>:10: error: not enough arguments for method apply: (v1: Int, v2: Int)Int => (Int => Int) in trait Function2.
Unspecified value parameter v2.
Comme vous pouvez le voir, parce que le premier paramètre de la liste d' foo
a deux paramètres, la première fonction dans le curry de la chaîne dispose de deux paramètres.
En résumé, l'application partielle de fonctions ne sont pas vraiment différentes de la forme des fonctions curryfiées en termes de fonctionnalité. C'est facile à vérifier étant donné que vous pouvez convertir n'importe quelle fonction pour un au curry:
scala> (modN _).curried
res45: Int => (Int => Boolean) = <function1
scala> modNCurried _
res46: Int => (Int => Boolean) = <function1>
Post Scriptum
Note: La raison pour laquelle votre exemple println(filter(nums, modN(2))
fonctionne sans le trait de soulignement après modN(2)
semble être que le compilateur Scala suppose simplement que le trait de soulignement comme une commodité pour le programmeur.
Plus: Comme @asflierl a souligné à juste titre, de la Scala ne semblent pas être en mesure de déduire le type partiellement l'application "normale" fonctions:
scala> modN(5, _)
<console>:9: error: missing parameter type for expanded function ((x$1) => modN(5, x$1))
Alors que l'information est disponible pour les fonctions de l'écrit à l'aide de multiples paramètres de la liste de notation:
scala> modNCurried(5) _
res3: Int => Boolean = <function1>
Cela répond montre comment cela peut être très utile.