Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Membre à l'essai
    Passer une fonction quelconque, dont le nombre de paramètres est variable, en paramètre d'une autre fonction
    Bonjour,

    je voudrais connaître l'implémentation Scala de ce morceau de code en Python
    C'est uniquement le passage en paramètre d'une fonction quelconque, elle-même constituée d'un nombre indéterminé de paramètres, qui m'intéresse.

    Code python :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    import time
    def timer(n, func, *pargs, **kargs):
       start = time.clock()
       for i in range(n):
          result = func(*pargs, **kargs)
       elapsed = time.clock() - start
    return (elapsed, result)


    Merci d'avance.

  2. #2
    Expert éminent
    Bonjour,

    Étant donnée la nature statiquement typée de Scala, en général on évite de manipuler des fonctions avec un nombre arbitraire de paramètres. Ça ne se prête généralement pas bien au langage. Au lieu de cela, dans ce cas spécifique, on va plutôt tabler sur le fait que Scala gère bien mieux les captures que Python, et donc on va simplement gérer le cas d'une fonction ne prenant aucun paramètre :

    Code scala :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    def timer[A](n: Int, f: () => A): (Long, A) = {
      val start = System.nanoTime()
      var result: A = null.asInstanceOf[A] // on arrangera ça plus tard
      for (_ <- 0 until n)
        result = f()
      val elapsed = System.nanoTime() - start
      (elapsed, result)
    }

    Note que l'usage d'une `var` ici n'est pas terrible (et c'est encore pire à cause du `null.asInstanceOf[A]`) donc on va réorganiser ça :
    Code scala :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    def timer[A](n: Int, f: () => A): (Long, A) = {
      assert(n > 0, "n must be strictly positive")
      val start = System.nanoTime()
      for (_ <- 0 until n-1)
        f()
      val result = f()
      val elapsed = System.nanoTime() - start
      (elapsed, result)
    }

    Maintenant, on peut appeler cette fonction avec :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    val (elapsed, result) = timer(5, { () =>
      uneFonction(avec, ses, parametres)
    })

    Remarque que les paramètres peuvent tout à fait se référer à des vals et vars déclarées en dehors de l'appel à `timer`. Ce qui veut dire que cette fonction gère tout à fait le passage d'un nombre arbitraire de paramètres à `uneFonction`. C'est juste qu'on les captures dans la fonction anonyme qui appelle en fait `uneFonction`. Perso je trouve ça nettement plus lisible que la version Python originale.

    On peut encore améliorer un peu l'API pour la rendre plus Scala-esque avec deux listes de paramètres, et un paramètre "by-name" :
    Code scala :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    def timer[A](n: Int)(f: => A): (Long, A) = {
      assert(n > 0, "n must be strictly positive")
      val start = System.nanoTime()
      for (_ <- 0 until n-1)
        f
      val result = f
      val elapsed = System.nanoTime() - start
      (elapsed, result)
    }

    À appeler comme suit :
    Code scala :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    val (elapsed, result) = timer(5) {
      uneFonction(avec, ses, parametres)
    }
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur exécutif du Scala Center à l'EPFL.
    Découvrez Mes tutoriels, ou mon logiciel phare FunLabyrinthe : un jeu de labyrinthe gratuit et personnalisable à l'infini avec des scripts Delphi-like.

  3. #3
    Membre à l'essai
    Quand on maîtrise ce dont on parle ...

    Merci sjrd


  4. #4
    Membre à l'essai
    Au fait sjrd !

    Quelques mots subtilement distillés dans les explications apportées mériteraient pour moi un petit développement supplémentaire :

    "Scala gère bien mieux les captures que Python"

    Je n'ai pas tout de suite saisi la portée de cette affirmation somme toute si anodine au premier abord.
    Serait-il possible d'avoir un soupçon d'explication (voire plus) ?
    Cela m'intéresse réellement.

    Merci par avance.

    Alain

  5. #5
    Expert éminent
    Oui en fait ce n'est pas tellement que scala gère ça mieux, mais plutôt que Python a quelques surprises liées aux closures à cause de sa combinaison de 1. déclaration implicite de variables locales et 2. captures des variables muables.

    Une bonne explication peut être trouvée ici (en anglais) :
    http://eev.ee/blog/2011/04/24/gotcha...ping-closures/
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur exécutif du Scala Center à l'EPFL.
    Découvrez Mes tutoriels, ou mon logiciel phare FunLabyrinthe : un jeu de labyrinthe gratuit et personnalisable à l'infini avec des scripts Delphi-like.

###raw>template_hook.ano_emploi###