Funzioni di prima classe

11

Ho iniziato seriamente a dare un'occhiata a Lisp questo fine settimana (con il quale intendo che ho solo imparato il Lisp e non tornare ai progetti in C #) e devo dire che lo adoro. Mi sono dilettato con altri linguaggi funzionali (F #, Haskell, Erlang) ma non ho sentito il sorteggio che Lisp mi ha dato.

Ora, mentre continuo a imparare Lisp, ho iniziato a chiedermi perché i linguaggi non funzionali non supportano funzioni di prima classe. So che linguaggi come C # possono fare cose simili con i delegati e in una certa misura puoi usare i puntatori alle funzioni in C / C ++ ma c'è un motivo per cui questo non sarebbe mai diventato una funzionalità in quelle lingue? C'è un inconveniente nel rendere le funzioni di prima classe? Per me è estremamente utile, quindi sono perso dal motivo per cui più lingue (al di fuori del paradigma funzionale) non la implementano.

[Modifica] Apprezzo le risposte finora. Dato che mi è stato dimostrato che molte lingue ora supportano funzioni di prima classe ora, riformulerò la domanda perché ci vorrebbe tanto tempo prima che le lingue le implementino? [/ Modifica]

    
posta Jetti 27.02.2011 - 17:54
fonte

5 risposte

5

C #, VB.NET, Python, JavaScript, ora anche C ++ 0x offre funzioni di prima classe.

Aggiornamento:

L'implementazione di chiusure richiede il lambda-lifting, una tecnica originariamente piuttosto estranea ai programmatori imperativi. Le corrette funzioni di prima classe (incluse le chiusure) richiedono almeno un certo supporto dal runtime e dalla VM. Ci è voluto del tempo per adottare le vecchie tecniche funzionali nel mondo imperativo.

E, la parte più importante: le funzioni di prima classe sono a malapena utilizzabili se non è presente la garbage collection. È stato introdotto in una programmazione di massa solo di recente, con Java e, di conseguenza, .NET. E l'approccio originale di Java era quello di semplificare eccessivamente la lingua al fine di renderla comprensibile dai programmatori medi. .NET è stata la prima a seguire, e solo recentemente si è separata da quella (IMHO, abbastanza giustificata e appropriata) direzione.

Tutti questi concetti richiedono tempo per essere digeriti dal settore.

    
risposta data 27.02.2011 - 18:01
fonte
5

Le funzioni di prima classe sono molto meno interessanti senza chiusure.

Le chiusure non sono realmente possibili senza una sorta di gestione dinamica dell'ambito (garbage collection). Una delle cose che rende C / C ++ così altamente performante è il fatto che è molto più facile compilare una lingua dove si gestisce la memoria manualmente, in modo tale da togliere C / C ++ dall'equazione.

E poi sì, c'è il problema dell'impatto OOP. Non hai più una separazione di metodi e proprietà. I metodi sono essi stessi proprietà che accettano funzioni come valori. In quel contesto, cosa significa veramente sovraccaricare i metodi poiché puoi semplicemente scambiare le cose sciocche in qualsiasi momento. Puoi davvero aggiungerlo a Java, ad esempio, senza introdurre un importante cambiamento di paradigma nell'intero linguaggio? Dov'è il contratto o quel senso di sicurezza (IMO false) che le persone traggono dal sapere che il costrutto garantisce che funzionerà sempre allo stesso modo tutte le volte? Potrebbe avere senso trattare le funzioni legate agli oggetti come metodi come un diverso organismo in linguaggi che consentiva alle funzioni di esistere indipendentemente, ma in Java non è davvero un'opzione.

In JavaScript, OOP e funzionale sono molto intrecciati e personalmente troverei difficile vedere le funzioni di prima classe come se non fossero imbullonate nelle lingue in cui non erano. Ma ciò richiede una serie di altre modifiche che cambiano paradigma, inclusi alti livelli di mutevolezza negli oggetti e nei loro stessi metodi, oltre a essere in grado di chiamare le funzioni come se fossero membri di qualsiasi oggetto al volo.

Le lingue non sono solo set di strumenti pieni di do-hickey per fare le cose per la maggior parte. Sono paradigmi. Gruppi di idee, strategie e opinioni che ogni tipo di andare insieme in un modo che è collegato (o sembra collegato). In molti casi le funzioni come nome e verbo in realtà non si adattano affatto al paradigma o, nel migliore dei casi, sono un adattamento imperfetto.

Detto questo, mi sento come se mi mancasse un braccio quando sono costretto a programmare senza di loro.

    
risposta data 21.01.2013 - 14:26
fonte
4

