Funzioni di prima classe


11

Ho iniziato seriamente a dare un'occhiata a Lisp questo fine settimana (con questo intendo che ho solo imparato Lisp e non sono tornato 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 ad imparare Lisp, ho iniziato a chiedermi perché i linguaggi non funzionali non supportino funzioni di prima classe. So che linguaggi come C # possono fare cose simili con i delegati e fino a un certo punto puoi usare i puntatori alle funzioni in C / C ++ ma c'è un motivo per cui questo non diventerebbe mai una caratteristica in quei linguaggi? C'è uno svantaggio nel rendere le funzioni di prima classe? Per me è estremamente utile, quindi mi sono perso il motivo per cui più lingue (al di fuori del paradigma funzionale) non lo implementano.

[Modifica] Apprezzo le risposte finora. Dato che mi è stato mostrato che molte lingue ora supportano ora funzioni di prima classe, ribadirò la domanda per essere perché ci vorrebbe così tanto tempo per implementarle? [/Modificare]


3
Non sono d'accordo sul fatto che C # possa fare "cose ​​simili". Direi che ha funzioni di prima classe a tutti gli effetti (che tipo di rovina la tua premessa). Ha una sintassi per i letterali delle funzioni, puoi inserire le funzioni in variabili, ecc.
Logan Capaldo,

@Logan - Stavo discutendo se includere esempi in C # ma ho deciso di basarmi su questa voce di Wikipedia . Secondo la voce, non ci sono vere funzioni di prima classe poiché "poiché gli oggetti che detengono lo stato dinamico della funzione devono essere costruiti manualmente". Tuttavia, se questa è un'affermazione errata, mi piacerebbe sapere perché! (Dopotutto, sono qui per imparare e non essere bloccato nei miei modi!)
Jetti,

2
quella voce di Wikipedia è obsoleta. Un C # moderno fornisce un lambda adeguato.
SK-logic,

Penso che il paragrafo sia scritto male. Sembra che i funzioni C ++ non siano di prima classe e nemmeno i delegati C #? Anche se potrei essere d'accordo con l'argomento per i funzioni, non sono sicuro che lo farei per i delegati di C #. Dice anche "(vedi lambda lifting)", che è un'affermazione su questi linguaggi che supportano le chiusure lessicali piuttosto che "funzioni come valori". Puoi averne uno senza l'altro. Anche se questo è il caso, non è vero per C #, ha chiusure lessicali. Parte del problema è che "la funzione di prima classe" può essere un termine vago.
Logan Capaldo,

1
@Logan & SK-Logic - Apprezzo il tuo feedback e rimani costruttivo. Sto ancora imparando ed è molto bello non essere infiammato, quindi lo apprezzo. Grazie mille per i commenti e le risposte!
Jetti,

Risposte:


5

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

Aggiornare:

Un'implementazione di chiusure richiede il lambda-lifting - una tecnica originariamente piuttosto aliena per i programmatori imperativi. Le funzioni di prima classe appropriate (che includono le chiusure) richiedono almeno un po 'di supporto dal runtime e dalla VM. Ci è voluto anche del tempo per adottare le vecchie tecniche funzionali nel mondo imperativo.

E, la parte più importante: le funzioni di prima classe sono appena utilizzabili se non è presente la raccolta dei rifiuti. È 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 il linguaggio per renderlo comprensibile dai programmatori medi. .NET ha seguito per la prima volta, e solo recentemente si è separato da quella direzione (IMHO, abbastanza giustificata e appropriata).

Tutti questi concetti richiedono tempo per essere digeriti dall'industria.


Ho modificato la domanda originale in base alle risposte.
Jetti,

