C # Dev - Ho provato Lisps, ma non capisco [chiuso]


37

Dopo alcuni mesi di conoscenza e di gioco con Lisp, sia CL che un po 'di Clojure, non vedo ancora un motivo convincente per scrivere qualcosa al suo posto invece di C #.

Vorrei davvero alcuni motivi convincenti, o per qualcuno sottolineare che mi manca qualcosa di veramente grande .

I punti di forza di Lisp (secondo la mia ricerca):

  • Notazione compatta ed espressiva - Più che in C #, sì ... ma mi sembra di poter esprimere quelle idee anche in C #.
  • Supporto implicito per la programmazione funzionale - C # con metodi di estensione LINQ:
    • mapcar = .Select (lambda)
    • mapcan = .Select (lambda) .Aggregate ((a, b) => a.Union (b))
    • auto / primo =. Primo ()
    • cdr / rest = .Skip (1) .... ecc.
  • Lambda e supporto di funzioni di ordine superiore - C # ha questo, e la sintassi è probabilmente più semplice:
    • "(lambda (x) (body))" versus "x => (body)"
    • "# (" con "%", "% 1", "% 2" è utile in Clojure
  • Invio di metodi separato dagli oggetti - C # ha questo tramite metodi di estensione
  • Invio multimetodo - C # non lo ha in modo nativo, ma potrei implementarlo come una chiamata di funzione in poche ore
  • Il codice è dati (e macro) - Forse non ho "ottenuto" le macro, ma non ho visto un singolo esempio in cui l'idea di una macro non potesse essere implementata come funzione; non cambia la "lingua", ma non sono sicuro che sia un punto di forza
  • DSL - Può farlo solo attraverso la composizione di funzioni ... ma funziona
  • Programmazione "esplorativa" non tipizzata - per le strutture / classi, le autoproperties di C # e l '"oggetto" funzionano abbastanza bene, e puoi facilmente passare a una digitazione più forte man mano che procedi
  • Funziona su hardware non Windows - Sì, quindi? Al di fuori del college, ho conosciuto solo una persona che non esegue Windows a casa, o almeno una VM di Windows su * nix / Mac. (Ancora una volta, forse questo è più importante di quanto pensassi e mi sono appena fatto il lavaggio del cervello ...)
  • Il REPL per il design dal basso - Ok, lo ammetto è davvero bello e mi manca in C #.

