Практический пример гибкости Лиспа?

Кто-то пытается продать мне Лисп как сверхмощный язык, который может делать все когда-либо, и еще кое-что.

Есть ли практический пример кода возможностей Лиспа?
(Желательно вместе с эквивалентной логикой, закодированной на обычном языке.)


person Peter Boughton    schedule 19.09.2008    source источник
comment
Просто небольшое спасибо всем, кто ответил до сих пор - у меня еще не было возможности внимательно рассмотреть это, и, возможно, какое-то время, но я ценю ответы и выберу ответ, как только получу время прочитать и понять их все. :)   -  person Peter Boughton    schedule 02.10.2008
comment
Желательно, чтобы наряду с эквивалентной логикой, закодированной на обычном языке, я бы хотел, чтобы кто-то это сделал. Я хотел бы увидеть такую ​​таблицу сравнения: coffeescript.org (CoffeeScript слева, скомпилированный вывод JavaScript на правильно)   -  person Matthew Lock    schedule 31.05.2016


Ответы (18)


Мне нравятся макросы.

Вот код, позволяющий убрать атрибуты людей из LDAP. У меня просто случайно был этот код, и я решил, что он будет полезен другим.

Некоторые люди сбиты с толку предполагаемым штрафом за выполнение макросов, поэтому в конце я добавил попытку прояснить ситуацию.

Вначале было дублирование

