2011-09-21 2 views
42

Je suis le tutoriel Pattern matching & functional composition sur Scala compose et andThen méthodes. Il y a un tel exemple:Composer et andThen méthodes

scala> def addUmm(x: String) = x + " umm" 
scala> def addAhem(x: String) = x + " ahem" 

val ummThenAhem = addAhem(_).compose(addUmm(_)) 

Lorsque je tente de l'utiliser, je reçois une erreur:

<console>:7: error: missing parameter type for expanded function ((x$1) => addAhem(x$1).compose(((x$2) => addUmm(x$2)))) 
    val ummThenAhem = addAhem(_).compose(addUmm(_)) 
          ^
<console>:7: error: missing parameter type for expanded function ((x$2) => addUmm(x$2)) 
    val ummThenAhem = addAhem(_).compose(addUmm(_)) 
              ^
<console>:7: error: type mismatch; 
found : java.lang.String 
required: Int 
    val ummThenAhem = addAhem(_).compose(addUmm(_)) 

Cependant, cela fonctionne:

val ummThenAhem = addAhem _ compose addUmm _ 

ou même

val ummThenAhem = addAhem _ compose addUmm 

Quel est le problème avec le code dans le tutoriel? Cette dernière expression n'est-elle pas la même que la première sans parenthèse?

Répondre

38

addAhem est une méthode. compose La méthode est définie sur les fonctions. addAhem _ convertit addAhem de la méthode à la fonction, donc compose peut être appelée. compose attend une fonction comme argument. Vous lui donnez une méthode addUmm en convertissant addUmm en une fonction avec addUmm _ (Le trait de soulignement peut être omis parce que le compilateur peut automatiquement convertir une méthode en fonction quand il sait qu'une fonction est quand même attendue). Donc, votre code:

addAhem _ compose addUmm 

est le même que

(addAhem _).compose(addUmm) 

mais pas

addAhem(_).compose(addUmm(_)) 

PS Je ne regarde pas le lien que vous avez fourni.

+0

Par souci de complétude, l'exemple andthen ressemble à:.. 'val ahemThenUmm = addAhem (_) andthen (addUmm (_))' quand il devrait ressembler 'val ahemThenUmm1 = (addAhem _) andthen (addUmm) ' –

+0

Je ne suis pas si sûr de la partie écrite entre parenthèses; le compilateur * ne convertit pas la méthode pour fonctionner automatiquement, au moins pour Scala 2.10.2. La solution consiste à déclarer 'addAhem' et' addUmm' en tant que fonctions pour que 'compose' ou' andThen' fonctionne sans le '_'. –

5

De compose documentation:

Composes two instances of Function1 in a new Function1, with this function applied last.

donc vous devriez écrire

scala> val ummThenAhem = (addAhem _).compose(addUmm _) 
ummThenAhem: String => java.lang.String = <function1> 

pour traiter addAhem et addUmm comme des fonctions partiellement appliquées (i.e. function1)

scala> addAhem _ 
res0: String => java.lang.String = <function1> 
2

Je crois que le tutoriel a été écrit pour une version antérieure de Scala (probablement 2.7.7 ou antérieure). Il y a eu quelques changements dans le compilateur depuis, à savoir, les extensions du système de type, ce qui provoque maintenant le type inférences échouer sur:

addUhum(_).compose(addAhem(_)) 

La levée à une fonction fonctionne toujours avec cette syntaxe si vous venez écrire:

addUhum(_) 
45

Eh bien, ceci:

addUhum _ 

est une extension eta. Il convertit les méthodes en fonctions.D'autre part, ceci:

addUhum(_) 

est une fonction anonyme. En fait, il s'agit d'une application de fonction partielle, en ce sens que ce paramètre n'est pas appliqué et que le tout est converti en fonction. Il se développe à:

x => addUhum(x) 

Les règles précises d'expansion sont un peu difficile à expliquer, mais, au fond, la fonction « start » au délimiteur d'expression la plus profonde. L'exception est les applications de fonction partielle, où le "x" est déplacé en dehors de la fonction - si _ est utilisé à la place d'un paramètre.

Quoi qu'il en soit, voici comment il se développe:

val ummThenAhem = x => addAhem(x).compose(y => addUmm(y)) 

Hélas, le inferencer type ne connaît pas le type de x ou y. Si vous le souhaitez, vous pouvez voir exactement ce qu'il a essayé en utilisant le paramètre -Ytyper-debug.