2013-09-07 4 views
0

je tentais de mettre en œuvre l'exemple de fermeture à Scala, de la présentation de la pensée fonctionnelle de Neal Ford qui est en Groovy. Reportez-vous glisser # 43bloc de code à Scala

def makeCounter : Unit = { 
var localVar = 0 
return { localVar += 1 } 
} 

Ce code renvoie une fonction anonyme. Maintenant, je veux incrémenter le localVar en invoquant cette fonction anonyme. J'ai deux questions:
1. Comment appeler la fonction anonyme?
2. Après l'avoir invoqué, comment vérifier si la valeur de localVar est incrémentée ou non?

D'abord j'ai essayé ceci -
val c1 = makeCounter(). Il a jeté l'erreur ci-dessous:
erreur: makeCounter de type L'unité ne prend pas de paramètres

Puis j'ai essayé ceci.
val = c1 makeCounter

Cela n'a pas donné aucune erreur. Seulement imprimé c1: Unit =(). Ensuite,
print (c1) a imprimé(), alors que c1() a donné la même erreur.

+2

"Ce code renvoie une fonction anonyme." - Alors pourquoi as-tu déclaré son type de retour comme 'Unit'? –

+0

Je pense qu'il mélange les paramètres unitaires par nom avec l'unité pure. – pedrofurla

Répondre

1

Je n'ai pas regardé la présentation, donc je ne sais pas si cela est la pensée fonctionnelle ou tout simplement l'une des diapositives sur la route de la pensée fonctionnelle, mais:

scala> def f:() => Int = { 
    | var v = 0 
    |() => v += 1 ; v } 
f:() => Int 

scala> val g = f 
g:() => Int = <function0> 

scala> g() 
res0: Int = 1 

scala> g() 
res1: Int = 2 

scala> g() 
res2: Int = 3 

La fonction littérale retournée par f est, bien sûr, tout après les parens.

+0

Cela fonctionne bien. Mais j'ai un doute conceptuel ici. Si je comprends bien, cette définition de fonction avec def f:() => Int implique qu'il ne prendra aucun paramètre et retournera un Int. Mais n'est-ce pas mal parce que cette fonction renvoie une fonction anonyme et non un Int? Ou est-ce que je manque quelque chose ici? –

+0

@VarunPaprunia La méthode 'f' est sans paramètre. Voyez comment il est invoqué à la ligne 2 sans parens. Il renvoie un '() => Int'. La valeur 'g' est appliquée en utilisant' g.apply() 'ou' g.apply' (avec des parenthèses automatiquement ajoutées) ou 'g()' (comme appel à 'apply'). –

6

Tout d'abord. N'utilisez pas return, sa sémantique est complètement différente dans Scala que dans Java ou Groovy. Le type Unit n'est pas un synonyme de fonction anonyme. C'est plus comme une indication d'effets secondaires. Le type d'une fonction anonyme est le () => A. Dans votre cas, vous voulez une fonction qui ne retourne rien, mais provoque un effet secondaire. Donc, son type devrait être () => Unit.

Voyons voir un peu de code:

def makeCounter :() => Unit = { 
    var x = 0 
    {() => x = x + 1 } 
} 

val counter = makeCounter 
counter(); counter(); counter() 

Great! Nous avons fait makeCounter nous donner un nouveau comptoir!

Il n'y a qu'un seul problème. x est une variable locale dans la méthode makeCounter et comme elle n'est jamais retournée, nous ne pouvons pas voir sa valeur! Déjà! Nous pourrions, par exemple, supprimer x de la méthode, en le rendant public dans la portée externe. Mais ce n'est pas très fonctionnel. Au lieu de cela, nous allons faire la fonction retourner:

def makeCounter :() => Int = { // Notice now, instead of Unit we use Int 
    var x = 0 
    {() => x = x + 1; x } 
} 

val counter = makeCounter 
println(counter(), counter(), counter()) 
val counter2 = makeCounter 
println(counter2(), counter2(), counter2()) 

Vous verrez « 1,2,3 » deux fois. Une fois pour chaque compteur.

+0

Désolé, je n'ai lu que jusqu'à "devrait être() => Unit' quand j'ai posté ma version. Peut-être que vous pourriez supprimer les demi-accolades supplémentaires de la réponse finale. "Est-ce votre réponse définitive?" –

+1

@ som-snytt En fait, j'ai des problèmes d'analyse visuelle de votre version. Je ne savais même pas que tu pouvais arranger des choses comme ça. – pedrofurla

+0

@pedrofurla Si je n'utilise pas le retour, il donne une erreur - "erreur: le bloc doit se terminer dans l'expression du résultat, pas dans la définition". Alors je l'ai retourné. Mais encore println (counter()) n'imprime rien –