differenza tra passare un valore e passare una funzione come parametro in scala

2

Spesso sento che scala ha la capacità di passare la funzione come parametro a un'altra funzione. Vorrei sapere la differenza tra il passaggio di un valore come parametro e il passaggio della funzione stessa come parametro. In che modo quest'ultimo approccio apporta un vantaggio alla programmazione. Se le funzioni vengono passate come parametro come vengono creati i riferimenti agli oggetti poiché le funzioni non sono legate a nessun oggetto.

    
posta prasonscala 01.08.2011 - 11:19
fonte

3 risposte

2

Hai mai usato il visitatore o modelli di strategia, fabbriche o iniezioni di dipendenza? Hai mai passato o richiesto un oggetto di tipo Runnable o Comparator ? Tutte queste cose sono hack ad hoc in cui manca la capacità di passare le funzioni.

Nel modello di visitatore , invece di avere accept ricevere un'interfaccia per un visitatore, si prende una funzione Element => Unit invece (per il caso di ritorno del vuoto). Il concetto generale di visitatore è noto come catamorfismo , di cui ogni tipo di mappatura e piega sono casi speciali di

Nel schema di strategia , l'interfaccia della strategia è solo una funzione. Nell'esempio wiki, sostituisci l'interfaccia con (Int, Int) => Int .

Nel schema dei metodi di fabbrica , l'intera classe di fabbrica è una funzione. Nell'esempio dell'incapsulazione wiki, ImageReaderFactory è solo una funzione (InputStream) => ImageReader .

A Runnable è solo una funzione () => Unit . Un Comparator è solo una funzione (A, A) => Int . Potrei andare avanti e avanti e avanti con questo, ma basti dire questo: hai passato le funzioni come argomenti per tutto questo tempo, solo nel modo più difficile.

Per quanto riguarda la tua ultima domanda, non capisco molto bene cosa intendi. Una funzione, in Scala, è un oggetto che implementa l'interfaccia FunctionN , dove N rappresenta l'arità. Naturalmente, i linguaggi non orientati agli oggetti non sono vincolati a rappresentare funzioni come oggetti. Infatti, anche i linguaggi object oriented non sono vincolati a questo - un int in Java non è un oggetto, quindi perché dovrebbe una funzione?

    
risposta data 01.08.2011 - 16:18
fonte
2

Valutazione pigra

Il vantaggio è la capacità di eseguire la valutazione Lazy dell'espressione che viene passata. Invece di dover calcolare il valore reale di x nel momento in cui viene passata l'espressione. Può creare un thunk che rimanda all'esecuzione fino alla sua assolutamente necessario.

Perché è utile? Un'istanza è che puoi definire una lista infinita di numeri data un'espressione.

Un esempio (Haskell)

let fibs = map fst $ iterate(\(a,b) -> (b,a+b)) (1,2)

In questo caso il valore fibs è dato un'espressione che è composta da più funzioni, in questo caso map fst iterate (e un'espressione anonima o lambda).

Se fibs dovesse valutare immediatamente, ciò causerebbe un overflow dello stack in quanto proverebbe immediatamente a calcolare una sequenza infinita di fibonacci. Se dovessi chiamare

let fibSum = sum fibs

Quindi è quello che succederebbe in realtà quando la somma proverà immediatamente a tentare di valutare i fib e causare uno stack overflow.

Tuttavia, se dovessi usare fib con un'altra espressione

let fibsEvenSum = sum(takeWhile(< 4000000) (filter even fibs))

Questa somma causerà comunque la valutazione di FIB, tuttavia il ritiro causerà la fine della valutazione quando l'elenco raggiunge i 4 milioni.

    
risposta data 01.08.2011 - 12:07
fonte
0

Le funzioni come parametri sono utili in molti molti modi. Considerare il modello Listener / Adapter di Java e le situazioni generali in cui sono necessarie le richiamate (API basate sugli eventi). In Java, per fare in modo che la GUI faccia qualcosa al clic del mouse o alla pressione di un tasto, sarà necessario implementare un'intera interfaccia Listener appropriata (o estendere la classe Adapter). Confrontalo con il semplice passaggio di un oggetto funzione da eseguire al clic del mouse (puoi vederlo in C # con il suo sistema di eventi). È molto più semplice.

Ci sono anche molte situazioni in cui si vorrebbe avere un determinato algoritmo, in cui una parte di esso è personalizzabile utilizzando una funzione passata. Per es.

  • Una famiglia di funzioni "notAny", "every", "any", "notEvery" che prendono tutti un parametro function e un parametro collection e restituiscono true se
    [la funzione restituisce false per tutti i coll. elem.]
    [la funzione restituisce true per tutti i coll. elem.]
    [la funzione restituisce true per qualsiasi coll. elem.]
    [funzione return false per qualsiasi coll. elem]
    rispettivamente
  • Un comparatore che confronta i risultati di una funzione sugli elementi di raccolta, ad es.
    il nuovo FuncComparator (Person.getName) consente di ordinare una raccolta di persone in base alla loro proprietà name
  • funzioni come "map", "filter", "groupBy", che prendono un parametro di funzione e una collezione (s) e producono una nuova collezione. La trasformazione della vecchia in nuova collezione utilizza in qualche modo la funzione parametro. Es:
    groupBy potrebbe prendere una funzione e una collezione e restituire una mappa di liste in cui gli elenchi contengono elementi della collezione originale per i quali la funzione parametro restituisce lo stesso valore e questo valore è la chiave della mappa.

Questi sono solo alcuni casi in cui un algoritmo generale di "andare oltre la raccolta e fare X" è notevolmente migliorato dalle funzioni come oggetti di prima classe, perché consente di specificare l'X attraverso il parametro della funzione. Questo non è tutto però ... ci sono usi più complessi delle funzioni come parametri (funzioni di prima classe), molte delle quali coinvolgono funzioni che generano funzioni. Si dovrebbe guardare al linguaggio di programmazione Clojure per esempi di questi usi.

Modifica: non conosco i dettagli esatti dell'implementazione, ma in genere l'implementazione utilizza una classe o un'istanza di interfaccia per rappresentare la funzione in JVM. Questa classe ha un metodo privilegiato che viene chiamato quando viene richiamato l'oggetto funzione. Questo plumbing è fatto dal compilatore di Scala.

    
risposta data 01.08.2011 - 13:24
fonte

Leggi altre domande sui tag