Cose che mi mancano in Lisp (a causa di un mix di C #, .NET, Visual Studio, Resharper):

  • Namespace. Anche con metodi statici, mi piace legarli a una "classe" per categorizzare il loro contesto (Clojure sembra avere questo, CL non sembra.)
  • Ottima compilazione e supporto in fase di progettazione
    • il sistema dei tipi mi permette di determinare la "correttezza" delle strutture dati che passo in giro
    • qualsiasi cosa errata viene sottolineata in tempo reale; Non devo aspettare fino al momento dell'esecuzione per sapere
    • i miglioramenti del codice (come l'uso di un approccio FP invece di uno imperativo) sono sottoposti a autosuggestione
  • Strumenti di sviluppo della GUI: WinForms e WPF (so che Clojure ha accesso alle librerie della GUI Java, ma sono del tutto estranee a me).
  • Strumenti di debug della GUI: breakpoint, step-in, step-over, ispettori di valore (testo, xml, personalizzati), orologi, debug-by-thread, breakpoint condizionali, finestra di stack di chiamate con la possibilità di saltare al codice a qualsiasi livello nello stack
    • (Per essere onesti, il mio periodo con Emacs + Slime sembrava fornire un po 'di questo, ma sono parziale dell'approccio guidato dalla GUI)

Mi piace molto l'hype che circonda Lisp e gli ho dato una possibilità.

Ma c'è qualcosa che posso fare in Lisp che non posso fare anche in C #? Potrebbe essere un po 'più dettagliato in C #, ma ho anche il completamento automatico.

Cosa mi sto perdendo? Perché dovrei usare Clojure / CL?


4
Dato che stai già programmando in uno stile funzionale e sembra che tu faccia abbastanza affidamento sull'infrastruttura di Windows, non riesco a vedere alcun motivo convincente per cambiare da C #. Quasi tutti quelli che conosco usano Mac o Linux, quindi molto dipende chiaramente dalla folla con cui corri (ho usato tutte le versioni di Windows dalla 3.1 ma preferisco ancora lavorare con software multipiattaforma e sistemi * nix in generale ... ma poi non eseguo alcun lavoro con GUI nativa, tutti i server e roba dell'interfaccia utente Web)
Sean Corfield,

2
Puoi dare un'occhiata a The Swine Before Perl . È un discorso divertente da ascoltare e presenta un semplice esempio di ciò a cui le macro vanno bene.
Matthias Benkard,

4
"Non ho visto un singolo esempio in cui l'idea di una macro non potesse essere implementata come una funzione" - Mi piacerebbe vedere come scrivere ANDo ORcome una funzione. Potrebbe essere fatto (dato LAMBDA, che è anche una macro) ma non vedo un modo ovvio per farlo che non farebbe assolutamente schifo.

1
"Namespace. ... Clojure sembra avere questo, CL non sembra" - puoi essere più specifico su ciò che stai cercando? Non ho usato Clojure, ma i suoi spazi dei nomi sembrano praticamente dei pacchetti di CL.

4
Jonathan: CL usa :(o ::per i simboli non esportati) per nominare i simboli nei pacchetti, ad esempio, il tuo esempio qui userebbe http:sessione chat:session.

Risposte:


23

Le macro ti consentono di scrivere compilatori senza lasciare il comfort della tua lingua. DSL in lingue come C # generalmente equivalgono a un interprete di runtime. A seconda del dominio, ciò potrebbe essere problematico per motivi di prestazioni. La velocità è importante , altrimenti codifichi in un linguaggio interpretato e non in C #.

Inoltre, le macro consentono anche di considerare i fattori umani: qual è la sintassi più intuitiva per un determinato DSL? Con C # non c'è molto che puoi fare per la sintassi.

Quindi Lisp ti consente di partecipare al design del linguaggio senza sacrificare un percorso verso l' efficienza . E mentre questi problemi potrebbero non importa a voi , sono estremamente importanti in quanto alla base le fondamenta di tutti i linguaggi di programmazione utili produzione orientata. In C # questo elemento fondamentale ti viene esposto in una forma molto limitata nella migliore delle ipotesi.

L'importanza delle macro non si perde in altre lingue - mi viene in mente il modello Haskell, camlp4. Ma ancora una volta è un problema di usabilità : le macro Lisp fino ad oggi sono probabilmente l'implementazione più semplice ma potente della trasformazione in fase di compilazione.

Quindi, in breve, ciò che la gente generalmente fa con lingue come C # è costruire DSIL (Domain Specific Interpreted Languages). Lisp ti dà l'opportunità di creare qualcosa di molto più radicale, DSP (Domain Specific Paradigms). La racchetta (precedentemente PLT-Scheme) è particolarmente stimolante in questo senso: hanno un linguaggio pigro (Lazy Racket), uno tipizzato (Typed Racket), Prolog e Datalog tutti incorporati in modo idiomatico tramite macro. Tutti questi paradigmi forniscono potenti soluzioni a grandi classi di problemi, problemi che non sono meglio risolti dalla programmazione imperativa o persino dai paradigmi FP.


3
Ciò che trovo interessante riguardo a tale argomento è che non ho mai incontrato un'opportunità (o l'ho completamente trascurata nella mia ignoranza) per l'implementazione di un DSL / DSIL. Potresti approfondire la potenza dei DSL? (Sia per uno sviluppatore che per un utente.) Sembra che potrebbe essere la cosa più grande che mi manca davvero.

15
@Jonathan Mitchem, stai già utilizzando molti DSL esterni: file di configurazione, script di compilazione, configurazioni ORM, generatori di codice visivo (ad es. Editor di winforms), XAML, generatori di parser, ecc. I DSL incorporati sono ancora migliori, mentre doni non hanno bisogno di uno strumento di costruzione separato per loro, e sono serviti in una sola lingua. E devi avere familiarità con almeno due dei DSL incorporati: espressioni regolari e SQL.
SK-logic,

Wow, ok. Non ho mai pensato a quelli come DSL. Ora, mi sono intenzionalmente allontanato molto da ciò, sulla base di "tutto ciò che posso fare con c #, rimarrò con c # per". Mi piace attenermi a uno strumento con un comportamento coerente, personalmente. Ma capisco il valore dei DSL in questi esempi.