Non è davvero impossibile. Ma è un'altra caratteristica e il budget di complessità è limitato. Può essere considerato non necessario da (o non si verifica nemmeno) il progettista del linguaggio - "perché diamine dovremmo passare le funzioni in giro? Questo linguaggio è per programmare un sistema operativo!". Potrebbe anche richiedere uno sforzo significativo per unirsi al resto della lingua. Ad esempio, un tipo di funzione può richiedere aggiunte serie al sistema di tipi (ad es. In Java), ancor più se si ha un sovraccarico (grazie a @Renesis per averlo indicato). È inoltre necessario fornire un codice di libreria per sfruttare la praticabilità - nessuno vuole definire map se stessi.

Potrebbe anche rendere più difficili gli altri obiettivi della lingua:

  • Diventa "difficile" ottimizzare (in realtà non è più difficile in molti casi, ma richiede approcci diversi da quelli a cui sei abituato). Ad esempio, se le funzioni globali possono essere riassegnate, devi dimostrare che f non viene mai riassegnato prima di inserirlo in linea.
  • Analogamente, se si realizzano oggetti con funzioni complete, è necessario un compilatore intelligente e JIT per rimuovere l'overhead associato a tale operazione e rendere la chiamata più efficiente (speed- e spazio-saggio ) come spingendo argomenti e indirizzo di ritorno e saltando a qualche indirizzo.
  • Come già accennato, è un'altra funzionalità completa e i primi passi verso il supporto di un altro paradigma: se vuoi un linguaggio semplice, forse non puoi permetterti di aggiungere funzioni di prima classe senza lanciare altre roba (che potresti considerare molto più importante).
  • Forse semplicemente non si sposa bene con il resto della lingua. Se progetta la lingua ad es. essere la migliore incarnazione di OOP da Smalltalk, potresti concentrarti su quello invece di offrire un altro paradigma molto diverso. Soprattutto se è difficile integrare i due (vedi sopra). N paradigmi fatti bene è più piacevole da programmare rispetto ai paradigmi N + 1 fatti male.

Allo stesso modo, ci si può chiedere perché qualsiasi linguaggio di programmazione L1 non ha la caratteristica F della lingua L2 molto diversa.

    
risposta data 27.02.2011 - 18:29
fonte
1

Penso che il primo problema sia un equivoco che non sia possibile combinare Object-Oriented e Functional. Un rapido elenco di lingue descritte, almeno da Wikipedia, come entrambi: JavaScript , ActionScript , Python , C # , F # .

Il secondo problema sembra essere una definizione di funzioni di prima classe - perché non consideri C # averli, per esempio?

Non sono un esperto linguistico funzionale, quindi per favore correggimi nei commenti se sbaglio, ma la mia comprensione è che l'inclusione di funzioni di prima classe stessa definisce più o meno se una lingua supporta un paradigma funzionale .

Qual è la vera domanda?

Quindi, capire che i linguaggi orientati agli oggetti possono essere anche funzionali, e queste lingue contengono funzioni di prima classe, sembra che la domanda che stai cercando sia perché alcuni oggetti- le lingue orientate non contengono funzioni di prima classe?

Sovraccarico di funzioni

Uno dei motivi principali è la difficoltà di definire funzioni di prima classe quando la lingua ha scelto anche di supportare l'overloading di funzioni (esempio in Java):

public int dispatchEvent(Event event);
public int dispatchEvent(String event, Object data);

Quale funzione dispatchEvent farebbe riferimento a una variabile?

Programmazione basata su classi

La programmazione basata su classi non impedisce a un linguaggio di supportare oggetti di prima classe, ma può renderlo più confuso o aggiungere domande a cui rispondere.

ActionScript, ad esempio, come linguaggio ECMAScript iniziato in un paradigma molto più funzionale come JavaScript. Le funzioni non erano intrinsecamente legate agli oggetti, potevano essere essenzialmente chiamate con qualsiasi oggetto in quanto portata al momento dell'esecuzione.

Quando aggiungi classi (non dinamiche), hai funzioni che sono intrinsecamente associate a un'istanza, non solo alla classe stessa. Questo getta alcune rughe nelle specifiche di Function.apply che onestamente non ho scavato per scoprire come l'hanno affrontato.

    
risposta data 27.02.2011 - 18:29
fonte
0

Mi sono chiesto la stessa cosa anch'io. Una volta che sono in una lingua con lambdas, li uso molto. Anche PHP migliora quando ti rendi conto che puoi fare una chiusura con php 5.3 (non è bello come lisp, ma è ancora meglio)

    
risposta data 27.02.2011 - 17:57
fonte