Skip to content

Files

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Latest commit

55d96a1 · Dec 2, 2021

History

History
103 lines (69 loc) · 3.29 KB

multiple-parameter-lists.md

File metadata and controls

103 lines (69 loc) · 3.29 KB
layout title partof num language next-page previous-page
tour
Multiple Parameter Lists (Currying)
scala-tour
12
fr
case-classes
nested-functions

Les méthodes peuvent avoir plusieurs listes de paramètre.

Exemple

Voici un exemple, défini sur le trait Iterable dans l'API collections de Scala :

trait Iterable[A] {
  ...
  def foldLeft[B](z: B)(op: (B, A) => B): B
  ...
}

foldLeft applique une fonction à deux paramètres op sur une valeur initiale z et tous les éléments de la collection, en allant de gauche à droite. Comme montré ci-dessous, un exemple d'utilisation.

En partant d'une valeur initiale de 0, ici foldLeft applique la fonction (m, n) => m + n à chaque élément de la liste avec la valeur précédemment accumulée.

{% scalafiddle %}

val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val res = numbers.foldLeft(0)((m, n) => m + n)
println(res) // 55

{% endscalafiddle %}

Cas d'usage

Les cas d'usage suggérés pour les listes multiples de paramètre incluent :

Commander l'inférence de type

Il se trouve qu'en Scala, l'inférence de type résout une liste de paramètre à la fois. Disons que vous avez la méthode suivante :

def foldLeft1[A, B](as: List[A], b0: B, op: (B, A) => B) = ???

Vous aimeriez l'appeler de la façon suivante, mais vous verriez que cela ne compile pas :

def notPossible = foldLeft1(numbers, 0, _ + _)

Vous auriez à l'appeler selon l'une des manières suivantes :

def firstWay = foldLeft1[Int, Int](numbers, 0, _ + _)
def secondWay = foldLeft1(numbers, 0, (a: Int, b: Int) => a + b)

C'est parce que Scala ne sera pas capable d'inférer le type de la fonction _ + _, puisqu'il sera toujours en train d'inférer A et B. En déplaçant le paramètre op dans sa propre liste de paramètre, A et B seront inférés dans la première liste de paramètre. Ces types déjà inférés seront disponibles pour la seconde liste de paramètre et _ + _ correspondra au type inféré (Int, Int) => Int.

def foldLeft2[A, B](as: List[A], b0: B)(op: (B, A) => B) = ???
def possible = foldLeft2(numbers, 0)(_ + _)

Cette définition n'a pas besoin d'aide et peut inférer tout ses types de paramètres.

Paramètre implicite

Pour spécifier seulement certains paramètres comme implicit, ils doivent être placés dans leur propre liste de paramètre implicit.

Un exemple de cela :

def execute(arg: Int)(implicit ec: scala.concurrent.ExecutionContext) = ???

Application partielle

Quand une méthode est appelée sans toutes ses listes de paramètre, alors cela va générer une fonction prennant les listes de paramètre restantes comme arguments. C'est formellement appelé une partial application.

Par exemple,

val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val numberFunc = numbers.foldLeft(List[Int]()) _

val squares = numberFunc((xs, x) => xs :+ x*x)
println(squares) // List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)

val cubes = numberFunc((xs, x) => xs :+ x*x*x)
println(cubes)  // List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)

Traduit par Antoine Pointeau.