2
@Jonathan Mitchem, il problema con qualsiasi strumento dato è che non sarà necessariamente adatto per un determinato scopo. Devi scegliere strumenti diversi per compiti diversi. E il potere di qualsiasi meta-lingua, incluso Lisp, è che non devi passare completamente a un altro strumento, in quanto puoi far crescere i tuoi strumenti specifici del dominio in cima alla tua lingua principale. Ti suggerisco di dare un'occhiata a Nemerle, sarebbe più facile capirlo per uno sviluppatore C #, e le sue macro sono quasi potenti come quelle di Lisp.
SK-logic,

3
"Mi piace attaccare con uno strumento ..." I DSL correttamente realizzati in Lisp non nascondono mai tutto il potere di Lisp, quindi hai ancora uno strumento. Aggiungono semplicemente al vocabolario in un modo che rende la codifica per un determinato dominio più "naturale", cioè con migliori astrazioni e organizzazione generale.

15

Quasi tutto ciò che era originariamente disponibile solo in Lisps è fortunatamente migrato in molte altre lingue moderne. La più grande eccezione è la filosofia "code is data" e le macro.

Il codice è dati (e macro) - Forse non ho "ottenuto" le macro, ma non ho visto un singolo esempio in cui l'idea di una macro non potesse essere implementata come funzione

Sì, le macro sono difficili da grok. La metaprogrammazione in generale è difficile da grok. Se hai visto una macro che poteva essere implementata come una funzione, allora il programmatore stava sbagliando. Le macro devono essere utilizzate solo quando una funzione non funziona.

L'esempio "ciao mondo" di una macro è scrivere "if" in termini di cond. Se sei veramente interessato ad apprendere il potere delle macro, prova a definire un "my-if" nel clojure, usando le funzioni e guarda come si rompe. Non intendo essere misterioso, non ho mai visto nessuno iniziare a capire le macro solo con una spiegazione, ma questa presentazione è un'introduzione abbastanza buona: http://www.slideshare.net/pcalcado/lisp-macros-in -20 minuti-con-clojure-presentazione

Ho avuto piccoli progetti in cui ho salvato letteralmente centinaia / migliaia di righe di codice usando le macro (rispetto a quello che avrebbe preso in Java). Gran parte di Clojure è implementata in Clojure, il che è possibile solo grazie al sistema macro.


3
Senza toccare alcun codice, ho attraversato lo scenario di implementazione di un "if" senza macro nella mia testa, sia in Clojure che in C #. In modo efficace (o letteralmente) non può essere fatto. Ammetto che è pulito. Ma mi manca la connessione di quanto mi sia utile. Cosa posso fare con le macro (oltre a scrivere "if") che non posso fare con un design funzionale o OO intelligente? "In che modo può aiutarmi" non è un criterio valido per valutare una lingua, ma è per valutare se la userò. (Voglio davvero che valga la pena passare a un Lisp, ma non ha raggiunto il punto di diventare una valida alternativa.)

1
Mi ci vorrà un po 'di tempo per capire questo esempio. Per me, "il salvataggio del codice del boilerplate" di solito invoca il termine "refactoring", che è parte del motivo per cui le spiegazioni non mi hanno convinto. Ho una soluzione che funziona in ogni caso in cui l'ho applicata. Penso quindi che la domanda sia: come identificare i casi in cui è possibile utilizzare una macro?

