2011-09-21 11 views
42

Podążam za samouczkami metodami Pattern matching & functional composition w Scala compose i andThen. Jest taki przykład:Skomponuj i zmień metody

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

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

Kiedy próbuję go użyć otrzymuję błąd:

<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(_)) 

Jednak to działa:

val ummThenAhem = addAhem _ compose addUmm _ 

lub nawet

val ummThenAhem = addAhem _ compose addUmm 

Co jest nie tak z kodem w samouczku? Czy to ostatnie wyrażenie nie jest takie samo jak pierwsze bez nawiasu?

Odpowiedz

38

addAhem jest metodą. compose Metoda jest zdefiniowana dla funkcji. addAhem _ konwertuje addAhem z metody na funkcję, dzięki czemu można na nią wywołać compose. compose oczekuje funkcji jako argumentu. Podajesz mu metodę addUmm poprzez przekształcenie addUmm w funkcję z addUmm _ (Znak podkreślenia można pominąć, ponieważ kompilator może automatycznie przekonwertować metodę na funkcję, gdy wie, że funkcja jest i tak oczekiwana). Więc twój kod:

addAhem _ compose addUmm 

jest taka sama jak

(addAhem _).compose(addUmm) 

ale nie

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

PS nie patrzeć w linku, który podałeś.

+0

Przez wzgląd na kompletność, tym przykładem andthen wygląda następująco:.. 'val ahemThenUmm = addAhem (_) andthen (addUmm (_))' gdy powinna wyglądać 'val ahemThenUmm1 = (addAhem _) andthen (addUmm) ' –

+0

Nie jestem pewien co do części napisanej w nawiasach okrągłych; kompilator * nie * konwertuje metody do automatycznego działania, przynajmniej dla Scala 2.10.2. Rozwiązaniem jest zadeklarowanie funkcji 'addAhem' i' addUmm' jako funkcji, aby 'compose' lub' andThen' działały bez '_'. –

5

Od compose dokumentacji:

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

więc trzeba napisać

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

traktować addAhem i addUmm jako częściowo stosowane funkcje (tj function1)

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

Wierzę, że samouczek został napisany dla wcześniejszej wersji Scala (prawdopodobnie 2.7.7 lub wcześniejszej). Odnotowano pewne zmiany w kompilator od tego czasu, a mianowicie, rozszerzenia do systemu typu, które obecnie powodują rodzaj wnioskowania na niepowodzenie na:

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

Podnoszenie do funkcji nadal współpracuje z tej składni, jeśli tylko napisać:

addUhum(_) 
45

Cóż, to:

addUhum _ 

jest ekspansją eta. Konwertuje metody na funkcje.Z drugiej strony:

addUhum(_) 

to funkcja anonimowa. W rzeczywistości jest to aplikacja funkcji częściowej, ponieważ ten parametr nie jest stosowany, a cała rzecz przekształcona w funkcję. Rozszerza się:

x => addUhum(x) 

Dokładne zasady ekspansji są nieco trudne do wyjaśnienia, ale w zasadzie, funkcja „start” w najgłębszej separatora ekspresji. Wyjątkiem są aplikacje funkcji częściowej, w których "x" jest przenoszone poza funkcję - jeśli zamiast parametru używany jest parametr _.

W każdym razie, to jest, jak się rozszerza:

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

Niestety, typ inferencer nie zna typ x lub y. Jeśli chcesz, możesz dokładnie sprawdzić, czego próbował, używając parametru -Ytyper-debug.