2011-09-02 6 views
9

Sto cercando di capire il punto di questa caratteristica del linguaggio di più clausole sui parametri e perché lo usereste. Ad esempio, qual è la differenza tra queste due funzioni in realtà?Qual è il punto di più clausole di parametro nelle definizioni di funzione in Scala?

class WTF { 
    def TwoParamClauses(x : Int)(y: Int) = x + y 
    def OneParamClause(x: Int, y : Int) = x + y 
} 

>> val underTest = new WTF 
>> underTest.TwoParamClauses(1)(1) // result is '2' 
>> underTest.OneParamClause(1,1) // result is '2' 

C'è qualcosa su questo nel Scala specification at point 4.6. Vedi se ha senso per te.

NB: la specifica chiama queste "clausole parametro", ma penso che alcune persone possano chiamarle anche "liste di parametri".

+0

programmatore Nnon-scala qui. Forse è solo uno stile diverso? Non tutto deve avere solo un modo per farlo. – apscience

+0

ok, c'è una piccola risposta a questo nella risposta di Daniel Sobral a http://stackoverflow.com/questions/4697404/scala-currying-by-nested-functions-or-by-multiple-parameter-lists –

+0

accettato la risposta qui probabilmente risponde a questa domanda: (1) quindi non devi specificare il tipo dalla prima clausola param nella seconda clausola; (2) per la flessibilità della progettazione della biblioteca; (3) per rendere più facile il curry: http://stackoverflow.com/questions/4915027/two-ways-of-currying-in-scala-whats-the-use-case-for-each –

risposta

9

Qui ci sono tre usi pratici di più elenchi di parametri,

  1. per aiutare l'inferenza dei tipi. Ciò è particolarmente utile quando si usano metodi di ordine superiore. Sotto, il parametro di tipo A di g2 si inferisce dal primo parametro x, quindi gli argomenti della funzione del secondo parametro f possono essere tralasciata,

    def g1[A](x: A, f: A => A) = f(x) 
    g1(2, x => x) // error: missing parameter type for argument x 
    
    def g2[A](x: A)(f: A => A) = f(x) 
    g2(2) {x => x} // type is inferred; also, a nice syntax 
    
  2. Per i parametri impliciti. Solo l'ultimo elenco di parametri può essere contrassegnato come implicito e un singolo elenco di parametri non può combinare parametri impliciti e non impliciti. La definizione di g3 sotto richiede due elenchi di parametri,

    // analogous to a context bound: g3[A : Ordering](x: A) 
    def g3[A](x: A)(implicit ev: Ordering[A]) {} 
    
  3. Per impostare i valori di default in base ai parametri precedenti,

    def g4(x: Int, y: Int = 2*x) {} // error: not found value x 
    def g5(x: Int)(y: Int = 2*x) {} // OK 
    
3

Ci sono alcuni casi in cui questa distinzione materie:

  1. più elenchi di parametri consentono di avere le cose come TwoParamClauses (2); che è una funzione generata automaticamente di tipo Int => Int che aggiunge 2 al suo argomento. Naturalmente puoi definire la stessa cosa tu stesso usando OneParamClause, ma ci vorranno più tasti

  2. Se hai una funzione con parametri impliciti che ha anche parametri espliciti, i parametri impliciti devono essere tutti nella loro propria clausola di parametro (questo può sembrare una restrizione arbitraria ma in realtà è abbastanza ragionevole)

Oltre a ciò, penso che la differenza sia stilistica.

8

TwoParamClause implica due richiami di metodo mentre il OneParamClause richiama la funzioneuna sola volta. Penso che il termine che stai cercando sia curring. Tra i molti casi d'uso, ti aiuta a suddividere il calcolo in piccoli passi. Questo answer potrebbe convincerti dell'utilità del curry.

+1

Il modulo con due clausole parametro richiama il metodo * una sola volta: il risultato di tale chiamata è una * funzione * che viene quindi applicata risultante nel valore finale. –

+1

@pst: Ma l'applicazione di una funzione richiama anche un metodo (vale a dire il metodo 'apply' della funzione). –

+0

@Alexey Romanov Vero. Il post originale era diverso ;-) Nel commento datato stavo cercando di enfatizzare la differenza tra un metodo (qualcosa che un oggetto sa come "rispondere") e una funzione (un oggetto discreto che può essere applicato, anche se tale applicazione è il risultato di invocare un metodo su di esso). Inoltre non sono d'accordo con la terminologia "...invoca la funzione solo una volta "perché invoca il metodo' OneParamClause' * * una sola volta. –

4

più elenchi di parametri possono aiutare tipo scala di inferenza per maggiori dettagli si veda: Making the most of Scala's (extremely limited) type inference

Tipo informazioni non scorre da sinistra a destra all'interno una lista di argomenti, solo dal sinistra a destra attraverso gli elenchi di argomenti. Quindi, anche se Scala conosce i tipi dei primi due argomenti ... quell'informazione non fluisce nella nostra funzione anonima.

...

Ora che la nostra funzione binaria è in una lista di argomenti separati, qualsiasi informazione di tipo dai precedenti elenchi di argomenti viene utilizzato per riempire i tipi per la nostra funzione ... quindi vi non è necessario annotare i parametri di lambda.

+0

Assicurati di includere degli stralci e/o dei ragionamenti e non solo i link nudi nei post. tuttavia. –

+0

Ho pensato che la mia breve descrizione sarebbe stata sufficiente per stuzzicare e per riferimento completo si dovrebbe leggere il blog, ma in questo modo va bene anche :) – AndreasScheinert

6

C'è una differenza tra entrambe le versioni riguardo l'inferenza di tipo.Si consideri

def f[A](a:A, aa:A) = null 
f("x",1) 
//Null = null 

Qui, il tipo A è destinata a Any, che è un super tipo di String e Int. Ma:

def g[A](a:A)(aa:A) = null 
g("x")(1) 

error: type mismatch; 
found : Int(1) 
required: java.lang.String 
     g("x")(1) 
      ^

Come si vede, il tipo di controllo considera solo la prima lista degli argomenti, in modo A ottiene Certamente String, in modo che il valore di Int per aa nella seconda lista degli argomenti è un errore di tipo.