C # Dev - я спробував Lisps, але я не розумію [закрито]


37

Після кількох місяців навчання та гри з Ліспом, як з CL, так і з Clojure, я все ще не бачу вагомих причин писати що-небудь замість C #.

Мені дуже хотілося б переконливих причин або для того, щоб хтось зазначив, що я пропускаю щось дійсно велике .

Сильні сторони Lisp (за моїм дослідженням):

  • Компактна, виразна нотація - Більше, ніж C #, так ... але, здається, я можу висловити ці ідеї і в C #.
  • Неявна підтримка функціонального програмування - C # з методами розширення LINQ:
    • mapcar = .Вибір (лямбда)
    • mapcan = .Select (лямбда) .Aggregate ((a, b) => a.Union (b))
    • машина / перший =. Перший ()
    • cdr / rest = .Skip (1) .... і т.д.
  • Підтримка функції лямбда та вищого порядку - у C # це є, а синтаксис, можливо, простіший:
    • "(лямбда (х) (тіло))" проти "х => (тіло)"
    • "# (" з "%", "% 1", "% 2" приємно в Clojure
  • Відправлення методу відокремлено від об'єктів - C # має це за допомогою методів розширення
  • Мультиметод-диспетчер - C # не має цього в основному, але я міг би реалізувати це як виклик функції за кілька годин
  • Код - це дані (і макроси) - можливо, я не "дістав" макросів, але я не бачив жодного прикладу, де ідея макросу не могла бути реалізована як функція; це не змінює "мову", але я не впевнений, що це сила
  • DSL - це можна зробити лише за допомогою функції функцій ... але це працює
  • Нетипізоване "дослідницьке" програмування - для структур / класів, автоматичні властивості C # та "об'єкт" працюють досить добре, і ви можете легко перерости в сильніший текст, коли ви йдете разом
  • Працює на апаратному забезпеченні, яке не є Windows - Так, так? Поза межами коледжу я знав лише одну людину, яка не працює вдома Windows або хоча б VM Windows на * nix / Mac. (Знову ж таки, можливо, це важливіше, ніж я думав, і мені щойно промили мозок ...)
  • REPL для дизайну знизу вгору - Гаразд, я визнаю, це дійсно дуже добре, і мені це не вистачає в C #.

