2011-01-29 19 views
34

sto guardando Runar Bjarnason present Functional Programming for Beginners, e alle 14:45 si definisce un metodo:Funzioni vs metodi Scala

def isDivisibleBy(k: Int): Int => Boolean = i => i % k == 0 

e una funzione:

val isEven = isDivisibleBy(2) 

Quali sono i pro ei contro di definire isEven come una funzione piuttosto che un metodo?

Ho letto Scala Functions vs Methods così come Difference between method and function in Scala, e capisco le differenze semantiche, ma mi chiedo se c'è qualche ragione più profonda in questo caso il motivo per cui una funzione potrebbe o non potrebbe essere preferibile utilizzare un metodo:

def isEven = isDivisibleBy(2) 
+0

pensate un po 'in Java equivalente (le funzioni Scala vs. Metodi fa un buon lavoro di questo) e come si inserisce nella fase di esecuzione. Questo è un buon motivo per un approccio rispetto all'altro. Si noti inoltre che l'ambito di 'def' è importante in quanto non è lo stesso ovunque (è solo un" metodo "- dettagli di implementazione a parte - a livello di classe). –

risposta

46

Sotto il cofano ci sono altre differenze tra funzioni e metodi. Generalmente, un metodo semplice genera meno overhead di una funzione (che tecnicamente è un oggetto con un metodo apply).

Tuttavia, se si tenta di non preoccuparsi di queste differenze e pensare a def, val e var come campi con semantica diversa, allora è semplicemente che def valuta ogni volta che viene chiamato mentre val valuta solo una volta.

Quindi, un val isEven = isDivisibleBy(2) deve chiamare isDivisibleBy(2) durante la sua definizione e assegnare il risultato di isDivisibleBy(2). Per esempio. sostituisce il k in

def isDivisibleBy(k: Int): Int => Boolean = i => i % k == 0 

con 2 e assegna il risultato dell'espressione finale (in questo caso v'è una sola espressione):

val isEven: Int => Boolean = i => i % 2 == 0 

def isEven invece non fa tale valutazione e risultati in una chiamata a isDivisibleBy (2) ogni volta.

Ciò significa che, più tardi, quando si esegue il codice, isEven(11) genera in caso di val

11 % 2 == 0 

e in caso di un def, avrete

isDivisibleBy(2)(11) 

e solo dopo valutando isDivisibleBy otterrai il risultato.

È possibile aggiungere del codice di debug per isDivisibleBy per vedere la differenza:

def isDivisibleBy(k: Int): Int => Boolean = { 
    println("evaluating isDivisibleBy") 
    i => i % k == 0 
} 
+1

Che dire della differenza tra 'def' a livello di classe e vs' def' all'interno di un metodo? +1 come questa è una buona risposta (anche se ogni volta viene applicata una funzione - ad esempio in un 'val' si chiamerà - è solo un dettaglio che i metodi possono essere invocati senza espliciti parens), ma sarebbe bello per catturare quelle differenze (e anche il significato di "metodo"). –

+0

domanda stupida: cosa fa il 'Boolean =' fare lì? Sono nuovo di Scala. :) – DavidLin

+0

Significa che chiamare la funzione isEven sarà più veloce e può chiamare il metodo isEven? Questo è il vantaggio delle funzioni rispetto ai metodi? –

5

Penso che il principale pro della definizione della funzionecome val sia mostrare al pubblico che la funzione può essere definita in questo modo. Quindi è chiaro che una funzione è solo un oggetto come tutto il resto in scala. Ma nel mondo della programmazione non dimostrativa, non è necessario scrivere funzioni come val s.

+0

Non esiste una definizione di funzione ma un'applicazione di un metodo con un risultato di funzione: mostra che una funzione (Int => Boolean) può essere memorizzata/trattata come un oggetto normale. 'val square = (x) => x * x' sarebbe una definizione, che mostra anche la stessa cosa. Le sottili sfumature tra i due (** metodi che sono vincolati all'oggetto e consentono il sovraccarico e l'override ** (in termini Java) e ** funzioni che non sono metodi **) sono dove diventa "interessante". –

