Salut, qu'est-ce que cela Int => Booleansignifie? Je pense que la syntaxe définie estdef foo(bar: Baz): Bin = expr
Ziu
@Ziu signifie que la fonction 'even' reçoit un Int comme argument et retourne un Boolean comme type de valeur. Vous pouvez donc appeler 'even (3)' qui s'évalue comme booléen 'false'
Denys Lobur
@DenysLobur merci pour votre réponse! Une référence sur cette syntaxe?
Ziu
@Ziu Je l'ai essentiellement découvert dans le cours Coursera d'Odersky - coursera.org/learn/progfun1 . Au moment où vous l'avez terminé, vous comprendrez ce que 'Type => Type' signifie
Denys Lobur
Réponses:
325
Méthode def even évalue à l'appel et crée à chaque fois une nouvelle fonction (nouvelle instance de Function1).
def even:Int=>Boolean= _ %2==0
even eq even
//Boolean = falseval even:Int=>Boolean= _ %2==0
even eq even
//Boolean = true
Avec def vous pouvez obtenir une nouvelle fonction à chaque appel:
val test:()=>Int={val r = util.Random.nextInt
()=> r
}
test()// Int = -1049057402
test()// Int = -1049057402 - same resultdef test:()=>Int={val r = util.Random.nextInt
()=> r
}
test()// Int = -240885810
test()// Int = -1002157461 - new result
val évalue une fois défini, def - lorsqu'il est appelé:
scala>val even:Int=>Boolean=???
scala.NotImplementedError: an implementation is missing
scala>def even:Int=>Boolean=???
even:Int=>Boolean
scala> even
scala.NotImplementedError: an implementation is missing
Notez qu'il existe une troisième option: lazy val.
Il évalue lors de son premier appel:
scala>lazyval even:Int=>Boolean=???
even:Int=>Boolean=<lazy>
scala> even
scala.NotImplementedError: an implementation is missing
Mais renvoie le même résultat (dans ce cas la même instance de FunctionN) à chaque fois:
lazyval even:Int=>Boolean= _ %2==0
even eq even
//Boolean = truelazyval test:()=>Int={val r = util.Random.nextInt
()=> r
}
test()// Int = -1068569869
test()// Int = -1068569869 - same result
Performance
val évalue une fois défini.
defévalue à chaque appel, les performances peuvent donc être pires que valpour plusieurs appels. Vous obtiendrez les mêmes performances avec un seul appel. Et sans appels, vous n'aurez aucun frais générauxdef , vous pouvez donc le définir même si vous ne l'utiliserez pas dans certaines branches.
Avec un, lazy valvous obtiendrez une évaluation paresseuse: vous pouvez le définir même si vous ne l'utiliserez pas dans certaines branches, et il évalue une fois ou jamais, mais vous obtiendrez un petit supplément de verrouillage double vérification sur chaque accès à votre lazy val.
Comme @SargeBorsch l'a noté, vous pouvez définir une méthode, et c'est l'option la plus rapide:
def even(i:Int):Boolean= i %2==0
Mais si vous avez besoin d'une fonction (et non d'une méthode) pour la composition de fonctions ou pour des fonctions d'ordre supérieur (comme filter(even)), le compilateur générera une fonction à partir de votre méthode chaque fois que vous l'utiliserez comme fonction, donc les performances pourraient être légèrement pires qu'avec val.
Pourriez-vous les comparer en ce qui concerne les performances? N'est-il pas important d'évaluer la fonction à chaque evenappel.
Amir Karimi
2
defpeut être utilisé pour définir une méthode, et c'est l'option la plus rapide. @ A.Karimi
Nom d'affichage
2
Pour le plaisir: sur 2,12, even eq even.
som-snytt
Existe-t-il un concept de fonctions en ligne comme en C ++? Je viens du monde c ++, pardonnez donc mon ignorance.
animageofmine
2
@animageofmine Le compilateur Scala peut essayer d'inclure des méthodes. Il y a un @inlineattribut pour cela. Mais il ne peut pas intégrer de fonctions car l'appel de fonction est un appel à la applyméthode virtuelle d'un objet fonction. JVM peut dévirtualiser et aligner de tels appels dans certaines situations, mais pas en général.
senia
24
Considère ceci:
scala>def even:(Int=>Boolean)={
println("def");(x => x %2==0)}
even:Int=>Boolean
scala>val even2:(Int=>Boolean)={
println("val");(x => x %2==0)}val//gets printed while declaration. line-4
even2:Int=>Boolean=<function1>
scala> even(1)def
res9:Boolean=false
scala> even2(1)
res10:Boolean=false
Voyez-vous la différence? En bref:
def : Pour chaque appel à even, il appelle à nouveau le corps de la evenméthode. Mais avec even2ie val , la fonction n'est initialisée qu'une seule fois lors de la déclaration (et donc elle s'imprime valà la ligne 4 et plus jamais) et la même sortie est utilisée à chaque fois qu'elle y accède. Par exemple, essayez de faire ceci:
scala>import scala.util.Randomimport scala.util.Random
scala>val x ={Random.nextInt }
x:Int=-1307706866
scala> x
res0:Int=-1307706866
scala> x
res1:Int=-1307706866
Lorsque xest initialisé, la valeur renvoyée par Random.nextIntest définie comme valeur finale de x. La prochaine foisx utiliserez à nouveau, il renverra toujours la même valeur.
Vous pouvez également initialiser paresseusement x. c'est-à-dire que la première fois qu'il est utilisé, il est initialisé et non pendant la déclaration. Par exemple:
scala>lazyval y ={Random.nextInt }
y:Int=<lazy>
scala> y
res4:Int=323930673
scala> y
res5:Int=323930673
Je pense que votre explication peut impliquer quelque chose que vous n'avez pas l'intention. Essayez d'appeler even2deux fois, une fois avec 1et une fois avec 2. Vous obtiendrez des réponses différentes à chaque appel. Ainsi, bien que le printlnne soit pas exécuté dans les appels suivants, vous n'obtenez pas le même résultat d'appels différents vers even2. Quant à savoir pourquoi le printlnn'est pas exécuté à nouveau, c'est une question différente.
melston
1
c'est en fait très intéressant. C'est comme dans le cas de val ie even2, la val est évaluée à une valeur paramétrée. alors oui avec un val vous l'évaluation de la fonction, sa valeur. Le println ne fait pas partie de la valeur évaluée. Cela fait partie de l'évaluation mais pas de la valeur évaluée. L'astuce ici est que la valeur évaluée est en fait une valeur paramétrisée, qui dépend de certaines entrées. chose intelligente
MaatDeamon
1
@melston exactement! c'est ce que j'ai compris, alors pourquoi le println ne s'exécute-t-il pas alors que la sortie a changé?
aur
1
@aur ce qui est retourné par even2 est en fait une fonction (l'expression entre parenthèses à la fin de la définition de even2). Cette fonction est en fait appelée avec le paramètre que vous passez à even2 chaque fois que vous l'invoquez.
melston
5
Regarde ça:
var x =2// using var as I need to change it to 3 laterval sq = x*x // evaluates right now
x =3// no effect! sq is already evaluated
println(sq)
Étonnamment, cela imprimera 4 et non 9! val (même var) est évalué immédiatement et affecté.
Maintenant changez val en def .. il imprimera 9! Def est un appel de fonction .. il évaluera chaque fois qu'il est appelé.
val ie "sq" est par définition Scala est fixe. Il est évalué juste au moment de la déclaration, vous ne pouvez pas le modifier ultérieurement. Dans d'autres exemples, où even2 vaut également, mais il a déclaré avec la signature de fonction, c'est-à-dire "(Int => Boolean)", donc ce n'est pas de type Int. C'est une fonction et sa valeur est définie par l'expression suivante
{
println("val");(x => x %2==0)}
Selon la propriété Scala val, vous ne pouvez pas affecter une autre fonction à even2, même règle que sq.
Pourquoi pourquoi appeler la fonction val eval2 n'imprime-t-il pas encore "val"?
Code d'origine:
val even2:(Int=>Boolean)={
println("val");(x => x %2==0)}
Nous savons que, dans Scala, la dernière déclaration du type d'expression ci-dessus (à l'intérieur de {..}) est en fait de retour sur le côté gauche. Ainsi, vous finissez par définir even2 sur la fonction "x => x% 2 == 0", qui correspond au type que vous avez déclaré pour le type val even2, c'est-à-dire (Int => Boolean), donc le compilateur est content. Maintenant, even2 ne pointe que sur la fonction "(x => x% 2 == 0)" (pas d'autre instruction avant ie println ("val") etc. L'invocation de event2 avec différents paramètres invoquera en fait "(x => x% 2 == 0) ", car seul celui-ci est enregistré avec event2.
Exécution d'une définition telle que def x = e n'évaluera pas l'expression e. Au lieu de cela, e est évalué chaque fois que x est invoqué.
Scala propose également une définition de valeur
val x = e, qui évalue le côté droit dans le cadre de l'évaluation de la définition. Si x est ensuite utilisé par la suite, il est immédiatement remplacé par la valeur pré-calculée de e, de sorte que l'expression n'a pas besoin d'être évaluée à nouveau.
aussi, Val est une évaluation par valeur. Ce qui signifie que l'expression de droite est évaluée lors de la définition. Où Def est par évaluation de nom. Il n'évaluera pas jusqu'à ce qu'il soit utilisé.
En plus des réponses utiles ci-dessus, mes conclusions sont les suivantes:
def test1:Int=>Int={
x => x
}--test1: test1[]=>Int=>Intdef test2():Int=>Int={
x => x+1}--test2: test2[]()=>Int=>Intdef test3():Int=4--test3: test3[]()=>Int
Ce qui précède montre que «def» est une méthode (avec zéro paramètre d'argument) qui renvoie une autre fonction «Int => Int» lorsqu'elle est invoquée.
Avec une question aussi ancienne et avec autant de réponses déjà soumises, il est souvent utile d'expliquer en quoi votre réponse diffère ou s'ajoute aux informations fournies dans les réponses existantes.
Int => Boolean
signifie? Je pense que la syntaxe définie estdef foo(bar: Baz): Bin = expr
Réponses:
Méthode
def even
évalue à l'appel et crée à chaque fois une nouvelle fonction (nouvelle instance deFunction1
).Avec
def
vous pouvez obtenir une nouvelle fonction à chaque appel:val
évalue une fois défini,def
- lorsqu'il est appelé:Notez qu'il existe une troisième option:
lazy val
.Il évalue lors de son premier appel:
Mais renvoie le même résultat (dans ce cas la même instance de
FunctionN
) à chaque fois:Performance
val
évalue une fois défini.def
évalue à chaque appel, les performances peuvent donc être pires queval
pour plusieurs appels. Vous obtiendrez les mêmes performances avec un seul appel. Et sans appels, vous n'aurez aucun frais générauxdef
, vous pouvez donc le définir même si vous ne l'utiliserez pas dans certaines branches.Avec un,
lazy val
vous obtiendrez une évaluation paresseuse: vous pouvez le définir même si vous ne l'utiliserez pas dans certaines branches, et il évalue une fois ou jamais, mais vous obtiendrez un petit supplément de verrouillage double vérification sur chaque accès à votrelazy val
.Comme @SargeBorsch l'a noté, vous pouvez définir une méthode, et c'est l'option la plus rapide:
Mais si vous avez besoin d'une fonction (et non d'une méthode) pour la composition de fonctions ou pour des fonctions d'ordre supérieur (comme
filter(even)
), le compilateur générera une fonction à partir de votre méthode chaque fois que vous l'utiliserez comme fonction, donc les performances pourraient être légèrement pires qu'avecval
.la source
even
appel.def
peut être utilisé pour définir une méthode, et c'est l'option la plus rapide. @ A.Karimieven eq even
.@inline
attribut pour cela. Mais il ne peut pas intégrer de fonctions car l'appel de fonction est un appel à laapply
méthode virtuelle d'un objet fonction. JVM peut dévirtualiser et aligner de tels appels dans certaines situations, mais pas en général.Considère ceci:
Voyez-vous la différence? En bref:
def : Pour chaque appel à
even
, il appelle à nouveau le corps de laeven
méthode. Mais aveceven2
ie val , la fonction n'est initialisée qu'une seule fois lors de la déclaration (et donc elle s'imprimeval
à la ligne 4 et plus jamais) et la même sortie est utilisée à chaque fois qu'elle y accède. Par exemple, essayez de faire ceci:Lorsque
x
est initialisé, la valeur renvoyée parRandom.nextInt
est définie comme valeur finale dex
. La prochaine foisx
utiliserez à nouveau, il renverra toujours la même valeur.Vous pouvez également initialiser paresseusement
x
. c'est-à-dire que la première fois qu'il est utilisé, il est initialisé et non pendant la déclaration. Par exemple:la source
even2
deux fois, une fois avec1
et une fois avec2
. Vous obtiendrez des réponses différentes à chaque appel. Ainsi, bien que leprintln
ne soit pas exécuté dans les appels suivants, vous n'obtenez pas le même résultat d'appels différents verseven2
. Quant à savoir pourquoi leprintln
n'est pas exécuté à nouveau, c'est une question différente.Regarde ça:
Étonnamment, cela imprimera 4 et non 9! val (même var) est évalué immédiatement et affecté.
Maintenant changez val en def .. il imprimera 9! Def est un appel de fonction .. il évaluera chaque fois qu'il est appelé.
la source
val ie "sq" est par définition Scala est fixe. Il est évalué juste au moment de la déclaration, vous ne pouvez pas le modifier ultérieurement. Dans d'autres exemples, où even2 vaut également, mais il a déclaré avec la signature de fonction, c'est-à-dire "(Int => Boolean)", donc ce n'est pas de type Int. C'est une fonction et sa valeur est définie par l'expression suivante
Selon la propriété Scala val, vous ne pouvez pas affecter une autre fonction à even2, même règle que sq.
Pourquoi pourquoi appeler la fonction val eval2 n'imprime-t-il pas encore "val"?
Code d'origine:
Nous savons que, dans Scala, la dernière déclaration du type d'expression ci-dessus (à l'intérieur de {..}) est en fait de retour sur le côté gauche. Ainsi, vous finissez par définir even2 sur la fonction "x => x% 2 == 0", qui correspond au type que vous avez déclaré pour le type val even2, c'est-à-dire (Int => Boolean), donc le compilateur est content. Maintenant, even2 ne pointe que sur la fonction "(x => x% 2 == 0)" (pas d'autre instruction avant ie println ("val") etc. L'invocation de event2 avec différents paramètres invoquera en fait "(x => x% 2 == 0) ", car seul celui-ci est enregistré avec event2.
Juste pour clarifier cela, voici une version différente du code.
Que va-t-il se passer? ici, nous voyons "inside final fn" imprimé encore et encore, lorsque vous appelez even2 ().
la source
Exécution d'une définition telle que
def x = e
n'évaluera pas l'expression e. Au lieu de cela, e est évalué chaque fois que x est invoqué.Scala propose également une définition de valeur
val x = e
, qui évalue le côté droit dans le cadre de l'évaluation de la définition. Si x est ensuite utilisé par la suite, il est immédiatement remplacé par la valeur pré-calculée de e, de sorte que l'expression n'a pas besoin d'être évaluée à nouveau.la source
aussi, Val est une évaluation par valeur. Ce qui signifie que l'expression de droite est évaluée lors de la définition. Où Def est par évaluation de nom. Il n'évaluera pas jusqu'à ce qu'il soit utilisé.
la source
En plus des réponses utiles ci-dessus, mes conclusions sont les suivantes:
Ce qui précède montre que «def» est une méthode (avec zéro paramètre d'argument) qui renvoie une autre fonction «Int => Int» lorsqu'elle est invoquée.
La conversion des méthodes en fonctions est bien expliquée ici: https://tpolecat.github.io/2014/06/09/methods-functions.html
la source
Dans REPL,
def signifie
call-by-name
, évalué sur demandeval signifie
call-by-value
, évalué lors de l'initialisationla source