it-swarm-eu.dev

Schéma vs Common LISP: Které vlastnosti změnily váš projekt?

Na StackOverflow i na tomto webu není dostatek nejasných otázek „Scheme vs Common LISP“, takže chci, aby byl tento více zaměřen. Otázka je pro lidi, kteří kódovali v obou jazycích:

Které konkrétní prvky vašeho společného zážitku s kódováním LISP vám při programování v systému nejvíce chyběly? Nebo naopak, co jste při programování v Common LISP vynechal z kódování ve schématu?

Nemyslím nutně jen jazykové funkce. Co se týče otázky, jsou všechny platné věci, které si musíte nechat ujít:

  • Specifické knihovny.
  • Specifické rysy vývojových prostředí, jako je SLIME, DrRacket atd.
  • Funkce konkrétních implementací, jako je schopnost Gambitu psát bloky C kódu přímo do vašeho zdroje schématu.
  • A samozřejmě jazykové funkce.

Příklady odpovědí, na které doufám:

  • "Snažil jsem se implementovat X do Common LISP, a kdybych měl prvotřídní pokračování Scheme, úplně bych udělal jen Y, ale místo toho jsem musel udělat Z, což byla spíše bolest."
  • „Skriptování procesu sestavování v mém projektu Scheme se stalo čím dál bolestivějším, protože můj zdrojový strom rostl a já jsem se propojil ve stále více knihovnách C. Pro svůj další projekt jsem se vrátil zpět do Common LISP.“
  • "Mám velkou existující C++ kódovou základnu a pro mě, být schopen vkládat volání C++ přímo do mého kódu Gambit Scheme, rozhodně stálo za jakékoli nedostatky, které může mít schéma oproti běžnému LISP, dokonce i bez podpory SWIG."

Takže doufám v válečné příběhy, spíše než v obecných náladách, jako je „Schéma je jednodušší jazyk“ atd.

159
SuperElectric

Mým nedokončeným titulem byl kognitivní věda a umělá inteligence. Z toho jsem měl jednosměrný úvod do LISP. Myslel jsem, že jazyk je zajímavý (jako v "elegantním"), ale moc jsem si o něm nemyslel, dokud jsem se nesetkal s Greenspunovým desátým pravidlem mnohem později:

Jakýkoli dostatečně komplikovaný program C nebo Fortran obsahuje ad hoc, neformálně specifikovanou, bug-ridden, pomalou implementaci poloviny Common LISP.

Greenspun poukázal na (částečně), že mnoho složitých programů má vestavěné tlumočníky. Namísto zabudování tlumočníka do jazyka navrhl, že by mohlo mít větší smysl použít jazyk jako LISP, který již má vestavěný tlumočník (nebo kompilátor).

V té době jsem pracoval na poměrně velké aplikaci, která prováděla uživatelsky definované výpočty pomocí vlastního tlumočníka pro vlastní jazyk. Rozhodl jsem se zkusit přepsat jeho jádro v LISP jako experiment ve velkém měřítku.

Trvalo to zhruba šest týdnů. Původní kód byl ~ 100 000 řádků Delphi (varianta Pascal). V LISP to bylo sníženo na ~ 10 000 řádků. Ještě překvapivější však byla skutečnost, že motor LISP byl 3-6krát rychlejší. A mějte na paměti, že se jednalo o dílo novy LISP! Celá ta zkušenost byla pro mě docela okouzlující; poprvé jsem viděl možnost kombinovat výkon a expresivitu v jednom jazyce.

O něco později, když jsem začal pracovat na webovém projektu, jsem vyzkoušel několik jazyků. Do mixu jsem zahrnul LISP a Scheme. Nakonec jsem vybral implementaci schématu -- Chez Scheme . S výsledky jsem byl velmi spokojený.

Webový projekt je vysoce výkonný "výběrový motor" . Schéma používáme mnoha různými způsoby, od zpracování dat po dotazování dat po generování stránky. Na mnoha místech jsme vlastně začali s jiným jazykem, ale nakonec jsme se přestěhovali do programu z důvodů, které stručně popíšu níže.

