Question

J'ai appris scala et je dois dire que c'est une langue vraiment cool. Je aime particulièrement ses capacités d'adaptation de modèle et littéraux de fonction, mais je viens d'un javascript, fond rubis et un de mes modèles préférés dans ces langues est la fonction paresseuse et modèle de définition méthode. Un exemple en javascript est

var foo = function() {
  var t = new Date();
  foo = function() {
    return t;
  };
  return foo();
};

Le même code avec quelques réglages mineurs fonctionne en rubis où vous venez d'utiliser l'objet singleton pour redéfinir la méthode après le calcul est effectué. Ce genre de chose est vraiment pratique quand calcul coûteux sont impliqués et vous ne savez pas à l'avance si vous allez avoir besoin du résultat. Je sais que dans scala je peux utiliser un cache pour simuler le même genre de résultat, mais j'essaie d'éviter les contrôles conditionnels et à ce jour mes expériences ont donné des résultats négatifs de. Ne sait quiconque s'il y a un modèle de définition de fonction ou une méthode paresseuse dans scala?

Note: Le code javascript est de Peter Michaux le site <. / p>

Était-ce utile?

La solution

Tout ce code compliqué en JavaScript semble juste essayer de mettre en cache la valeur de la date. En Scala, vous pouvez obtenir la même chose trivialement:

lazy val foo = new Date

Et, si je ne veux même pas faire un val, mais que vous voulez appeler une fonction qui n'exécute le code cher si elle en a besoin, vous pouvez

def maybeExpensive(doIt: Boolean, expensive: => String) {
  if (doIt) println(expensive)
}
maybeExpensive(false, (0 to 1000000).toString)  // (0 to 1000000).toString is never called!
maybeExpensive(true, (0 to 10).toString)        // It is called and used this time

où le motif expensive: => String est appelé un paramètre par nom, vous pouvez penser que, « Donnez-moi quelque chose qui va générer une chaîne sur demande. » Notez que si vous utilisez deux fois, il régénérer à chaque fois, ce qui est à portée de main où modèle « Randall Schultz est disponible en:

def maybeExpensiveTwice(doIt: Boolean, expensive: => String) {
  lazy val e = expensive
  if (doIt) {
    println(e)
    println("Wow, that was " + e.length + " characters long!")
  }
}

Maintenant, vous générez que si vous en avez besoin (via le sous-nom de paramètre) et stocker et réutiliser si vous en avez besoin à nouveau (via le val paresseux).

Alors faites-le de cette façon, pas la façon JavaScript, même si vous pourrait faire Scala ressemble beaucoup à l'activation de Javascript.

Autres conseils

Scala a lazy vals, dont initializers ne sont pas évalués à moins que et jusqu'à ce que le val est utilisé. vals paresseux peuvent être utilisés comme méthode des variables locales.

Scala a aussi par le nom des paramètres de méthode, dont les expressions paramètre réel sont enveloppés dans un thunk et que thunk est évalué chaque fois que le paramètre formel est référencé dans le corps de la méthode.

Ensemble ceux-ci peuvent être utilisés pour atteindre la sémantique d'évaluation paresseux tels que sont la valeur par défaut dans Haskell (au moins dans ma compréhension très limitée de Haskell).

def meth(i: => Int): Something = {
  //        ^^^^^^ by-name parameter syntax
  lazy val ii = i
  // Rest of method uses ii, not i
}

Dans ce procédé, l'expression utilisée en tant que paramètre réel sera évalué soit zéro fois (si le chemin d'exécution dynamique du corps de la méthode utilise jamais ii) ou une fois (si elle utilise une de ii fois ou plus).

Vous pouvez définir un val paresseux qui est une fonction:

lazy val foo = {
  val d = new Date
  () => { d }
}

println(foo())

foo() retourne maintenant la même date l'objet chaque fois, objet qui sera initialisé la première fois foo est appelé.

Pour expliquer un peu le code, est appelé { val d = new Date; () => { d } } est exécutée, d est affecté à une nouvelle valeur de date puis évaluer la dernière expression () => { d } et l'affecter à la valeur foo la première fois foo (). Ensuite foo est une fonction sans paramètre qui retour d.

Je pense que certains des intervenants étaient un peu confus par la façon dont vous avez formulé la question. La construction Scala vous voulez ici est une définition simple paresseuse:

lazy val foo = new java.util.Date

La construction de l'objet Date aura lieu au plus une fois et être différée jusqu'à ce que la première référence à foo.

Je ne sait rien à propos de Ruby, mais scala a motif objet singleton aussi:

Welcome to Scala version 2.8.0.r22634-b20100728020027 (Java HotSpot(TM) Client VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.

scala> object LazyInit {                                       
     |     val msec = { println("Hi,I'm here!");   System.currentTimeMillis }
     | }
defined module LazyInit

scala> System.currentTimeMillis                                              
res0: Long = 1282728315918

scala> println(System.currentTimeMillis +" : " + LazyInit.msec)              
Hi,I'm here!
1282728319929 : 1282728319930

scala> println(System.currentTimeMillis +" : " + LazyInit.msec)
1282728322936 : 1282728319930

scala> println(System.currentTimeMillis +" : " + LazyInit.msec)
1282728324490 : 1282728319930

scala> 

Si vous voulez obtenir la fonction, vous pouvez le faire sous-type d'un type de fonction:

scala> object LazyFun extends (() => Long) {            
     |     val msec = System.currentTimeMillis          
     |     def apply() = msec                           
     | }
defined module LazyFun

scala> System.currentTimeMillis                         
res2: Long = 1282729169918

scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729190384 : 1282729190384

scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729192972 : 1282729190384

scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729195346 : 1282729190384

Je pense que vous voulez dire « fonction paresseuse » est littérale de fonction ou fonction anonyme.

Scala vous pouvez faire des choses comme ça, très semblable au code javascript que vous avez publié.

val foo = () => {
    val t = new Date()
    val foo = () => {t}

    foo()
}

println ("Hello World:" + foo())

La principale différence est que:

  • Vous ne pourriez pas réattribution le foo externe
  • Il n'y a aucun mot-clé "fonction", au lieu que vous utilisez quelque chose comme (s: String) => {code}
  • La dernière déclaration est la valeur de retour d'un bloc, de sorte que vous n'avez pas besoin d'ajouter « retour ».
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top