Те, чого мені не вистачає в Lisp (завдяки суміші C #, .NET, Visual Studio, Resharper):

  • Простори імен. Навіть зі статичними методами я люблю прив'язувати їх до "класу", щоб класифікувати їх контекст (Clojure, здається, має це, CL не здається.)
  • Прекрасна підтримка компіляції та дизайну
    • система типів дозволяє мені визначати "правильність" структур даних, які я передаю
    • в режимі реального часу підкреслюється що-небудь неправильно написане; Мені не потрібно чекати часу виконання, щоб знати
    • удосконалення коду (наприклад, використання підходу FP замість імперативного) автоматично запропоновано
  • Інструменти розробки графічного інтерфейсу: WinForms та WPF (я знаю, що Clojure має доступ до бібліотек Java GUI Java, але вони мені повністю чужі.)
  • Інструменти для налагодження графічного інтерфейсу: точки прориву, вхід, перехід, інспектори значень (текст, xml, користувальницький), годинник, налагодження за допомогою потоку, умовні точки перерви, вікно стека виклику з можливістю переходити до коду на будь-якому рівні в стопку
    • (Справедливо кажучи, моє враження щодо Emacs + Slime, здавалося, щось із цього забезпечує, але я частково ставлюся до підходу VS GUI)

Мені дуже подобається ажіотаж навколо Lisp, і я дав йому шанс.

Але чи можу я зробити в Ліспі щось, що я не можу зробити так добре в C #? Це може бути трохи докладніше в C #, але у мене також є автозаповнення.

Що я пропускаю? Чому я повинен використовувати Clojure / CL?


4
Оскільки ви вже програмуєте у функціональному стилі, і це здається, що ви досить сильно покладаєтесь на інфраструктуру Windows, я не бачу жодної вагомої причини перейти від C #. Більшість усіх, кого я знаю, використовують Mac чи Linux, тому багато чого очевидно залежить від натовпу, з яким ви працюєте (я використовував кожну версію Windows з 3.1, але я все ще віддаю перевагу роботі з кросплатформенним програмним забезпеченням та * nix системами взагалі ... але тоді я не займаюся жодною роботою з графічним інтерфейсом, усі сервери та веб-інтерфейси)
Sean Corfield,

2
Ви могли поглянути на Свиня перед Перлом . Слухати цікаву розмову та подає простий приклад того, які макроси хороші.
Маттіас Бенкард

4
"Я не бачив жодного прикладу, де ідея макросу не могла бути реалізована як функція" - я хотів би бачити, як ви пишете ANDчи ORяк функцію. Це можна зробити (дано LAMBDA, що також є макросом), але я не бачу очевидного способу зробити це, який би не був повністю смоктати.

1
"Простори імен. ... Здається, у Clojure це є, CL не здається" - ви можете бути більш конкретними щодо того, що ви шукаєте? Я не дуже використовував Clojure, але його простори імен виглядають так само, як і пакунки CL.

4
Джонатан: CL використовує :(або ::неекспортовані символи) для іменування символів у пакунках, наприклад, ваш приклад тут використовує http:sessionі chat:session.

Відповіді:


23

Макроси дозволяють писати компілятори, не залишаючи комфорту вашої мови. DSL-мови на таких мовах, як C #, як правило, складають інтерпретатор виконання. Залежно від вашого домену, це може бути проблематичним з міркувань продуктивності. Швидкість має значення , інакше ви будете кодувати інтерпретованою мовою, а не C #.

Також макроси також дозволяють вам враховувати людські фактори - що є найбільш зручним для користувачів синтаксисом для конкретного DSL? Що стосується синтаксису, ти не можеш багато чого зробити.

Тож Lisp дозволяє брати участь у мовному дизайні, не жертвуючи шляху до ефективності . І хоча ці питання можуть не мати для вас значення , вони є надзвичайно важливими, оскільки лежать в основі всіх корисних мов програмування, орієнтованих на виробництво. У C # цей основоположний елемент піддається вам у кращому випадку у дуже обмеженій формі.

Важливість макросів не втрачається в інших мовах - на думку приходить шаблон Haskell, camlp4. Але знову ж таки, це питання зручності використання - макроси Lisp на сьогоднішній день - це, мабуть, найбільш зручна для користувача, але потужна реалізація перетворень за час компіляції.

Отже, підсумовуючи те, що люди, як правило, роблять w / мови, як, наприклад, C #, - це побудувати DSIL (інтерпретовані мови, визначені для домену). Lisp надає вам можливість створити щось набагато більш радикальне, DSP (Paradigms Specific Paradigms). Ракетка (раніше PLT-схема) особливо надихає в цьому плані - вони мають ледачу мову (Lazy Racket), набрану (Typed Racket), Prolog та Datalog, вбудовану ідіоматично через макроси. Усі ці парадигми забезпечують потужне вирішення великих класів проблем - проблем, не найкращим чином вирішених імперативним програмуванням або навіть парадигмами ПП.


3
Що мені здається цікавим у цьому аргументі, це те, що я ніколи не стикався з можливістю (або просто не помічав її в невідомості) для впровадження DSL / DSIL. Не могли б Ви детальніше розглянути питання про потужність DSL? (І для розробника, і для користувача.) Це здається, що це може бути великою річчю, якої я дійсно відсутня.

15
@ Джонатан Мітхем, ви вже використовуєте безліч зовнішніх DSL - файли конфігурації, сценарії побудови, конфігурації ORM, генератори візуальних кодів (наприклад, редактор winforms), XAML, генератори парсеру тощо. Мені не потрібен окремий інструмент побудови для них, і вони подаються на одній мові. І ви повинні бути знайомі як мінімум з двома вбудованими DSL - регулярними виразами та SQL.
SK-логіка

Нічого, добре. Я просто ніколи не вважав таких, як DSL. Тепер я навмисно відхилився від багатьох цього, на основі "все, що я можу зробити з c #, я збираюся дотримуватися c # for". Мені подобається дотримуватися одного інструменту з послідовною поведінкою, особисто. Але я розумію цінність DSL в цих прикладах.

2
@ Джонатан Мітчем, проблема будь-якого інструменту полягає в тому, що це не обов'язково підходить для певної мети. Ви повинні вибрати різні інструменти для різних завдань. І сила будь-якої мета-мови, включаючи Lisp, полягає в тому, що вам не доведеться повністю переходити на інший інструмент, оскільки ви можете розробити власні інструменти, характерні для домену, поверх своєї основної мови. Я пропоную вам поглянути на Nemerle, це було б простіше зрозуміти це для розробника C #, і його макроси майже такі ж потужні, як і Lisp.
SK-логіка

3
"Мені подобається дотримуватися одного інструменту ..." Правильно складені DSL в Lisp ніколи не приховують всю потужність Lisp, тому у вас все ще є один інструмент. Вони просто додають до словника таким чином, що робить кодування для певного домену більш "природним", тобто з кращими абстракціями та загальною організацією.

15

Практично все, що спочатку було доступне лише в Ліпсі, вдячно перейшло на безліч інших сучасних мов. Найбільшим винятком є ​​філософія "код - дані" та макроси.

Код - це Дані (і макроси) - Можливо, я не "дістав" макросів, але я не бачив жодного прикладу, де ідея макросу не могла бути реалізована як функція

Так, макроси важко рихлити. Метапрограмування взагалі важко піддатися. Якщо ви бачили будь-який макрос, який можна було реалізувати як функцію, програміст робив це неправильно. Макроси слід використовувати лише тоді, коли функція не працюватиме.

Приклад "привіт світу" макросу - писати "якщо" з точки зору cond. Якщо вам дійсно цікаво дізнатись про силу макросів, спробуйте визначити "мій-якщо" в clojure, використовуючи функції та спостерігайте, як він ламається. Я не хочу бути таємничим, я просто ніколи не бачив, щоб хто-небудь починав розуміти макроси за допомогою пояснення поодинці, але це слайд-шоу є досить хорошим введенням: http://www.slideshare.net/pcalcado/lisp-macros-in -20-хвилин-показ-кложур-презентація

У мене були невеликі проекти, де я зберігав буквально сотні / тисячі рядків коду за допомогою макросів (порівняно з тим, що було б у Java). Значна частина Clojure реалізована в Clojure, що можливо лише завдяки макросистемі.


3
Не торкаючись жодного коду, я пробіг сценарій реалізації "якщо" без макросів у голові, як у Clojure, так і на C #. Це ефективно (або буквально) зробити це неможливо. Я визнаю, це акуратно. Але я пропускаю зв’язок того, як це мені корисно. Що я можу зробити з макросами (крім того, щоб написати "якщо"), які не можу зробити з розумним функціоналом або OO-дизайном? "Як це могло мені допомогти" не є дійсним критерієм для оцінки мови, але це для того, щоб оцінити, чи буду я її використовувати. (Я дуже хочу, щоб на Lisp варто було перейти, але це не вдалося досягти життєздатної альтернативи.)

1
Це займе у мене небагато часу, щоб сприймати цей приклад. Для мене "збереження кодового коду" зазвичай викликає термін "рефакторинг", який є частиною того, чому пояснення мене не переконали. У мене є рішення, яке працює у кожному випадку, я його застосував. Я думаю, що тоді питання полягає в тому, як визначити випадки, коли можна використовувати макрос?

1
Я погоджуюся, що макроси варті, але це неправда, що мій-якщо вимагає їх, він може бути записаний як функція вищого порядку (див. Приклад CL нижче). Макроси вам справді потрібні лише в тому випадку, якщо ви хочете перейти до коду або розмістити його в новому лексичному контексті. (defun my-if (test then &optional else) (cond (test (funcall then)) ('otherwise (funcall else))))

1
В основному з функцією у вас є вибір прийняти або цитований код, по якому ви можете ходити, але в ньому відсутній його лексичний контекст, оскільки ви ходите і виконуюте його в лексичному контексті вашої функції. Або ви можете приймати закриття, які зберігають їхній лексичний контекст, але ви можете лише телефонувати, а не ходити або додавати щось до їх лексичного контексту. Для цього вам потрібен макрос, який може ходити та загортати код до того, як його розширення буде розміщене у лексичному контексті макровиклику.

7
@Jonathan Mitchem, синтаксис LINQ - хороший приклад того, що можна зробити з макросами, але його потрібно було реалізувати в мовному ядрі, оскільки мова не підтримує жодної гідної метапрограмування.
SK-логіка

14

Я не є експертом у Common Lisp, але знаю і C #, і Clojure досить добре, тому, сподіваюся, це корисна перспектива.

  • Простий синтаксис => потужність - Lisps - це про найпростіший синтаксис, який міг би працювати. S-вирази - все, що вам потрібно. Після того, як ви "grokked" (function-call arg1 arg2 arg3) ", ви в основному це отримали. Решта - це лише вибір правильних викликів та аргументів функції. Здається, це майже тривіально просто, але факт полягає в тому, що ця простота - це те, що надає Ліпсу стільки сил і гнучкості, і, зокрема, дає можливість метапрограмування, якими славиться Лісп. наприклад, якщо я хочу, щоб макрос викликав кілька різних функцій на одних і тих же аргументах, я просто роблю щось на кшталт наступного (не це не лише програма виконання програми - це макрос, який генерує скомпільований код, як ніби ви виписали всі окремі виклики функції вручну):
(defmacro print-many [functions args]  
  `(do   
     ~@(map   
        (fn [function] `(println (~function ~@args)))   
        functions)))

(print-many [+ - * /] [10 7 2])  
19  
1  
140  
5/7
  • В результаті неймовірно простого синтаксису філософія Ліспа "Код - це дані" набагато потужніша за все, що ви можете зробити зі складом функцій / шаблонами / дженериками тощо. Це більше, ніж просто DSL, це генерування коду та маніпулювання під час компіляції , як фундаментальна особливість мови. Якщо ви спробуєте отримати такі можливості на мові, яка не гомонічна, на зразок C # або Java, врешті-решт, викрийте Lisp, погано. Звідси знамените десяте правило Грінспунса: "Будь-яка достатньо складна програма C або Fortran містить спеціальну, неофіційну інформацію, помилку, повільну реалізацію половини звичайного Lisp". Якщо ви коли-небудь опинялися, що винайшли загальнозміцнюючу мову шаблону / управління потоком у вашій програмі, ви, напевно, знаєте, що я маю на увазі .....

  • Паралельність - це унікальна сила Clojure (навіть відносно інших Lisps), але якщо ви вважаєте, що майбутнє програмування означатиме необхідність писати програми, які масштабуються на високоядерних машинах, то вам справді слід справді розібратися в цьому - це досить новаторський. Clojure STM (Software Transactional Memory) працює тому, що Clojure охоплює незмінні та безконтурні конструкції одночасності, засновані на новому розділенні ідентичності та стану (див. Чудове відео Річ Хікі про особистість та стан ). Було б дуже боляче переносити подібні можливості сумісності на середовище мови / часу виконання, де значна частина API працює над об'єктами, що змінюються.

  • Функціональне програмування - Ліпс підкреслює програмування з функціями вищого порядку. Ви маєте рацію в тому, що його можна імітувати в OO-об'єктах із закритими / функціональними об'єктами тощо, але різниця полягає в тому, що вся мова та стандартна бібліотека розроблені, щоб допомогти вам писати код таким чином. Наприклад, послідовності Clojure ліниві , тому можуть бути нескінченно довгими на відміну від ваших ArrayLists або HashMaps в C # / Java. Це робить деякі алгоритми набагато простішими у висловленні, наприклад, наступний реалізує нескінченний список номерів полів:

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

  • Динамічна типізація - Ліпси, як правило, знаходяться на «динамічному» кінці функціонального спектра мови програмування (на відміну від мов, таких як Haskell, з дуже сильною і красивою концепцією статичних типів). Це має як переваги, так і недоліки, але я стверджую, що динамічні мови, як правило, надають перевагу продуктивності програмування через більшу гнучкість. Цей динамічний набір тексту має незначну вартість виконання, але якщо це вас непокоїть, ви завжди можете додати підказки до типу, щоб отримати статичне введення тексту. В основному - ви отримуєте зручність за замовчуванням і продуктивність, якщо ви готові зробити трохи додаткової роботи, щоб отримати її.

  • Інтерактивний розвиток - насправді я думаю, що ви можете отримати якусь відповідь для C # 4.0, але в Lisp це стандартна практика, а не новинка. Вам взагалі не потрібно робити цикл компіляції / складання / тестування - ви пишете свій код безпосередньо у запущеному середовищі і лише пізніше копіюєте його у вихідні файли. Це вчить вас дуже різним способом кодування, де ви бачите результати одразу і вдосконалюєте рішення ітераційно.

Кілька швидких коментарів до речей, які ви вважаєте "відсутніми":

  • Як ви кажете, у Clojure є простори імен. Насправді це динамічні простори імен: ви можете оновити їх під час виконання - це дає деякі дивовижні переваги для інтерактивної розробки. Мені було весело переосмислювати функції під носом запущеної нитки або зламати живу структуру даних ....
  • Підтримка часу компіляції / проектування - не дуже актуальна, якщо ви кодуєте в системі REPL - ви просто зробите це і побачите результат безпосередньо. Сказавши це, Clojure починає отримувати покращену підтримку IDE, наприклад, плагін CounterClockwise для Eclipse .
  • Розробка графічного інтерфейсу - Так, вам доведеться вивчити новий API, але це завжди буде так, коли потрібно перемикати мови .... хороша новина полягає в тому, що Java API не такі вже й важкі, і зараз є цікаві Clojure- конкретні обгортки / приклади, які виглядають досить просто у використанні. Дивіться це питання щодо розробки графічного інтерфейсу Clojure, щоб побачити кілька прикладних прикладів
  • Налагодження GUI: це працює з налагодженням графічного інтерфейсу в Eclipse, якщо ви використовуєте CounterClockwise або Enclojure, якщо ви використовуєте Netbeans. Сказавши це, я не використовую цю можливість - я вважаю інтерактивне налагодження в REPL більш продуктивним.

Я особисто вважаю переваги Clojure / Lisp досить переконливими, і не збираюся повертатися до C # / Java (крім того, що мені потрібно позичити всім корисним бібліотекам!).

Тим не менш, мені знадобилося кілька місяців, щоб я все-таки обернув голову. Якщо ви по-справжньому зацікавлені в тому, щоб засвоїти Лісп / Клуджур як освіжаючий досвід навчання, заміни зануренням у нього та змушуючи себе реалізувати декілька речей ...


1
Дякую за велике перерахування ідей. Насправді я дуже часто використовую ліниві послідовності через конструкцію IEnumerable <> в C # (і не торкався ArrayList з 2005 року або більше), але я розумію цю ідею. Конкурсні примітиви Clojure надзвичайно вражають. Я кілька років тому робив сіткові обчислення в C # - паралельність на багатьох багатоядерних машинах - і все ще вважаю, що це майбутнє. Напевно, найбільша ідея, яку я здобув у всіх, - це "ти справді повинен просто копатись і переживати це, насправді це неможливо пояснити". Отже, я буду продовжувати копати і продовжувати переживати.

1
Класно, радий, що допомогли - і це абсолютно правильний дух !!
mikera

10

C # має багато функцій, але мікс відчуває себе інакше. Те, що деяка мова має особливість, ще не означає, що вона проста у використанні, парадигматична та добре інтегрована з рештою мови.

У звичайного Lisp є така суміш:

  • s-вирази як синтаксис даних
  • код як дані призводить до макросів та інших прийомів символічного обчислення
  • динамічна мова дозволяє змінювати час виконання (пізнє прив'язування, MOP, ...)
  • сильно набраний, динамічно набраний
  • інтерактивне використання з інкрементальним компілятором чи перекладачем
  • Оцінювач як двигун основних процесів
  • керована пам'ять за допомогою збирання сміття
  • Гібридна мова з важким використанням імперативного, функціонального та об’єктно-орієнтованого програмування. Можна додати й інші парадигми (правила, логіка, обмеження, ...).

Тепер інші мови, як-от C #, також мають це. Але часто не з однаковим акцентом.

C # має

  • С-подібний синтаксис
  • переважно імперативні об'єктно-орієнтовані, з деякими функціями ПП
  • статично набрані
  • здебільшого використовуйте пакетний компілятор
  • керована пам'ять за допомогою збирання сміття

Це не допомагає, що C # має, наприклад, функції маніпулювання кодом, якщо вони широко не використовуються, як у Lisp. В Lisp ви не знайдете багато програмного забезпечення, яке не використовує макросів у всіх видах простих і складних способів. Використання маніпуляції кодом - це справді велика особливість у Lisp. Емуляція деяких застосувань можлива у багатьох мовах, але це не робить її центральною особливістю, як у Lisp. Перегляньте приклади книг на кшталт "On Lisp" або "Practical Common Lisp".

Те саме для інтерактивного розвитку. Якщо ви розробляєте велику систему САПР, більша частина розробки буде інтерактивною з редактора, а REPL - безпосередньо в запущеному додатку CAD. Більшу частину цього можна імітувати на C # або інших мовах - часто застосовуючи мову розширення. Для Lisp було б нерозумно перезавантажувати додаток CAD, що розробляється, для додавання змін. Система CAD також міститиме розширений Lisp, який би додав мовні функції (у вигляді макросів та символічних описів) для опису об'єктів CAD та їх взаємозв'язків (частково, що містяться, ...). Можна робити подібні речі в C #, але в Lisp це стиль розробки за замовчуванням.

Якщо ви розробляєте складне програмне забезпечення за допомогою інтерактивного процесу розробки або у вашому програмному забезпеченні є значна символічна частина (метапрограмування, інші парадигми, комп’ютерна алгебра, композиція музики, планування, ...), то Lisp може бути для вас.

Якщо ви працюєте в середовищі Windows (я цього не роблю), C # має перевагу, оскільки це основна мова розробки Microsoft. Microsoft не підтримує жодної форми Lisp.

Ви пишете:

  • Простори імен. Навіть зі статичними методами я люблю прив'язувати їх до "класу", щоб класифікувати їх контекст (Clojure, здається, має це, CL не здається.)

Загальний Lisp не приєднує простори імен до класів. Простори імен надаються пакетами символів і не залежать від класів. Якщо ви використовуєте CLOS, вам потрібно переорієнтувати підхід до об'єктно-орієнтованого програмування.

  • Велика підтримка компіляції та проектування-часу система типів дозволяє мені визначити "правильність" структур даних, які я передаю навколо чогось неправильно написаного, підкресленого в реальному часі; Мені не потрібно чекати, поки час виконання, щоб знати покращення коду (наприклад, використання FP-підходу замість імперативного), автоматично запропоновано

Використовуйте компілятор Lisp. Він інформує вас про невідомі змінні, може мати рекомендації щодо стилю (залежно від використовуваного компілятора), дає підказки щодо ефективності, ... Компілятор відхиляє натискання клавіші.

  • Інструменти розробки графічного інтерфейсу: WinForms та WPF (я знаю, що Clojure має доступ до бібліотек Java GUI Java, але вони мені повністю чужі.)

Комерційні Lisps, такі як LispWorks та Allegro CL, пропонують подібні речі під Windows.

  • Інструменти для налагодження графічного інтерфейсу: точки прориву, вхід, перехід, інспектори значень (текст, xml, користувальницькі), годинник, налагодження за допомогою потоку, умовні точки перерви, вікно стека виклику з можливістю переходити до коду на будь-якому рівні у групі (Чесно кажучи, моє враження про Emacs + Slime, здавалося, забезпечує щось із цього, але я часткова до підходу, орієнтованого на VS GUI)

Комерційні Lisps, такі як LispWorks та Allegro CL, пропонують усе це під Windows.


1
Моя критика насправді не стосується Ліпса. Я вважаю їх цілком здатними. Я шукаю, що може зробити / дати мені Лісп, що я ще не роблю. Я повністю розумію, що більшість розробників C # не використовують багато "нових" мовних функцій. Я думаю, що більш суть полягає в тому, що я це роблю, і, чесно кажучи, поза графічним інтерфейсом я майже пишу в 100% FP стилі. FP був концептуальним стрибком, але того вартий. Однак перехід на Lisp, звідки я, здається, мало користі. Я сподіваюся виявити, що є причина, яку я повинен продовжувати давати їй шанс.

@Jonathan Mitchem: C # насправді не схожий на FP-мову, навіть якщо мова має деякі функції, які її підтримують, і кілька бібліотек можуть використовувати їх. Якщо ви хочете займатися програмуванням FP в екосистемі Microsoft, то F # може бути для вас.

@Rainer Ні, це не схоже на мову FP, але це можна зробити, і досить компактно. І коли мені потрібно / потрібний імперативний код, або ОО, я теж можу це зробити. (злегка поза темою: я насправді не вважаю F # серйозною мовою, яку варто копати, я б швидше обвів голову монадами в Haskell. Але коли я був розробником C ++ і C # вийшов, я не вважав це "справжню" мову [і тоді це не було, imho])


@Jonathan Mitchem: чому я повинен дивитись? Я писав, що C # підтримує деякі функції FP. Він просто додається до імперативної об'єктно-орієнтованої мови і не робить її ідіоматичною, як, скажімо, Lisp, Scheme і особливо не порівнюється зі SML, F #, Haskell або іншими переважно функціональними мовами. Моя думка: деякий FP можливий у C #, але це не є основною особливістю.

5

Реньє Джосвіг сказав це найкраще.

Для мене силу Ліса неможливо зрозуміти, просто переглянувши список функцій Lisp. Для Ліспа, і зокрема для Ліса, ціле більше, ніж сума частин. Це не лише REPL плюс s-вирази плюс макроси плюс багатопроменева відправка плюс закриття плюс пакунки плюс CLOS плюс перезавантаження плюс X, Y і Z. Це весь шебанг, все геніально інтегрований. Це щоденний досвід, який дуже сильно відрізняється, ніж щоденний досвід інших мов програмування.

Лісп виглядає інакше, він використовується по-різному, підходити до програмування по-іншому, коли його використовувати. Це елегантний, повний, великий та безшовний. Не обійшлося і без власних вад та пекадило. Звичайно, існують порівняння з іншими мовами, які можуть бути зроблені там, де він може не вийти попереду. Але жодним чином не є Lisp просто мовою X плюс REPL та макросами, а також мовою Y плюс мульти-методом відправки та перезапуску.


3
Код - це дані (і макроси) - можливо, я не "дістав" макросів, але я не бачив жодного прикладу, де ідея макросу не могла бути реалізована як функція; це не змінює "мову", але я не впевнений, що це сила

Як правило, макрос слід використовувати для чогось, що не є виразним як виклик функції. Я не знаю, чи в C # є умовний перемикач (подібний до того, що існує у C, як перемикач (форма) {case ...}), але припустимо, що він має і має близькі до тих же обмежень ( вимагає інтегрального типу).

Тепер давайте припустимо, що вам сподобається щось, що виглядає так, але розсилається на рядках. У Lisp (ну, конкретно, у Common Lisp і, мабуть, у інших), це "просто" макрос, і якщо ви обмежите користувач постійними рядками (напевно, не важкими), щоб відповідати, ви можете (компілювати час) обчислити мінімальна послідовність тестів, щоб визначити, який випадок відповідає (або використовувати хеш-таблицю, можливо, зберігаючи закриття).

Хоча можливо виразити, що в якості функції (рядок порівняння, список випадків та закриттів для виконання) він, мабуть, не виглядає як "нормальний код", і саме там макроси lisp мають певну виграш. Ви , ймовірно , використовували досить багато макросів або спеціальні форми TAHT є макро-як, як defun, defmacro, setf, cond, loopі багато іншого.


2

Це найкраща пояснювальна стаття, яку я знайшов, що зводить читача з поверхні адвокатури Ліспа, щоб показати деякі глибші наслідки використовуваних понять:

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

Я пам'ятаю, як читав в іншому місці таку ідею, як така: Інші мови перейняли різні риси Ліспа; збирання сміття, динамічне введення тексту, анонімні функції, закриття для отримання кращого C ++ / C / Algol. Однак, щоб отримати повну потужність Ліспа, вам потрібні всі його основні риси, і тоді ви маєте ще один діалект Ліспа, чітке сімейство мов, яке існує в тій чи іншій формі вже більше 50 років.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.