Teď mohu odpovědět na vaši otázku (alespoň částečně).

Během konkurzu jsme se podívali na různé implementace LISP a Scheme. Na straně LISP jsme se podívali (věřím) na Allegro CL, CMUCL, SBCL a LispWorks. Na straně schématu jsme se podívali (věřím) na Bigloo, kuře, Chez, Gambit. (Výběr jazyka byl již dávno; proto jsem trochu mlhavý. Pokud je to důležité, můžu si nahrát nějaké poznámky.)

Hned po netopýři jsme hledali a) nativní vlákna ab) Linux, Mac a Windows. Tyto dvě podmínky společně zaklepaly všechny, ale (myslím) Allegro a Chez ven - takže abychom mohli pokračovat v hodnocení, museli jsme uvolnit požadavek na více vláken.

Sestavili jsme sadu malých programů a použili je pro vyhodnocení a testování. To odhalilo řadu problémů. Například: některé implementace měly závady, které zabránily spuštění některých testů; některé implementace nemohly kompilovat kód za běhu; některé implementace nemohly snadno integrovat run-time kompilovaný kód s předkompilovaným kódem; některé implementace měly sběratele odpadu, které byly jasně lepší (nebo jasně horší) než ostatní “; atd.

Pro naše potřeby byly provedeny pouze tři komerční implementace - Allegro, Chez a Lispworks. Ze tří pouze Chez prošel všemi testy s létajícími barvami. V té době si myslím, že Lispworks neměla nativní vlákna na žádné platformě (myslím, že ano) a myslím, že Allegro měla nativní vlákna na některých platformách. Kromě toho měl Allegro licenční poplatek za volání „zavolejte nám“, který se mi moc nelíbil. Věřím, že Lispworks neměl žádný poplatek za běh a Chez měl přímou (a velmi rozumnou) úpravu (a to se to jen rozběhlo, pokud jste kompilátor použili v době běhu).

Po vyrobení poněkud významných kusů kódu v LISP i ve schématu zde jsou některé srovnávací a kontrastní body:

  • Prostředí LISP jsou mnohem vyspělejší. Získáte mnohem víc třesku za babku. (Po tom, co řekl, více kódu také znamená více chyb.)

  • Prostředí LISP je mnohem obtížnější se naučit. K tomu, abyste se stali zdatnými, potřebujete mnohem více času; Společný LISP je obrovský jazyk - a to je ještě předtím, než se dostanete do knihoven, které komerční implementace přidávají. (Jak už bylo řečeno, případ syntaxe Scheme je mnohem jemnější a komplikovanější než kterákoli jiná věc v LISP.)

  • Prostředí LISP může být o něco obtížnější vyrobit binární soubory. Musíte odstranit obrázek, abyste odstranili nepotřebné bity, a pokud během tohoto procesu nevykonáváte program správně, můžete později skončit s chybami run-time. . Naproti tomu s Chez sestavujeme soubor nejvyšší úrovně, který obsahuje všechny ostatní soubory, které potřebuje, a jsme hotovi.

Už jsem řekl, že jsme nakonec použili program Scheme na mnoha místech, na které jsme původně neměli v úmyslu. Proč? Mohu myslet na tři důvody mimo temeno hlavy.

Nejprve jsme se naučili důvěřovat Chezovi (a jeho vývojáři, Cadence). Zeptali jsme se hodně z nástroje, a to důsledně dodávány. Například, Chez historicky měl triviálne malý počet defektů a jeho správce paměti byl velmi, velmi dobrý.

Za druhé, naučili jsme se milovat výkon, který jsme dostali od Cheza. Používali jsme něco, co se cítilo jako skriptovací jazyk - a dostávali jsme z toho rychlost nativního kódu. Pro některé věci, na kterých nezáleželo - ale nikdy to neublížilo, a někdy to pomohlo strašlivému množství.

Zatřetí jsme se naučili milovat abstrakční schéma, které může poskytnout. Mimochodem nemyslím jen makra; Mám na mysli věci jako uzávěry, lambdy, chvostová volání atd. Jakmile začnete uvažovat v těchto termínech, zdá se, že srovnání jiných jazyků se zdá být omezené.