Funzioni di prima classe! = Chiusure (e GC è molto più necessario per quest'ultima). Sebbene, sì, sono strettamente correlati e raramente, se mai, li vedi separati.

@delnan, senza almeno qualche forma di chiusura lessicale, le funzioni non sono componibili e non costruibili in fase di esecuzione, il che è obbligatorio per una definizione di funzioni di prima classe.
SK-logic,

No. Potresti non consentire il riferimento a variabili di ambiti racchiusi (o copiare i valori della variabile riferita al momento della creazione della funzione - non so se questo conta come chiusura). Il risultato non è particolarmente utile, ma le funzioni possono ancora essere costruite in fase di runtime senza essere chiusure e quindi avresti (strane) funzioni di prima classe.

1
@ SK-logic: C ++ 0x fornisce chiusure senza garbage collection con il solito trucco -> se la variabile non rientra nell'ambito e si sta ancora aderendo a un riferimento, l'utilizzo del riferimento è un comportamento indefinito. Quindi è possibile ... mette l'onere sullo sviluppatore.
Matthieu M.

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ù semplice compilare un linguaggio in cui gestisci la memoria manualmente, in modo che un po 'C / C ++ esca dall'equazione.

E poi sì, c'è la questione 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 stupide in qualsiasi momento. Puoi davvero aggiungerlo a Java, ad esempio, senza introdurre un grande cambiamento di paradigma nell'intero linguaggio? Dov'è il contratto o quel senso di sicurezza (IMO falso) che le persone ottengono conoscendo il costrutto garantisce che funzionerà sempre allo stesso modo ogni volta? Potrebbe avere senso trattare le funzioni legate agli oggetti come metodi come un diverso organismo nei linguaggi che ha permesso alle funzioni di esistere indipendentemente in primo luogo, ma in Java non è proprio un'opzione.

In JavaScript, OOP e funzionale sono molto intrecciati e personalmente troverei difficile vedere funzioni di prima classe come tutt'altro che imbullonate in lingue dove non lo erano. Ma ciò richiede una serie di altri cambiamenti che cambiano il paradigma, inclusi alti livelli di mutabilità negli oggetti e nei loro stessi metodi, oltre a poter chiamare funzioni come se fossero membri di qualsiasi oggetto al volo.

Le lingue non sono solo set di strumenti pieni di do-hickeys per fare le cose per la maggior parte. Sono paradigmi. Fasci di idee, strategie e opinioni che tutti i tipi di andare insieme in un modo che è collegato (o sembrano collegati). In molti casi le funzioni come nome e verbo in realtà non rientrano affatto nel paradigma o nella migliore delle ipotesi sono un adattamento imperfetto.

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


Puoi trattare tutti i metodi come sigillati o semplicemente sigillare quelli a cui tieni di più, e starai bene.
Alexei Averchenko,

@AlexeiAverchenko Sono felice di dire che non sono sicuro al 100% di cosa tu voglia dire. Mi dispiace aver perso il tuo commento fino ad ora. Googling "metodi sigillati".
Erik Reppen,

4

Non è proprio impossibile. Ma è ancora un'altra caratteristica e il budget di complessità è limitato. Può essere ritenuto superfluo dal progettista del linguaggio (o addirittura non si presenta) - "perché diamine avremmo bisogno di passare le funzioni? Questo linguaggio è per programmare un sistema operativo!". Potrebbe anche essere necessario uno sforzo significativo per fondersi con il resto della lingua. Ad esempio, un tipo di funzione può richiedere serie aggiunte al sistema dei tipi (ad es. In Java), ancora di più se si ha un sovraccarico (grazie a @Renesis per averlo sottolineato). È inoltre necessario fornire un codice di libreria per utilizzare la fattibilità: nessuno vuole definirsi map.

Potrebbe anche rendere più difficili da raggiungere altri obiettivi della lingua:

  • Diventa "più difficile" da ottimizzare (non in realtà più difficile in molti casi, ma richiede approcci diversi da quelli a cui sei abituato). Ad esempio, se è possibile riassegnare le funzioni globali, è necessario dimostrare che fnon vengono mai riassegnate prima di incorporarle.
  • Allo stesso modo, se si creano oggetti con funzionalità complete, è necessario un compilatore intelligente e un JIT per rimuovere l'overhead associato e rendere la chiamata efficiente (in termini di velocità e spazio) come spingere argomenti e indirizzo di ritorno e passare a qualche indirizzo.
  • Come già accennato, è un'altra funzionalità completa e i primi passi per supportare ancora un altro paradigma: se vuoi un linguaggio semplice, forse non puoi permetterti di aggiungere funzioni di prima classe senza lanciare altre cose (che potresti considerare molto più importanti) su.
  • Forse semplicemente non si fonde bene con il resto della lingua. Se si progetta la lingua, ad esempio, per essere la migliore incarnazione di OOP dopo Smalltalk, è possibile concentrarsi 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é un linguaggio di programmazione L1 non abbia la funzione F del linguaggio L2 molto diverso.


1

Penso che il primo problema sia un fraintendimento che Orientamento agli oggetti e Funzionale non possono essere mescolati. Un breve elenco di lingue descritte, almeno da Wikipedia, come entrambe: JavaScript , ActionScript , Python , C # , F # .

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

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

Qual è la vera domanda?

Quindi, comprendendo che anche i linguaggi orientati agli oggetti possono essere funzionali e che questi linguaggi contengono funzioni di prima classe, sembra che la domanda che stai cercando sia: perché alcuni linguaggi orientati agli oggetti non contengono funzioni di prim'ordine?

Sovraccarico di funzioni

Uno dei motivi principali di ciò è la difficoltà di definire funzioni di prima classe quando il linguaggio ha anche scelto di supportare il sovraccarico delle funzioni (esempio in Java):

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

A quale dispatchEventfunzione si riferirebbe una variabile?

Programmazione basata su classi

La programmazione basata su classi non impedisce ai linguaggi di supportare oggetti di prima classe, ma può creare confusione 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 essenzialmente essere richiamate con qualsiasi oggetto in quanto ambito al momento dell'esecuzione.

Quando si aggiungono classi (non dinamiche), si hanno funzioni intrinsecamente legate a un'istanza, non solo alla classe stessa. Questo getta alcune rughe nella specifica di Function.applycui onestamente non ho scavato per scoprire come hanno affrontato.


3
"L'inclusione di funzioni di prima classe in sé rende più o meno funzionale un linguaggio." - Sbagliato. È un prequisito, sì. Ma c'è molto altro, come (per citarne solo tre) evitare lo stato mutevole, l'attenzione alle espressioni e all'applicazione delle funzioni piuttosto che alle dichiarazioni sequenziali e l'enfasi sulla trasparenza referenziale.

@delnan Dovresti andare su Wikipedia corretta allora ... A meno che un "linguaggio funzionale" e un "linguaggio che sostengano un paradigma funzionale" siano due cose diverse.
Nicole,

1
@Rensis: sono cose diverse. Puoi creare qualcosa di simile a oggetti (anche includendo vtables) in C, ma non è carino. Passare da "ha funzioni di prima classe" a "è un linguaggio funzionale" non è poi così male, ma è comunque una differenza. Inoltre, wiki (correttamente) afferma sulla pagina collegata a "Queste funzionalità sono necessarie per lo stile di programmazione funzionale [...]." (cioè: non "la caratteristica che definisce") ed elenca molte altre caratteristiche nella pagina su FP.

@delnan, va bene, ho corretto la mia formulazione. Volevo solo dire che la condizione per una lingua fosse considerata come un paradigma funzionale - così come la pagina di Wikipedia per ciascuna di quelle lingue che ho elencato. Non intendevo dire che è tutto ciò che fa parte dello stile di programmazione funzionale .
Nicole,

0

Mi sono chiesto la stessa cosa me stesso. Una volta che sono in una lingua con lambda li uso MOLTO. Anche PHP migliora quando ti rendi conto che puoi fare una chiusura con php 5.3 (non è bello come lisp, ma comunque migliore)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.