+0

Ho una vaga comprensione di cosa sia '' definizione di funzione', perché è piuttosto difficile da google :-), quindi lo sto usando in modo intuitivo. Com'è 'val square ...' diverso? Accetta anche un argomento e crea una funzione che restituisce un oggetto applicando il metodo '*' a 'x'. Ho provato a leggere la domanda a fondo e rispondere a questa particolare domanda. "in questo caso" è cruciale, la domanda è menzionare un uomo che parla alla presentazione e il suo punto era imho mostrare un modo diverso di "trattare" metodi/funzioni, la domanda non riguardava le sfumature tra metodo e oggetto funzionale. – coubeatczech

+0

Un metodo se un artefatto di Java (forse Scala avrebbe se non fosse una parte di Java) - gli oggetti hanno * metodi * (questi sono definiti con 'def' a livello di classe). Le funzioni in Scala sono solo una forma speciale di un oggetto (vedi FunctionN, ecc.) Che hanno un metodo 'apply' (' def' all'interno di una funzione sono * non metodi * - in realtà, possono essere/sono implementati come tali, ma questo è un dettaglio di implementazione in quanto non è esposto).Scala fa semplicemente girare un * metodo * in una * funzione * (o nella memorizzazione di una * funzione * in una variabile) banale. Non ho visto questa distinzione affrontata in nessuna risposta. –

3

Il metodo def isDivisibleBy(k: Int): Int => Boolean restituisce una funzione che prende un int (i) come parametro e restituisce un valore booleano (i % k == 0).

val isEven = isDivisibleBy(2) d'altra parte è un campo in cui è memorizzata la funzione restituita da isDivisibleBy(2). Se si utilizza def anziché val, il metodo isDivisibleBy viene chiamato ogni volta che viene chiamato il metodo isEven, ma ora viene chiamato una sola volta e il risultato viene archiviato nel campo.

si potrebbe ottenere lo stesso risultato scrivendo def isEven(i: Int): Boolean = i % 2 == 0

penso che il punto di questo esempio è che si può avere funzioni che restituiscono altre funzioni, ed è possibile memorizzare le funzioni come oggetti, e poi li chiamano come se erano metodi tradizionalmente definiti. Il codice sopra riportato è anche molto simile a currying, quindi potrebbe anche essere una cosa dimostrata dall'esempio (anche se non usa Scala's syntax for currying).

+0

Con il curry sembra un po 'più lento, non so perché. – Debilski

13

Mi piacerebbe affrontare un altro punto qui. Questo definisce isEven come metodo:

def isEven = isDivisibleBy(2) 

E questo definisce isEven come metodo così:

val isEven = isDivisibleBy(2) 

In entrambi i casi, isEven è un metodo che, quando viene chiamato, restituisce una funzione.

Nel primo caso, isDivisible(2) viene chiamato ogni volta che viene chiamato isEven. Ad esempio, ciò richiede isDivisible(2) tre volte:

def isEven = isDivisibleBy(2) 
List(1,2,3).filter(isEven) 

Nel secondo caso, isDivisible(2) è chiamato una volta (in fase di costruzione, o quando viene eseguita che in linea ad una definizione), e tale valore viene recuperato ogni volta isEven è chiamato. L'esempio seguente chiama isDivisible(2) una sola volta:

val isEven = isDivisibleBy(2) 
List(1,2,3).filter(isEven) 
+3

Per quanto ne so, 'val' non definisce un metodo. Forse vuoi dire che è tradotto in un metodo in codice byte java per qualche ragione (anche se non vedo perché sarebbe il caso). Penserei che sia semplicemente un riferimento all'oggetto funzione. Dopotutto puoi semplicemente passare il riferimento in giro come con altri oggetti. – herman