322 votes

Quel est le rendement de Scala?

Je comprends le rendement de Ruby et Python. Que fait le rendement de Scala?

842voto

Daniel C. Sobral Points 159554

Je pense que l'on a accepté la réponse est grande, mais il semble que beaucoup de gens ont échoué à saisir quelques points fondamentaux.

Tout d'abord, Scala "pour les interprétations de la" équivalent à Haskell "faire" de la notation, et il n'est rien de plus qu'un sucre syntaxique pour la composition de plusieurs monadique opérations. Que cette déclaration ne sera probablement pas aider quelqu'un qui a besoin d'aide, essayez encore une fois... :-)

Scala "pour des compréhensions" est sucre syntaxique pour la composition de plusieurs opérations à la carte, flatMap et le filtre. Ou foreach. Scala en fait traduit une expression dans les appels à ces méthodes, de sorte que toute classe, ou un sous-ensemble d'entre eux, peuvent être utilisés pour des compréhensions.

Tout d'abord, nous allons parler des traductions. Il y a des règles très simples:

1) Cette

for(x <- c1; y <- c2; z <-c3) {...}

est traduit en

c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))

2) Ce

for(x <- c1; y <- c2; z <- c3) yield {...}

est traduit en

c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))

3) Cette

for(x <- c; if cond) yield {...}

se traduit sur Scala de 2,7 en

c.filter(x => cond).map(x => {...})

ou, sur Scala 2.8, en

c.withFilter(x => cond).map(x => {...})

avec un repli dans l'ancien si la méthode withFilter n'est pas disponible, mais filter . Consultez l'édition ci-dessous pour plus d'informations sur cette.

4) Ce

for(x <- c; y = ...) yield {...}

est traduit en

c.map(x => (x, ...)).map((x,y) => {...})

Quand vous regardez très simple pour des compréhensions, de la carte/foreach alternatives look, en effet, mieux. Une fois que vous commencez à composer eux, cependant, vous pouvez facilement se perdre dans les parenthèses et les niveaux d'imbrication. Lorsque cela se produit, pour des compréhensions sont généralement beaucoup plus claire.

Je vais vous montrer un exemple simple, et volontairement omettre aucune explication. Vous pouvez décider quelle syntaxe est plus facile à comprendre.

l.flatMap(sl => sl.filter(el => el > 0).map(el => el.toString.length))

ou

for{
  sl <- l
  el <- sl
  if el > 0
} yield el.toString.length

MODIFIER

Scala 2.8 introduit une méthode appelée withFilter, dont la principale différence est que, au lieu de retourner un nouveau, de les filtrer, de collection, il les filtres sur la demande. L' filter méthode a son comportement défini sur la base de la rigueur de la collection. Pour mieux comprendre ce processus, nous allons jeter un oeil à quelques Scala 2.7 List (strict) et Stream (non stricte):

scala> var found = false
found: Boolean = false

scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9

scala> found = false
found: Boolean = false

scala> Stream.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3

La différence se produit parce que le filtre est appliqué immédiatement avec List, de retour d'une liste de cotes -- depuis found est false. Alors seulement, foreach est exécuté, mais, par ce temps, en changeant found est vide de sens, comme filter a déjà été exécutée.

Dans le cas d' Stream, la condition n'est pas immédiatement appliquées. Au lieu de cela, chaque élément est demandé par foreach, filter tests de l'état, qui permet aux foreach de l'influencer par found. Juste pour préciser, ici, c'est l'équivalent pour les-de la compréhension du code:

for (x <- List.range(1, 10); if x % 2 == 1 && !found) 
  if (x == 5) found = true else println(x)

for (x <- Stream.range(1, 10); if x % 2 == 1 && !found) 
  if (x == 5) found = true else println(x)

Cela a causé beaucoup de problèmes, parce que les gens devraient l' if pour être considéré à la demande, au lieu d'être appliquée à l'ensemble de la collection à l'avance.

Scala 2.8 introduite withFilter, ce qui est toujours non-stricte, peu importe la sévérité de la collection. L'exemple suivant montre List avec les deux méthodes sur Scala 2.8:

scala> var found = false
found: Boolean = false

scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9

scala> found = false
found: Boolean = false

scala> List.range(1,10).withFilter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3

Ce qui produit le résultat plupart des gens attendent, sans changer la façon dont filter se comporte. Comme une note de côté, Range a été modifié à partir de la non-strict strict entre Scala 2.7 et Scala 2.8.

210voto

Dario Points 26259

Il est utilisé dans la séquence de compréhensions (comme le Python de la liste des inclusions et des générateurs, où vous pouvez utiliser yield aussi).

Il est appliqué en combinaison avec d' for , et a écrit un nouvel élément dans la séquence.

Exemple Simple (à partir de la scala-lang)

/** Turn command line arguments to uppercase */
object Main {
  def main(args: Array[String]) {
    val res = for (a <- args) yield a.toUpperCase
    println("Arguments: " + res.toString)
  }
}

L'expression correspondante en F#, serait

[ for a in args -> a.toUpperCase ]

ou

from a in args select a.toUpperCase

dans Linq.

Ruby yield a un effet différent.

24voto

Alexey Romanov Points 39124

Oui, comme Earwicker dit, il est à peu près l'équivalent de LINQ select et a très peu à voir avec Ruby et Python yield. En gros, là où en C#, on peut écrire

from ... select ??? 

en Scala, vous les avez

for ... yield ???

Il est également important de comprendre que l' for-compréhensions ne travaille pas seulement avec des séquences, mais avec n'importe quel type qui définit certaines méthodes, comme LINQ:

  • Si votre type définit juste map, il permet d' for-expressions composé d'un seul générateur.
  • Si elle définit flatMap ainsi que map, il permet d' for-expressions composé de plusieurs générateurs.
  • Si elle définit foreach, il permet d' for-boucles sans rendement (à la fois avec un seul ou de plusieurs générateurs).
  • Si elle définit filter, il permet d' for-filtre expressions commençant avec une if dans l' for expression.

15voto

Daniel Earwicker Points 63298

À moins d'obtenir une meilleure réponse à partir d'un Scala utilisateur (dont je ne suis pas), voici ma compréhension.

Il n'apparaît que comme une partie d'une expression commençant par for, qui indique comment générer une nouvelle liste à partir d'une liste existante.

Quelque chose comme:

var doubled = for (n <- original) yield n * 2

Donc il y a un élément de sortie pour chaque entrée (bien que je crois qu'il y a un moyen de déposer des doublons).

C'est très différent de la "impératif suites" activé par le rendement dans d'autres langues, où il fournit un moyen pour générer une liste de n'importe quelle longueur, à partir de quelques impératif de code avec presque n'importe quelle structure.

(Si vous êtes familier avec le C#, c'est plus proche de LINQ select opérateur de elle est à l' yield return).

12voto

Richard Gomes Points 1386

Le mot-clé yield en Scala est simplement du sucre syntaxique qui peut être facilement remplacé par un map, comme Daniel Sobral déjà expliqué en détail.

D'autre part, yield est tout à fait trompeuse si vous êtes à la recherche pour les générateurs (ou suites) similaires à ceux en Python. Voir ce fil pour plus d'informations: le moyen privilégié pour mettre en oeuvre une "rendement" de Scala?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X