(defun ldap-users ()
  (let ((people (make-hash-table :test 'equal)))
    (ldap:dosearch (ent (ldap:search *ldap* "(&(telephonenumber=*) (cn=*))"))
                   (let ((mail  (car (ldap:attr-value ent 'mail)))
                         (uid   (car (ldap:attr-value ent 'uid)))
                         (name  (car (ldap:attr-value ent 'cn)))
                         (phonenumber (car (ldap:attr-value ent 'telephonenumber))))
                      (setf (gethash uid people)
                            (list mail name phonenumber))))
    people))

Вы можете думать о «привязке let» как о локальной переменной, которая исчезает за пределами формы LET. Обратите внимание на форму привязок - они очень похожи, отличаются только атрибутом объекта LDAP и именем («локальная переменная»), к которому нужно привязать значение. Полезно, но немного многословно и содержит дублирование.

В поисках красоты

Итак, было бы хорошо, если бы у нас не было всего этого дублирования? Распространенной идиомой является макрос WITH -..., который связывает значения на основе выражения, из которого вы можете получить значения. Давайте представим наш собственный макрос, работающий так, WITH-LDAP-ATTRS, и заменим его в нашем исходном коде.

(defun ldap-users ()
  (let ((people (make-hash-table :test 'equal))) ; equal so strings compare equal!
    (ldap:dosearch (ent (ldap:search *ldap* "(&(telephonenumber=*) (cn=*))"))
                   (with-ldap-attrs (mail uid name phonenumber) ent
                       (setf (gethash uid people)
                             (list mail name phonenumber))))
    people))

Вы видели, как группа строк внезапно исчезла и была заменена одной единственной строкой? Как это сделать? Конечно, с помощью макросов - кода, который пишет код! Макросы в Лиспе - это совершенно другое животное, чем те, которые вы можете найти в C / C ++ с помощью препроцессора: здесь вы можете запустить настоящий код Lisp (а не #define вздор в cpp) который генерирует код Lisp до того, как будет скомпилирован другой код. Макросы могут использовать любой реальный код Лиспа, то есть обычные функции. По сути, никаких ограничений.

Избавление от уродливого

Итак, посмотрим, как это было сделано. Чтобы заменить один атрибут, мы определяем функцию.

(defun ldap-attr (entity attr)
  `(,attr (car (ldap:attr-value ,entity ',attr))))

Синтаксис обратной кавычки выглядит немного запутанным, но то, что он делает, прост. Когда вы вызываете LDAP-ATTRS, он выдаст список, содержащий значение attr (это запятая), за которым следует car ("первый элемент в списке" (фактически пара минусов) , и на самом деле существует функция first, которую вы тоже можете использовать), которая получает первое значение в списке, возвращаемом ldap:attr-value. Поскольку это не код, который мы хотим запустить при компиляции кода (получение значений атрибутов - это то, что мы хотим делать при запуске программы), мы не добавляем запятую перед вызовом .

Так или иначе. Переходим к остальной части макроса.

(defmacro with-ldap-attrs (attrs ent &rest body)
  `(let ,(loop for attr in attrs
         collecting `,(ldap-attr ent attr))
     ,@body)) 

,@-синтаксис предназначен для размещения где-нибудь содержимого списка вместо фактического списка.

Результат

Вы можете легко убедиться, что это даст вам то, что вам нужно. Макросы часто пишутся так: вы начинаете с кода, который хотите упростить (вывод), вместо этого вы хотите написать (ввод), а затем вы начинаете формировать макрос, пока ваш ввод не даст правильный вывод. Функция macroexpand-1 сообщит вам, верен ли ваш макрос:

(macroexpand-1 '(with-ldap-attrs (mail phonenumber) ent
                  (format t "~a with ~a" mail phonenumber)))

оценивает

(let ((mail (car (trivial-ldap:attr-value ent 'mail)))
      (phonenumber (car (trivial-ldap:attr-value ent 'phonenumber))))
  (format t "~a with ~a" mail phonenumber))

Если вы сравните LET-привязки расширенного макроса с кодом в начале, вы обнаружите, что он имеет ту же форму!

Время компиляции и время выполнения: макросы и функции

Макрос - это код, который запускается во время компиляции, с добавленной особенностью, заключающейся в том, что они могут вызывать любую обычную функцию или макрос по своему усмотрению! Это не более чем причудливый фильтр, который принимает некоторые аргументы, применяет некоторые преобразования и затем передает компилятору результирующие s-выражения.

По сути, он позволяет вам писать свой код глаголами, которые можно найти в проблемной области, вместо низкоуровневых примитивов из языка! В качестве глупого примера рассмотрим следующее (если when еще не был встроенным):

(defmacro my-when (test &rest body)
  `(if ,test 
     (progn ,@body)))

if - это встроенный примитив, который позволит вам выполнять только одну форму в ветвях, и если вы хотите, чтобы их было больше одной, то вам нужно использовать progn ::

;; one form
(if (numberp 1)
  (print "yay, a number"))

;; two forms
(if (numberp 1)
  (progn
    (assert-world-is-sane t)
    (print "phew!"))))

С нашим новым другом, my-when, мы могли бы как: а) использовать более подходящий глагол, если у нас нет ложной ветви, и б) добавить неявный оператор упорядочивания, то есть progn ::

(my-when (numberp 1)
  (assert-world-is-sane t)
  (print "phew!"))

Однако скомпилированный код никогда не будет содержать my-when, потому что на первом проходе все макросы раскрываются, поэтому никаких штрафов во время выполнения не возникает!

Lisp> (macroexpand-1 '(my-when (numberp 1)
                        (print "yay!")))

(if (numberp 1)
  (progn (print "yay!")))

Обратите внимание, что macroexpand-1 выполняет только один уровень расширений; возможно (скорее всего, на самом деле!), что расширение продолжится и дальше вниз. Однако в конечном итоге вы столкнетесь с деталями реализации, специфичными для компилятора, которые часто не очень интересны. Но продолжая расширять результат, вы в конечном итоге получите либо более подробную информацию, либо просто вернете введенное s-exp.

Надеюсь, что это проясняет ситуацию. Макросы - это мощный инструмент, и одна из функций Лиспа мне нравится.

person Mikael Jansson    schedule 20.09.2008
comment
Неплохо, хотя я бы использовал & body вместо & rest для тела функции. По сути, он оценивает то же самое, но проясняет намерение. - person Alec; 05.09.2009

Лучшим примером, о котором я могу думать, является широко доступная книга Пола Грэма On Lisp. Полный PDF-файл можно скачать по ссылке, которую я только что дал. Вы также можете попробовать Практический Common Lisp (также полностью доступный в Интернете).

У меня много непрактичных примеров. Однажды я написал программу примерно на 40 строках Lisp, которая могла анализировать себя, обрабатывать свой источник как список lisp, выполнять обход списка по дереву и строить выражение, которое оценивается как WALDO, если идентификатор waldo существует в источнике или оценивается как ноль, если Вальдо не было. Возвращенное выражение было построено путем добавления вызовов car / cdr к исходному источнику, который был проанализирован. Я понятия не имею, как это сделать на других языках в 40 строках кода. Возможно, Perl сможет сделать это в еще меньшем количестве строк.

person Jason Dagit    schedule 19.09.2008


В Лиспе есть множество потрясающих функций, но макросы - это то, что мне особенно нравится, потому что на самом деле больше нет барьера между тем, что определяет язык, и тем, что я определяю. Например, в Common Lisp нет конструкции while. Однажды я реализовал это в голове во время прогулки. Это просто и чисто:

(defmacro while (condition &body body)
  `(if ,condition
       (progn
         ,@body
         (do nil ((not ,condition))
           ,@body))))

И вуаля! Вы только что расширили язык Common Lisp новой фундаментальной конструкцией. Теперь вы можете:

(let ((foo 5))
  (while (not (zerop (decf foo)))
    (format t "still not zero: ~a~%" foo)))

Что напечатает:

still not zero: 4
still not zero: 3
still not zero: 2
still not zero: 1

Выполнение этого на любом языке, отличном от Lisp, оставлено в качестве упражнения для читателя ...

person Nowhere man    schedule 23.09.2008
comment
Мне пришлось добавить два завершающих)) в блок (let ... выше, прежде чем он будет оцениваться, но пример сработал. Спасибо! - person Daniel J. Pritchett; 03.12.2009
comment
Я хотел бы сказать, что у меня есть реализация здесь, в то время как в c, она имеет некоторые ограничения (вы должны использовать WHILE / ENDWHILE вместо while () {}, WHILE () WHILE () в той же строке не допускается .. .), но он в основном работает, он использует goto и ifstatement со стеком для его реализации, я хотел вставить его сюда, но это выглядело некрасиво. pastebin.com/0D6BAX2w - person flownt; 15.12.2010
comment
@flownt: в этом вся суть, на любом другом языке его расширение некрасиво и совсем не подходит. В Лиспе вы не можете отличить примитивную конструкцию от конструкции, созданной пользователем. Во многих реализациях Common Lisp объектная ориентация фактически добавляется к основной реализации кодом Lisp! - person Nowhere man; 15.07.2011
comment
Почему такая сложность? Хотя может быть определено с помощью (defmacro while (condition & body body) `(do () ((not, condition)), @ body)) ... - person 6502; 20.02.2012

Собственно, хороший практический пример - это макрос LOOP в Лиспе.

http://www.ai.sri.com/pkarp/loop.html

Макрос LOOP - это просто макрос Лиспа. Тем не менее, он в основном определяет миниатюрный циклический DSL (язык, специфичный для домена).

Просматривая этот небольшой учебник, вы можете увидеть (даже новичку), что трудно понять, какая часть кода является частью макроса Loop, а какая - «нормальным» Лиспом.

И это один из ключевых компонентов выразительности Лиспа: новый код действительно невозможно отличить от системы.

В то время как, скажем, в Java вы не можете (с первого взгляда) узнать, какая часть программы поступает из стандартной библиотеки Java, а не из вашего собственного кода или даже из сторонней библиотеки, вы ДЕЙСТВИТЕЛЬНО знаете, какая часть кода - это язык Java, а не просто вызов методов для классов. Конечно, это ВСЕ «язык Java», но как программист вы ограничены только выражением своего приложения в виде комбинации классов и методов (а теперь и аннотаций). В то время как в Лиспе буквально все открыто.

Рассмотрим интерфейс Common SQL для подключения Common Lisp к SQL. Здесь http://clsql.b9.com/manual/loop-tuples.html, они показывают, как макрос CL Loop расширяется, чтобы сделать привязку SQL «гражданином первого класса».

Вы также можете наблюдать такие конструкции, как «[выберите [имя] [фамилия]: от [сотрудник]: упорядочить по [фамилия]]». Это часть пакета CL-SQL и реализована как «макрос чтения».

Видите ли, в Лиспе вы можете не только создавать макросы для создания новых конструкций, таких как структуры данных, управляющие структуры и т. Д., Но вы даже можете изменять синтаксис языка с помощью макроса чтения. Здесь они используют макрос чтения (в данном случае символ '[') для перехода в режим SQL, чтобы SQL работал как встроенный SQL, а не как просто необработанные строки, как во многих других языках.

Наша задача как разработчиков приложений - преобразовать наши процессы и конструкции в форму, понятную процессору. Это означает, что нам неизбежно приходится «говорить свысока» с компьютерным языком, поскольку он нас «не понимает».

Common Lisp - одна из немногих сред, в которых мы можем не только создавать наше приложение сверху вниз, но и поднимать язык и среду, чтобы идти навстречу. Мы можем кодировать с обеих сторон.

Каким бы элегантным это ни было, это не панацея. Очевидно, что есть и другие факторы, влияющие на выбор языка и среды. Но, безусловно, стоит изучить и поиграть. Я считаю, что изучение Лиспа - отличный способ продвинуть свое программирование даже на других языках.

person Will Hartung    schedule 19.09.2008
comment
некоторые будут обсуждать статус LOOP как хорошего примера. Возможно, DO или DOTIMES или RETURN-FROM были бы лучшими примерами. - person Aaron; 27.03.2009
comment
Но как практический пример мощи Лиспа, вы вряд ли сможете его превзойти. LOOP уродлив и эффективен, как экскаватор с обратной лопатой. - person JasonFruit; 08.05.2011

Мне нравится Common Lisp Object System (CLOS) и мультиметоды.

Большинство, если не все, объектно-ориентированные языки программирования имеют базовые понятия о классах и методах. Следующий фрагмент в Python определяет классы PeelingTool и Vegetable (что-то похожее на Шаблон посетителя):

class PeelingTool:
    """I'm used to peel things. Mostly fruit, but anything peelable goes."""
    def peel(self, veggie):
        veggie.get_peeled(self)

class Veggie:
    """I'm a defenseless Veggie. I obey the get_peeled protocol
    used by the PeelingTool"""
    def get_peeled(self, tool):
        pass

class FingerTool(PeelingTool):
  ...

class KnifeTool(PeelingTool):
  ...

class Banana(Veggie):
    def get_peeled(self, tool):
        if type(tool) == FingerTool:
            self.hold_and_peel(tool)
        elif type(tool) == KnifeTool:
            self.cut_in_half(tool)

Вы помещаете метод peel в PeelingTool, и Banana его принимает. Но он должен принадлежать к классу PeelingTool, поэтому его можно использовать, только если у вас есть экземпляр класса PeelingTool.

Версия объектной системы Common Lisp:

(defclass peeling-tool () ())
(defclass knife-tool (peeling-tool) ())
(defclass finger-tool (peeling-tool) ())

(defclass veggie () ())
(defclass banana (veggie) ())

(defgeneric peel (veggie tool)
  (:documentation "I peel veggies, or actually anything that wants to be peeled"))

;; It might be possible to peel any object using any tool,
;; but I have no idea how. Left as an exercise for the reader
(defmethod peel (veggie tool)
   ...)

;; Bananas are easy to peel with our fingers!
(defmethod peel ((veggie banana) (tool finger-tool))
  (with-hands (left-hand right-hand) *me*
    (hold-object left-hand banana)
    (peel-with-fingers right-hand tool banana)))

;; Slightly different using a knife
(defmethod peel ((veggie banana) (tool knife-tool))
  (with-hands (left-hand right-hand) *me*
    (hold-object left-hand banana)
    (cut-in-half tool banana)))

Все может быть написано на любом языке, полном Тьюринга; разница между языками заключается в том, сколько обручей вам нужно перепрыгнуть, чтобы получить эквивалентный результат.

Мощные языки, такие как Common Lisp, с такими функциями, как макросы и CLOS, позволяют вам достичь результаты быстро и легко, не перепрыгивая через столько обручей, что вы либо соглашаетесь на некачественное решение, либо становитесь кенгуру.

person Mikael Jansson    schedule 20.09.2008
comment
Какие? Вы можете написать что угодно на полном языке Тьюринга? Нет. Вы имели в виду, что, вероятно, все, что можно сделать на полном языке Тьюринга, можно сделать и на другом полном языке Тьюринга. - person egaga; 02.06.2009

Я нашел эту статью довольно интересной:

Сравнение языков программирования: Lisp и C ++

Автор статьи Брэндон Корфман пишет об исследовании, в котором сравнивает решения на Java, C ++ и Lisp с проблемой программирования, а затем пишет свое собственное решение на C ++. Тестовое решение - это 45 строк Лиспа Питера Норвига (написано за 2 часа).

Корфман считает, что его решение сложно сократить до менее чем 142 строк C ++ / STL. Его анализ того, почему, интересно читать.

person Nelson    schedule 13.10.2008

Что мне больше всего нравится в системах Lisp (и Smalltalk), так это то, что они кажутся живыми. Вы можете легко исследовать и изменять системы Lisp во время их работы.

Если это звучит загадочно, запустите Emacs и введите какой-нибудь код на Лиспе. Введите C-M-x и вуаля! Вы только что изменили Emacs из Emacs. Вы можете продолжить и переопределить все функции Emacs во время его работы.

Другое дело, что эквивалентность кода = списка делает границу между кодом и данными очень тонкой. А благодаря макросам очень легко расширить язык и быстро создать DSL.

Например, можно создать базовый HTML-конструктор, код которого очень близок к полученному HTML-выводу:

(html
  (head
    (title "The Title"))
  (body
    (h1 "The Headline" :class "headline")
    (p "Some text here" :id "content")))

=>

<html>
  <head>
    <title>The title</title>
  </head>
  <body>
    <h1 class="headline">The Headline</h1>
    <p id="contents">Some text here</p>
  </body>
</html>

В коде Lisp автоматический отступ делает код похожим на вывод, за исключением отсутствия закрывающих тегов.

person Sébastien RoccaSerra    schedule 20.09.2008
comment
Я должен повторить это нечеткое ощущение живого существа. Мне действительно кажется, что работа в (Common) Lisp или Smalltalk отличается (и намного превосходит ее) по сравнению с работой с другими языками, которую мне трудно выразить. - person Frank Shearar; 18.06.2010

Что мне нравится, так это то, что я могу обновлять код во время выполнения без потери состояния приложения. Это полезно только в некоторых случаях, но когда это полезно, иметь его уже там (или только за минимальную плату во время разработки) НАМНОГО дешевле, чем реализовывать его с нуля. Тем более, что это происходит по принципу «нет или почти нет».

person Vatine    schedule 14.01.2009
comment
Это потрясающая функция во время разработки! - person Luís Oliveira; 12.08.2011

Мне нравится этот пример макроса из http://common-lisp.net/cgi-bin/viewcvs.cgi/cl-selenium/?root=cl-selenium Это привязка Common Lisp к Selenium (среда тестирования веб-браузера), но вместо отображения каждого метода он читает XML-документ определения API-интерфейса Selenium во время компиляции и генерирует код сопоставления с использованием макросов. Вы можете увидеть сгенерированный API здесь: common-lisp.net/project/cl-selenium/api/selenium-package/index.html

По сути, это запуск макросов с внешними данными, которые в данном случае являются XML-документом, но могут быть столь же сложными, как чтение из базы данных или сети. Это сила того, что вся среда Lisp доступна вам во время компиляции.

person Lispnik    schedule 22.08.2009

Узнайте, как расширить Common Lisp с помощью шаблонов XML: пример XML cl-quasi-quote, страница проекта < / а>,

(babel:octets-to-string
 (with-output-to-sequence (*html-stream*)
   <div (constantAttribute 42
         someJavaScript `js-inline(print (+ 40 2))
         runtimeAttribute ,(concatenate 'string "&foo" "&bar"))
     <someRandomElement
       <someOther>>>))

 =>

 "<div constantAttribute=\"42\"
       someJavaScript=\"javascript: print((40 + 2))\"
       runtimeAttribute=\"&amp;foo&amp;bar\">
    <someRandomElement>
      <someOther/>
    </someRandomElement>
  </div>"

По сути, это то же самое, что и программа чтения обратных кавычек Lisp (которая предназначена для квази-цитирования списка), но она также работает для различных других вещей, таких как XML (установленный со специальным синтаксисом ‹>), JavaScript (установлен на` js-inline) и т. Д. .

Чтобы было понятно, это реализовано в пользовательской библиотеке! И он компилирует статические части XML, JavaScript и т. Д. В литерал в кодировке UTF-8 байтовые массивы, готовые к записи в сетевой поток. С помощью простого , (запятая) вы можете вернуться к Lisp и чередовать данные, сгенерированные во время выполнения, в буквенные массивы байтов.

Это не для слабонервных, но это то, во что библиотека компилирует приведенное выше:

(progn
 (write-sequence
  #(60 100 105 118 32 99 111 110 115 116 97 110 116 65 116 116 114 105 98
    117 116 101 61 34 52 50 34 32 115 111 109 101 74 97 118 97 83 99 114
    105 112 116 61 34 106 97 118 97 115 99 114 105 112 116 58 32 112 114
    105 110 116 40 40 52 48 32 43 32 50 41 41 34 32 114 117 110 116 105
    109 101 65 116 116 114 105 98 117 116 101 61 34)
  *html-stream*)
 (write-quasi-quoted-binary
  (let ((*transformation*
          #<quasi-quoted-string-to-quasi-quoted-binary {1006321441}>))
    (transform-quasi-quoted-string-to-quasi-quoted-binary
      (let ((*transformation*
               #<quasi-quoted-xml-to-quasi-quoted-string {1006326E51}>))
        (locally
            (declare (sb-ext:muffle-conditions sb-ext:compiler-note))
         (let ((it (concatenate 'string "runtime calculated: " "&foo" "&bar")))
           (if it
               (transform-quasi-quoted-xml-to-quasi-quoted-string/attribute-value it)
               nil))))))
  *html-stream*)
 (write-sequence
  #(34 62 10 32 32 60 115 111 109 101 82 97 110 100 111 109 69 108 101 109
    101 110 116 62 10 32 32 32 32 60 115 111 109 101 79 116 104 101 114 47
    62 10 32 32 60 47 115 111 109 101 82 97 110 100 111 109 69 108 101 109
    101 110 116 62 10 60 47 100 105 118 62 10)
  *html-stream*)
 +void+)

Для справки, два больших байтовых вектора в приведенном выше примере при преобразовании в строку выглядят следующим образом:

"<div constantAttribute=\"42\"
      someJavaScript=\"javascript: print((40 + 2))\"
      runtimeAttribute=\""

И второй:

"\">
 <someRandomElement>
    <someOther/>
  </someRandomElement>
</div>"

И он хорошо сочетается с другими структурами Лиспа, такими как макросы и функции. теперь сравните это с JSP ...

person Attila Lendvai    schedule 20.09.2008

Я был студентом ИИ в Массачусетском технологическом институте в 1970-х. Как и любой другой ученик, я считал, что язык превыше всего. Тем не менее Лисп был основным языком. Вот некоторые вещи, для которых я все еще считаю, что он очень хорош:

  • Символическая математика. Легко и поучительно написать символическое дифференцирование выражения и алгебраическое упрощение. Я до сих пор их делаю, хотя делаю их на Си-как угодно.

  • Доказательство теорем. Время от времени я впадаю в временную запой с ИИ, как будто пытаюсь доказать, что сортировка вставки правильная. Для этого мне нужно выполнять символические манипуляции, и я обычно прибегаю к Lisp.

  • Немного предметно-ориентированных языков. Я знаю, что Lisp не действительно практичен, но если я хочу немного попробовать, DSL без необходимости погружаться в парсинг и т. д., макросы Lisp упрощают эту задачу.

  • Маленькие игровые алгоритмы, такие как поиск по дереву минимаксной игры, могут быть выполнены в виде трех строк.

  • Хотите попробовать лямбда-исчисление? В Лиспе это просто.

В основном то, что Lisp делает для меня, - это умственные упражнения. Затем я смогу перенести это на более практичные языки.

P.S. Говоря о лямбда-исчислении, то, что также началось в 1970-х, в том же AI milieu, заключалось в том, что объектно-ориентированный объект начал вторгаться в мозг каждого, и каким-то образом интерес к тому, что это есть, похоже, вытеснил большой интерес к тому, что это хорошо для. Т.е. работа над машинным обучением, естественным языком, зрением, решением проблем - все это ушло в дальний конец комнаты, в то время как классы, сообщения, типы, полиморфизм и т. д. пошли вперед.

person Mike Dunlavey    schedule 01.05.2009
comment
Вы как минимум дважды заявляете, что Лисп нецелесообразен. Почему нет? Clojure не практичен? Каковы ваши критерии практичности? - person Todd Stout; 19.08.2009
comment
@Todd: Мой практический критерий: можете ли вы создать с его помощью продукт, распространить его, быть уверенным, что он не даст сбоев в полевых условиях, будет иметь адекватную производительность, уметь обрабатывать горы данных, иметь приятный и надежный пользовательский интерфейс. Я люблю Лисп. Для экспериментального ПО, такого как AI, это здорово. - person Mike Dunlavey; 19.08.2009
comment
Программное обеспечение ITA, движущая сила таких туристических сайтов, как Kayak, Orbitz, Bing travel, American Airlines и т. Д., Использует Lisp для своей поисковой системы, обработки данных и отрисовки некоторых веб-страниц. Это, безусловно, квалифицируется как обработка огромного количества данных с адекватной производительностью. Он разделяет честь Java за красивый и надежный пользовательский интерфейс. Я не отрицаю вашего утверждения, что Lisp также отлично подходит для экспериментального программного обеспечения. См .: paulgraham.com/carl.html. - person SuperElectric; 08.12.2010
comment
@SuperElectric: Я впечатлен. Спасибо за обновления. - person Mike Dunlavey; 09.12.2010
comment
@SuperElectric Люди, кажется, приводят в пример только ITA Software, о которой говорил Грэм. - person Unknow0059; 26.11.2020

Вы видели это объяснение того, почему макросы мощные и гибкие? Хотя нет примеров на других языках, извините, но это может помочь вам в макросах.

person William Keller    schedule 19.09.2008
comment
Было бы неплохо, если бы вы процитировали сайт вместо того, чтобы просто поставить на него ссылку. - person Unknow0059; 26.11.2020

@Отметка,

Хотя в том, что вы говорите, есть доля правды, я считаю, что это не всегда так просто.

Программисты и люди в целом не всегда находят время, чтобы оценить все возможности и решить сменить язык. Часто решения принимают менеджеры или школы, в которых преподают первые языки ... и программистам никогда не нужно вкладывать достаточно времени, чтобы достичь определенного уровня, если они могут решить, что этот язык экономит мне больше времени, чем этот язык.

Кроме того, вы должны признать, что языки, поддерживаемые крупными коммерческими организациями, такими как Microsoft или Sun, всегда будут иметь преимущество на рынке по сравнению с языками без такой поддержки.

Чтобы ответить на исходный вопрос, Пол Грэм пытается привести пример здесь, хотя я признаю это не обязательно так практично, как хотелось бы :-)

person Pat    schedule 19.09.2008

Одна вещь, которая произвела на меня впечатление, - это возможность написать собственное расширение объектно-ориентированного программирования, если вам не нравится включенный CLOS.

Один из них находится в Garnet, а другой - в В Lisp.

Также существует пакет под названием Screamer, который позволяет недетерминированное программирование (чего я не оценено).

Любой язык, который позволяет вам изменять его для поддержки различных парадигм программирования, должен быть гибким.

person David Thornley    schedule 01.06.2009

Вы можете найти этот пост Эрика Норманда полезным. Он описывает, как по мере роста кодовой базы Lisp помогает, позволяя вам построить язык для вашего приложения. Хотя это часто требует дополнительных усилий на раннем этапе, позже это дает вам большое преимущество.

person drewr    schedule 19.09.2008

Тот простой факт, что это мультипарадигмальный язык, делает его очень гибким.

person temp2290    schedule 01.03.2009

Джон Остерхаут сделал следующее интересное наблюдение относительно Лиспа в 1994 году:

Разработчики языков любят спорить о том, почему тот или иной язык должен быть лучше или хуже априори, но ни один из этих аргументов не имеет большого значения. В конечном итоге все языковые проблемы решаются, когда пользователи голосуют ногами.

Если [язык] делает людей более продуктивными, они будут им пользоваться; когда появится какой-нибудь другой язык, который лучше (или если он уже есть), тогда люди переключатся на этот язык. Это Закон, и это хорошо. Закон говорит мне, что Scheme (или любой другой диалект Lisp), вероятно, не является «правильным» языком: слишком много людей голосовали ногами за последние 30 лет.

http://www.vanderburg.org/OldPages/Tcl/war/0009.html

person Mark Harrison    schedule 19.09.2008
comment
Бред какой то. Этот аргумент предполагает, что большинство всегда право. Вряд ли очень солидная предпосылка. - person troelskn; 22.09.2008
comment
Более того, предполагается, что все инструменты одинаково мощны, только с разными порогами обучения. Нет ничего более плохого. - person Mikael Jansson; 22.09.2008
comment
да, случай с миллионом мух ... в этом нет ничего плохого ... :) Я прошел долгий путь от ассемблера до шепелявости через все основные языки, и в итоге я выбрал шепелявость именно для моей более высокой производительности. .. и мы делаем корпоративные приложения. да, в общем шепелявите. - person Attila Lendvai; 12.11.2008
comment
Наблюдение Оустерхаута на самом деле довольно небрежно. Это довольно хороший аргумент в пользу того, что lisp не является хорошим средним языком для современного среднего программиста, который игнорирует тот факт, что дизайн языка и текущий средний программист развивались совместно (давление с одной стороны на взаимозаменяемые модули программиста, с другой стороны на язык power), и, что более важно, упускает из виду тот факт, что эти средние значения обычно не очень интересны. Иногда все остальные делают это - хорошая идея, а иногда совсем нет. - person simon; 01.05.2009