Je schéma perfektní? Ne; je to kompromis. Zaprvé, umožňuje individuálním vývojářům, aby byli efektivnější - ale pro vývojáře je obtížnější si navzájem propíchnout kód, protože ve schématu chybí ukazatele, které má většina jazyků (např. Pro smyčky) (např. Existuje milion způsobů, jak to udělat) pro smyčku). Zadruhé, existuje mnohem menší skupina vývojářů, se kterými si můžete promluvit, najmout, půjčit si atd.

Abych to shrnul, myslím, že bych řekl: LISP a schéma nabízejí některé funkce, které nejsou nikde jinde široce dostupné. Tato schopnost je kompromisem, takže měla být lepší ve vašem konkrétním případě. V našem případě určující faktory mezi tím, zda jít s LISP nebo schématem, měly více společného s velmi základními funkcemi (podpora platformy, podprocesy platformy, kompilace za běhu, licencování za běhu), než tomu bylo u jazykových nebo knihovních funkcí. I v našem případě to byl kompromis: s Chezem jsme dostali základní funkce, které jsme chtěli, ale ztratili jsme rozsáhlé knihovny, které komerční prostředí LISP mělo.

Také jen zopakuji: už dávno jsme se podívali na různé lispsy a schémata; od té doby se všichni vyvinuli a vylepšili.

102
Michael Lenaghan

Obvykle se mi nelíbí vložení odkazu jako odpovědi, ale o této věci jsem napsal blogový článek. Není to vyčerpávající, ale získává některé z hlavních bodů.

http://symbo1ics.com/blog/?p=729