1
Concordo sul fatto che le macro valgono la pena, ma non è vero che un my-if le richieda, può essere scritto come una funzione di ordine superiore (vedere un esempio CL di seguito). Hai davvero bisogno di macro solo se vuoi usare il codice o inserirlo in un nuovo contesto lessicale. (defun my-if (test then &optional else) (cond (test (funcall then)) ('otherwise (funcall else))))

1
Fondamentalmente con una funzione puoi scegliere di accettare entrambi i codici tra virgolette, che puoi percorrere ma manca il suo contesto lessicale perché stai camminando ed eseguendolo nel contesto lessicale della tua funzione. Oppure puoi accettare chiusure, che mantengono il loro contesto lessicale ma puoi solo chiamarle, non percorrerle o aggiungere qualcosa al loro contesto lessicale. Per fare entrambe le cose è necessaria una macro, che può camminare e racchiudere il codice prima che la sua espansione venga inserita nel contesto lessicale della chiamata macro.

7
@Jonathan Mitchem, la sintassi LINQ è un bell'esempio di cosa si può fare con le macro, ma invece è stato necessario implementarlo in un nucleo linguistico, poiché il linguaggio non supporta metaprogrammi decenti.
SK-logic,

14

Non sono un esperto di Common Lisp, ma conosco ragionevolmente bene sia C # che Clojure, quindi spero che questa sia una prospettiva utile.

  • Sintassi semplice => potenza - I Lisps rappresentano la sintassi più semplice che potrebbe funzionare. Le espressioni S sono tutto ciò di cui hai bisogno. Una volta che hai grokked "(funzione-chiamata arg1 arg2 arg3)", in pratica lo hai capito. Il resto è solo scegliere le giuste funzioni chiamate e argomenti. Sembra quasi banalmente semplice, ma il fatto è che questa semplicità è ciò che dà a Lisps tanta forza e flessibilità, e in particolare abilita le capacità di meta-programmazione per cui Lisp è famosa. ad es. se voglio che una macro richiami diverse funzioni diverse sugli stessi argomenti, faccio semplicemente qualcosa del tipo seguente (non questa non è solo un'applicazione con funzione di runtime - è una macro che genera codice compilato come se avessi scritto tutte le singole chiamate di funzione a mano):
(defmacro print-many [functions args]  
  `(do   
     ~@(map   
        (fn [function] `(println (~function ~@args)))   
        functions)))

(print-many [+ - * /] [10 7 2])  
19  
1  
140  
5/7
  • Come risultato della sintassi incredibilmente semplice, la filosofia del "codice è dato" di Lisp è molto più potente di qualsiasi cosa tu possa fare con la composizione di funzioni / modelli / generici ecc. È più di un semplice DSL, è generazione di codice e manipolazione, al momento della compilazione , come caratteristica fondamentale della lingua. Se cerchi di ottenere questo tipo di capacità in un linguaggio non omoiconico come C # o Java, finirai per reinventare Lisp, malamente. Da qui la famosa decima regola dei Greenspuns: "Qualsiasi programma C o Fortran sufficientemente complicato contiene un'implementazione lenta ad hoc, specificata in modo informatico, corrotta da bug, della metà di Common Lisp". Se ti sei mai trovato a inventare un linguaggio di controllo del flusso / templing completo nella tua applicazione, probabilmente sai cosa intendo .....

  • La concorrenza è un punto di forza unico di Clojure (anche rispetto ad altri Lisps), ma se credi che il futuro della programmazione significherà dover scrivere applicazioni che si adattano a macchine altamente multi-core, allora dovresti davvero esaminare questo - è carino innovativo. Clojure STM (Software Transactional Memory) funziona perché Clojure abbraccia immutabilità e costrutti di concorrenza senza lock basati su una nuova separazione tra identità e stato (vedi l'eccellente video di Rich Hickey su identità e stato ). Sarebbe molto doloroso innestare questo tipo di capacità di concorrenza in un ambiente di linguaggio / runtime in cui una parte significativa delle API lavora su oggetti mutabili.

  • Programmazione funzionale - I Lisps enfatizzano la programmazione con funzioni di ordine superiore. Hai ragione che può essere emulato in oggetti OO con chiusure / oggetti funzione ecc. Ma la differenza è che l'intero linguaggio e la libreria standard sono progettati per aiutarti a scrivere codice in questo modo. Ad esempio, le sequenze Clojure sono pigre , quindi possono essere infinitamente lunghe a differenza delle tue ArrayLists o HashMaps in C # / Java. Ciò rende alcuni algoritmi molto più facili da esprimere, ad esempio i seguenti implementano un elenco infinito di numeri di fibonacci:

    (def fibs (lazy-cat '(0 1) (map + fibs (drop 1 fibs))))

  • Digitazione dinamica - I lividi tendono ad essere all'estremità "dinamica" dello spettro del linguaggio di programmazione funzionale (al contrario di lingue come Haskell con una concezione molto forte e bella di tipi statici). Ciò ha sia vantaggi che svantaggi, ma direi che i linguaggi dinamici tendono a favorire la produttività della programmazione a causa della maggiore flessibilità. Questa digitazione dinamica ha un costo minore in termini di prestazioni di runtime, ma se ciò ti dà fastidio puoi sempre aggiungere suggerimenti di tipo al codice per ottenere la digitazione statica. Fondamentalmente: ottieni comodità per impostazione predefinita e prestazioni se sei disposto a fare un po 'di lavoro extra per ottenerlo.

  • Sviluppo interattivo - in realtà penso che tu possa ottenere una sorta di REPL per C # 4.0, ma in Lisp è una pratica standard piuttosto che una novità. Non è necessario eseguire un ciclo di compilazione / compilazione / test: si scrive il codice direttamente nell'ambiente in esecuzione e solo successivamente lo si copia nei file di origine. Ti insegna un modo molto diverso di programmare, dove puoi vedere immediatamente i risultati e perfezionare la tua soluzione in modo iterativo.

Alcuni brevi commenti sulle cose che vedi "mancanti":

  • Come dici tu, Clojure ha spazi dei nomi. In realtà, sono spazi dei nomi dinamici: è possibile aggiornarli in fase di esecuzione - questo offre alcuni sorprendenti vantaggi per lo sviluppo interattivo. Mi sono divertito un sacco a ridefinire le funzioni sotto il naso di un thread in esecuzione o hackerare una struttura di dati dal vivo ...
  • Supporto in fase di compilazione / progettazione - non molto rilevante se stai programmando un REPL - lo fai e vedi direttamente il risultato. Detto questo, Clojure sta iniziando a ottenere un supporto IDE migliorato, ad esempio il plugin CounterClockwise per Eclipse .
  • Sviluppo di GUI - Sì, dovrai imparare una nuova API, ma lo sarà sempre quando cambi lingua .... una buona notizia è che le API Java non sono così difficili e ora ci sono alcuni interessanti Clojure- involucri / esempi specifici che sembrano abbastanza facili da usare. Vedi questa domanda sullo sviluppo della GUI di Clojure per alcuni esempi interessanti
  • Debug della GUI: funziona con il debugger della GUI in Eclipse supponendo che tu usi CounterClockwise o Enclojure se usi Netbeans. Detto questo, non utilizzo questa funzionalità: trovo più produttivo il debug interattivo presso il REPL.

Personalmente trovo i vantaggi di Clojure / Lisp piuttosto convincenti e non sto pensando di tornare a C # / Java (oltre a quello che mi serve per prendere in prestito tutte le utili librerie!).

Tuttavia, ci sono voluti alcuni mesi per farmi davvero capire tutto. Se sei veramente interessato all'apprendimento di Lisp / Clojure come esperienza di apprendimento illuminante, non c'è sostituto per immergerti e costringerti a implementare alcune cose .....


1
Grazie per la grande enumerazione di idee. In realtà uso molto sequenze pigre tramite il costrutto IEnumerable <> in C # (e non ho più toccato una ArrayList dal 2005 circa) ma capisco l'idea. I primitivi di concorrenza di Clojure sono estremamente impressionanti. Qualche anno fa facevo il grid computing in C # - concorrenza su molte macchine multi-core - e credo ancora che sia il futuro. Probabilmente l'idea più grande che ho avuto da tutti è "devi solo scavare e sperimentarlo, non può davvero essere spiegato". Quindi continuerò a scavare e continuerò a sperimentare.

1
Bello, felice di aver aiutato - ed è assolutamente lo spirito giusto !!
Mikera,

10

C # ha molte funzionalità, ma il mix sembra diverso. Il fatto che alcune lingue abbiano ancora una caratteristica non significa che sia facile da usare, paradigmatico e ben integrato con il resto della lingua.

Common Lisp ha questo mix:

  • espressioni s come sintassi dei dati
  • il codice come dati porta a macro e altre tecniche di calcolo simbolico
  • linguaggio dinamico consente modifiche di runtime (late binding, MOP, ...)
  • fortemente tipizzato, tipizzato dinamicamente
  • uso interattivo con compilatore o interprete incrementale
  • Valutatore come motore di esecuzione principale
  • memoria gestita con Garbage Collection
  • Linguaggio ibrido con un uso intenso di programmazione imperativa, funzionale e orientata agli oggetti. Altri paradigmi possono essere aggiunti (regole, logica, vincoli, ...).

Ora anche altre lingue, come C #, hanno questo. Ma spesso non con la stessa enfasi.

C # ha

  • Sintassi simile a C.
  • per lo più imperativo orientato agli oggetti, con alcune funzionalità FP
  • digitato staticamente
  • uso principalmente batch con un compilatore batch
  • memoria gestita con Garbage Collection

Non aiuta che C # abbia, ad esempio, funzionalità di manipolazione del codice, se non sono ampiamente utilizzate come in Lisp. In Lisp non troverai molti software che non fanno un uso pesante delle macro in tutti i modi semplici e complessi. L'uso della manipolazione del codice è davvero una grande caratteristica di Lisp. Emulare alcuni usi è possibile in molte lingue, ma non lo rende una caratteristica centrale come in Lisp. Vedi libri come 'On Lisp' o 'Practical Common Lisp' per esempi.

Lo stesso per lo sviluppo interattivo. Se si sviluppa un sistema CAD di grandi dimensioni, la maggior parte dello sviluppo sarà interattiva dall'editor e dal REPL, direttamente nell'applicazione CAD in esecuzione. Puoi emularne gran parte in C # o in altre lingue, spesso implementando un linguaggio di estensione. Per Lisp sarebbe stupido riavviare l'applicazione CAD in fase di sviluppo per aggiungere modifiche. Il sistema CAD conterrebbe quindi anche un Lisp migliorato che avrebbe aggiunto funzionalità linguistiche (sotto forma di macro e descrizioni simboliche) per descrivere gli oggetti CAD e le loro relazioni (parte di, contenuti, ...). In C # si possono fare cose simili, ma in Lisp questo è lo stile di sviluppo predefinito.

Se sviluppi un software complesso usando un processo di sviluppo interattivo o il tuo software ha una parte simbolica sostanziale (meta-programmazione, altri paradigmi, algebra del computer, composizione musicale, pianificazione, ...), allora Lisp potrebbe fare al caso tuo.

Se lavori in ambiente Windows (io no), C # ha un vantaggio, poiché è un linguaggio di sviluppo principale di Microsoft. Microsoft non supporta alcun modulo Lisp.

Scrivi:

  • Namespace. Anche con metodi statici, mi piace legarli a una "classe" per categorizzare il loro contesto (Clojure sembra avere questo, CL non sembra.)

Lisp comune non associa spazi dei nomi alle classi. Gli spazi dei nomi sono forniti da pacchetti di simboli e sono indipendenti dalle classi. È necessario riorientare il proprio approccio alla programmazione orientata agli oggetti se si utilizza CLOS.

  • Grande supporto in fase di compilazione e di progettazione, il sistema dei tipi mi permette di determinare la "correttezza" delle strutture di dati che passo attorno a qualsiasi errore di ortografia sia sottolineato in tempo reale; Non devo aspettare che il runtime conosca i miglioramenti del codice (come l'uso di un approccio FP invece di uno imperativo) con autosuggestione

Usa il compilatore Lisp. Ti informa su variabili sconosciute, potrebbe avere consigli di stile (a seconda del compilatore utilizzato), fornisce suggerimenti di efficienza, ... Il compilatore è a portata di tasto.

  • Strumenti di sviluppo della GUI: WinForms e WPF (so che Clojure ha accesso alle librerie della GUI Java, ma sono del tutto estranee a me).

I Lisps commerciali come LispWorks e Allegro CL offrono cose simili su Windows.

  • Strumenti di debug della GUI: breakpoint, step-in, step-over, ispettori di valore (testo, xml, personalizzati), orologi, debug-by-thread, breakpoint condizionali, finestra di stack di chiamate con la possibilità di saltare al codice a qualsiasi livello nello stack (Per essere onesti, il mio periodo con Emacs + Slime sembrava fornire un po 'di questo, ma sono parziale all'approccio guidato dalla GUI VS)

I Lisps commerciali come LispWorks e Allegro CL offrono tutto ciò sotto Windows.


1
La mia critica non è proprio di Lisps. Li trovo abbastanza capaci. Sto cercando cosa può fare / darmi un Lisp che non ho già fatto. Comprendo appieno che la maggior parte degli sviluppatori C # non utilizza molte delle "nuove" funzionalità del linguaggio. Penso che il punto più grande sia che lo faccio e, onestamente, al di fuori della GUI, scrivo quasi in uno stile FP al 100%. FP è stato un salto concettuale, ma ne vale la pena. Tuttavia, il passaggio a un Lisp da dove mi trovo sembra fornire pochi benefici. Spero di scoprire che c'è un motivo per cui dovrei continuare a dargli una possibilità.

@Jonathan Mitchem: C # non sembra davvero un linguaggio FP, anche se il linguaggio ha alcune funzionalità che lo supportano e alcune librerie potrebbero usarle. Se vuoi fare la programmazione FP nell'ecosistema Microsoft, allora F # potrebbe fare al caso tuo.

@Rainer No, non sembra un linguaggio FP, ma può farlo, e abbastanza compatto. E quando voglio / ho bisogno di un codice imperativo, o OO, posso farlo anch'io. (leggermente fuori tema: non considero davvero F # un linguaggio serio nel quale valga la pena approfondire, preferirei concentrarmi sulle monadi di Haskell. Ma quando ero un sviluppatore C ++ e C # uscì, non lo considerai una lingua "reale" o [e allora non lo era, imho])


@Jonathan Mitchem: perché dovrei guardare? Ho scritto che C # supporta alcune funzionalità FP. Si è appena aggiunto a un linguaggio imperativo orientato agli oggetti e non lo rende idiomatico, come ad esempio Lisp, Scheme e soprattutto non rispetto a SML, F #, Haskell o altri linguaggi principalmente funzionali. Il mio punto è: alcuni FP sono possibili in C #, ma non è una caratteristica fondamentale.

5

Rainier Joswig l'ha detto il migliore.

Per me, il potere di Lisp non può essere compreso semplicemente guardando un elenco di funzionalità di Lisp. Per Lisp, e Common Lisp in particolare, il tutto è maggiore della somma delle parti. Non si tratta solo di REPL plus s-espressioni, macro, spedizione multi-metodo, chiusure, pacchetti, CLOS, riavvii, X, Y e Z. L'intera shebang è ingegnosamente integrata. È l'esperienza quotidiana molto diversa dall'esperienza quotidiana di altri linguaggi di programmazione.

Lisp ha un aspetto diverso, viene utilizzato in modo diverso, ci si avvicina alla programmazione in modo diverso quando lo si utilizza. È elegante, completo, grande e senza soluzione di continuità. Non è privo di imperfezioni e peccadilli. Vi sono certamente confronti con altre lingue che potrebbero essere fatti laddove non potrebbe venire fuori. Ma in nessun modo Lisp è solo linguaggio X più REPL e macro, o linguaggio Y più invio e riavvio multi-metodo.


3
Il codice è dati (e macro) - Forse non ho "ottenuto" le macro, ma non ho visto un singolo esempio in cui l'idea di una macro non potesse essere implementata come funzione; non cambia la "lingua", ma non sono sicuro che sia un punto di forza

In genere, una macro dovrebbe essere utilizzata per qualcosa che non è espressibile come chiamata di funzione. Non so se esiste una condizione simile a switch in C # (simile a ciò che esiste in C, come switch (modulo) {case ...}), ma supponiamo che lo faccia e abbia quasi le stesse restrizioni ( richiede un tipo integrale).

Ora, supponiamo ulteriormente che ti piacerebbe qualcosa che assomigli a quello, ma invii sulle stringhe. In lisp (bene, in particolare in Common Lisp e probabilmente in altri), questo è "solo" una macro di distanza e se si limita l'utente ad avere stringhe costanti (probabilmente non ardue) con cui confrontarsi, è possibile (compilare-tempo) calcolare una sequenza minima di test per determinare quale caso corrisponde (o usare una tabella hash, archiviando chiusure, forse).

Mentre può essere possibile esprimerlo come una funzione (stringa di confronto, un elenco di casi e chiusure da eseguire), probabilmente non sembrerebbe "codice normale" ed è qui che le macro lisp hanno una vincita definita. Probabilmente avete usato un paio di macro bel o forme speciali taht sono macro-come, come defun, defmacro, setf, cond, loope molti altri.


2

Questo è il miglior articolo esplicativo che ho trovato che prende il lettore dalla superficie della difesa di Lisp per mostrare alcune delle implicazioni più profonde dei concetti usati:

http://www.defmacro.org/ramblings/lisp.html

Ricordo di aver letto altrove un'idea come questa: altre lingue hanno adottato varie caratteristiche di Lisp; garbage collection, digitazione dinamica, funzioni anonime, chiusure per produrre un C ++ / C / Algol migliore. Tuttavia, per ottenere il pieno potere di Lisp hai bisogno di tutte le sue caratteristiche essenziali, a quel punto hai un altro dialetto di Lisp, una famiglia distinta di lingue che esiste da una parte o dall'altra da oltre 50 anni.

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.