Upravit : Zde jsou základní body:

  1. [~ # ~] existence [~ # ~] : Obě klapky přišly po spoustě dalších klapek. Schéma zvolilo minimální axiomatickou cestu. CL se vydal barokní cestou.
  2. [~ # ~] případ [~ # ~] : Typicky se ve schématu rozlišují velká a malá písmena. CL není (i když to může být). To se někdy přehlíží, ale o jeho praktičnosti se diskutuje (já).
  3. [~ # ~] jména [~ # ~] : Názvy symbolů v CL jsou mnohokrát liché a matoucí. TERPRI, PROGN atd. Schéma má obvykle velmi rozumná jména. To je něco, co v CL chybí.
  4. [~ # ~] funkce [~ # ~] : CL má samostatný obor názvů funkcí. Ve schématu to není vynecháno. Mít jediný jmenný prostor obvykle umožňuje velmi čisté funkční programování, což je v CL často obtížné nebo nepříjemné. Ale přichází to za cenu --- občas musíte zmatit jména jako „list“ na „lst“ ve schématu.
  5. [~ # ~] makra [~ # ~] : Chybí mi špinavá makra nízké úrovně nejvíce ve schématu. To jo, syntax-rules je v pořádku a dandy, dokud si nepřejete, aby se nějaké věci opravdu rozbily. Na druhé straně jsou v CL někdy vynechána hygienická makra. Nemít standardní způsob, jak to udělat, znamená znovu vynalézat kolo.
  6. [~ # ~] přenositelnost [~ # ~] : Často se stává, že CL je přenosnější, přestože jsou oba jazyky standardizovány. CL je větší, a proto existuje více standardních funkcí, které lze použít bez externích knihoven. To také znamená, že více přenosů závisí na implementaci. Schéma také trpí bilionovými implementacemi, z nichž většina je poněkud nekompatibilní. Díky tomu je CL velmi žádoucí.
  7. [~ # ~] knihovny [~ # ~] : Velmi souvisí s mým posledním bodem. Schéma má SRFI, ale nejsou všeobecně uznávány. Neexistuje žádný přenosný způsob práce s knihovnami. CL na druhé straně má způsoby. A Quicklisp je dar od Boha (Xach) --- jakési úložiště knihoven pro použití.
  8. [~ # ~] implementace [~ # ~] : Schéma trpí tolika implementacemi. Neexistuje žádná skutečná kanonická implementace. Na druhé straně CL má některé velmi pěkné implementace s vysokým výkonem nebo se specifickým využitím (vysoký výkon: SBCL, komerční: Allegro, embedded: ECL, přenosný: CLISP, Java: ABCL, ...).

Zatímco jsem mluvil pouze v první osobě o něco výše, mělo by být jasné, co mi chybí a co ne.

[Omlouvám se, jsou-li příliš obecné. Zdá se, že budete chtít mnohem konkrétnější podrobnosti. V příspěvku jsou některá specifika.]

37
Quadrescence

Nedávno jsem zahájil domácí projekt pomocí knihovny, která má verzi C a verzi Java=.) Chtěl jsem pro tento projekt použít LISP, a strávil jsem asi měsíc očkováním mezi používáním Common LISP, Scheme nebo Clojure. Mám nějaké zkušenosti se všemi třemi, ale pouze s projekty hraček. Povím vám něco o své zkušenosti s každým z nich, než řeknu, který z nich jsem nakonec vybral.

PLT Racket má Nice IDE), které nejen umožňuje vyhodnocovat výrazy z editoru, ale také umožňuje psát závorky namísto paren, případně je přepínat zpět na parens. Racket má také velkou sadu knihoven s instalací a ještě více dostupných ke stažení. Vizuální debugger je také užitečný.

Moje běžná implementace LISP (SBCL) nemá IDE, ale u implementací CL s otevřeným zdrojovým kódem je obvyklé používat Emacs a SLIME. Tato kombinace může být velmi efektivní. Kromě schopnosti vyhodnocovat výrazy při jejich zadávání do zdrojového souboru je k dispozici také REPL), který obsahuje všechny příkazy pro úpravy emaců, takže kopírování kódu může jít efektivně oběma způsoby. objekty zobrazené ve vyrovnávací paměti REPL buffer lze kopírovat a vložit. Alt+( a Alt+) jsou efektivní pro řešení uzavřených závorek a odsazení.

Všechny výše uvedené funkce Emacsu jsou k dispozici také pro Clojure. Moje editační zkušenost s Clojure je podobná jako u LISP. Interop Java Java fungoval dobře a jakmile zraje, rád bych udělal projekt Clojure).

Do knihovny jsem měl přístup pomocí všech tří (Common LISP, Racket a Clojure), ale nakonec jsem pro projekt vybral Common LISP. Rozhodujícím faktorem bylo, že použití FFI bylo mnohem jednodušší v Common LISP. CFFI má velmi dobrou příručku s ukázkovým kódem a podrobným vysvětlením každé metody. Odpoledne jsem dokázal zabalit 20 C funkcí a od té doby jsem se nemusel dotýkat kódu.

Dalším faktorem bylo, že jsem více obeznámen s Common LISP než s Clojure nebo R6RS Scheme. Četl jsem většinu praktických běžných knih LISP a Grahama a jsem s Hyperspecem spokojený. Ještě to není příliš „lispy“ kód, ale jsem si jist, že se to změní, když získám více zkušeností.

25
Larry Coleman

Programuji jak v CL, tak v Raketě.

Nyní vyvíjím webovou stránku v Common LISP a napsal jsem sadu vlastních programů pro mého předchozího zaměstnavatele v Racket.

Pro interní kód jsem si vybral Racket (tehdy známý jako PLT Scheme), protože zaměstnavatel byl Windows shop a nemohl jsem je přimět, aby zaplatili za LispWorks. Jedinou dobro open-source implementací CL pro Windows bylo (a stále je) CCL, které vyžaduje SSE podpora v procesoru. Zaměstnavatel, který byl levný, používal Hardware v době kamenné. I když zaměstnavatel měl slušný hardware, jedinou knihovnou GUI, která má důsledek v Common LISP, je McCLIM, který funguje pouze na Unixu. úspěch projektu.

Strávil jsem přes rok vychováním s primitivním editorem DrRacket. EMACS nemohl proměnit GUI verzi Racket, tehdy známou jako MrEd, v podřadný LISP na Windows. Musel jsem to udělat, aniž bych byl schopen vyhodnotit výraz u kurzoru jediným stiskem klávesy. Namísto toho jsem musel ručně vybrat S-výraz, zkopírovat ho, kliknout na okno REPL (protože neexistuje žádný stisk klávesy), a pak vložit S-výraz. musel dělat bez editoru, který by mi ukázal očekávané argumenty funkce nebo makra, které jsem používal. DrRacket nenahrazuje SLIME.

Zaměstnavatel používal proprietární databázi s komplikovaným rozhraním XML API, které vyžadovalo spoustu zdánlivě nepotřebných informací, aby bylo možné odpovědět na jeho verzi dotazu SELECT. Rozhodl jsem se použít HTMLPrag jak k vysílání XML do tohoto API, tak k analýze odpovědí. Fungovalo to skvěle.

Musel jsem se naučit Racketův nadměrně komplikovaný "syntaktický" makro systém, abych mohl napsat makro, které mi umožní interakci s příliš komplikovaným XML API zadáním formulářů, které vypadají jako SQL. Tato část by byla mnohem jednodušší, kdybych měl DEFMACRO k dispozici. Konečný výsledek však byl stále plynulý, i když to vyžadovalo více úsilí.

Kromě toho jsem se musel obejít bez běžného makra LOOP LISP. Racket začal nabízet alternativu až poté, co jsem napsal většinu kódu, a alternativa stále saje ve srovnání s LOOP (i když vývojový tým Racket trvá na tom, že je to lepší - prostě se mýlí). Nakonec jsem psal spoustu pojmenovaných LET formulářů, které používaly "auto" a "cdr" pro iteraci seznamů.

Když už mluvíme o autě a cdr, nic není frustrujícíjší než Schemeho interpretace (car '()) jako chyby. Využil jsem Racketovy případové citlivosti a implementoval CAR a CDR, které mají sémantiku Common LISP. Oddělováním '() a #f je však mnohem méně užitečné vrátit' () jako výchozí hodnotu.

Také jsem skončil re-implementace UNWIND-PROTECT a vynalezl jsem svůj vlastní restartovací systém, aby vyplnil mezeru, kterou zbývá Racket. Komunita raket se musí naučit, že restartování je velmi užitečné a snadno implementovatelné.

Formulář let-value rakety byl příliš podrobný, takže jsem implementoval MULTIPLE-VALUE-BIND. To bylo naprosto nezbytné, protože raketa vyžaduje vy obdržíte všechny generované hodnoty, ať už je používáte nebo ne.

Později jsem se pokusil napsat eBay XML API klienta do Common LISP, jen abych zjistil, že nemá nic jako HTMLPrag. HTMLPrag je užitečný. Nakonec jsem ten projekt dělal v Racketu. Experimentoval jsem s Racketovými gramotnými programovacími zařízeními, jen abych zjistil, že jsem jediný programátor na Zemi, který shledává, že správně napsaný gramotný kód je těžší upravovat než obyčejný kód, nebo nesprávně napsaný gramotný kód „nadměrných komentářů“.

Můj nový projekt se provádí v rámci společného LISP, což byla správná volba, protože komunita raket prostě nevěří v paralelismus, což je pro tento projekt zásadní. Jediná věc, o které jsem si myslel, že jsem z Racketa mohl uniknout, byla pokračování. Pomocí restartu jsem však dokázal udělat to, co jsem potřeboval, a zpětně jsem to asi mohl udělat s jednoduchým zavřením.

21
Racketeer

Schéma je navržena s ohledem na samostatnou kompilaci. V důsledku toho je moc jeho maker často přísně omezena, a to i s rozšířeními, která umožňují defmacro stylu LISP namísto špatného, ​​omezujícího hygienického makro systému. Není vždy možné definovat makro, které definuje další makro, určené k okamžitému použití v dalším řádku kódu. A taková možnost je nezbytná pro implementaci efektivních kompilátorů eDSL.

Netřeba připomínat, že implementace schématu pouze s hygienickými makry R5RS jsou pro mě stěží užitečná, protože můj metaprogramovací styl nelze přiměřeně převést na hygienu.

Naštěstí existují implementace systému (např. Racket), které toto omezení nemají.

5
SK-logic