LINUX.ORG.RU
ФорумTalks

Лисперы, приведите пример превосходства Лиспа

 , ,


2

15

Я вот пытаюсь понять, так ли хорош Лисп, как его малюют?

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

В общем, вопрос мой не «про функциональщину вообще», а именно про LISP.

И вот он, этот вопрос, точнее просьба: приведите, пожалуйста, пример кода на ЛИСПе (своего или чужого), который бы вызывал вау-эффект в форме «Вау! LISP реально могуч!». На любом диалекте Лиспа.

Но, конечно, нужно быть честными и соблюдать такие условия:

  • Нужно описание, что ваш код делает (желательно еще с комментариями внутри кода).
  • Код должен демонстрировать, прежде всего, превосходства Лиспа как языка, а не большое количество существующих макросов и библиотек.
  • Код должен решать какую-нибудь практическую задачу. Сколь угодно узкоспециализированную, но имеющую отношение к реальному миру. «Программа в 40 строк, которая парсит и исполняет сама себя рекурсивно, пока память не кончится» - это хорошо, но не интересно. Разве что если она перекомпилирует сама себя в Python, а код на Python перекомпилирует сам себя в LISP. Это хоть и не практично, но эпично.
  • Задача не должна быть совсем примитивной. «А вот тебе расчет факториала в одну строку» - это, конечно, хорошо, но интересует ведь что-то нестандартное.
  • Если дадите ссылку на статью, то в ней должен быть приведен код целиком, а не по кускам, которые надо старательно вычленять и собирать. Или сами приведите его. Я (пока) не знаю Лиспа, как я смогу его собрать и оценить?
  • Я знаю, что ЛОР - не моя личная армия, но если все так уж страшно заняты, то кто же сидит в толксах?


Как говорят американцы, «продайте мне Lisp».

Всем откликнувшимся заранее спасибо.

Перемещено tazhate из development

Первые 20 глав Practical Common Lisp приведут замечательный и подробно описанный пример.

anonymous ()
Ответ на: комментарий от anonymous

Первые 20 глав Practical Common Lisp приведут замечательный и подробно описанный пример.

Мое замечание про примеры из статей обосновано как раз Practical Common Lisp. Для того, чтобы увидеть замечательность тамошних примеров, надо читать статьи целиком и понять, как, собственно, выглядит код программ. А чтобы осознать, как он работает, надо изучать книгу. А я вот и хочу понять, имеет ли смысл это делать.

proud_anon ★★★★★ ()
Ответ на: комментарий от proud_anon

Из лиспов интересные фишки копируют в другие языки уже 60 лет. И, грубо говоря, единственное что сейчас раздублировано не везде — это макросы. Чтобы действительно понять возможности макросистемы коммон лиспа — нужно иметь представление о использовании языка вообще. А значит статей короче пары десятков страниц, рассчитанных на нулевое знание языка ты не найдёшь.

anonymous ()
Ответ на: комментарий от anonymous

Интересно, кто бы это стал дублировать фичи из языка, в котором даже hello world невозможно понять, не прочитав пару книжек, по вашим же собственным словам.

quiet_readonly ★★★★ ()
Ответ на: комментарий от anonymous

А значит статей короче пары десятков страниц, рассчитанных на нулевое знание языка ты не найдёшь.

Так я же не прошу объяснений. Я же прошу вау-эффекта. Ну, например, ты говоришь о возможностях макросистемы Common Lisp. Нет ли какого-нибудь кода, который бы показал ее возможности во всей красе и уделал своей краткостью/очевидность/логичностью/еще чем-нибудь все императивные языки (или вообще всех популярных ровесников Лиспа и их наследников).

proud_anon ★★★★★ ()

from LISP 1.5 PM :(


; The Lisp defined in McCarthy's 1960 paper, translated into CL.
; Assumes only quote, atom, eq, cons, car, cdr, cond.
; Bug reports to lispcode@paulgraham.com.

(defun null. (x)
  (eq x '()))

(defun and. (x y)
  (cond (x (cond (y 't) ('t '())))
        ('t '())))

(defun not. (x)
  (cond (x '())
        ('t 't)))

(defun append. (x y)
  (cond ((null. x) y)
        ('t (cons (car x) (append. (cdr x) y)))))

(defun list. (x y)
  (cons x (cons y '())))

(defun pair. (x y)
  (cond ((and. (null. x) (null. y)) '())
        ((and. (not. (atom x)) (not. (atom y)))
         (cons (list. (car x) (car y))
               (pair. (cdr x) (cdr y))))))

(defun assoc. (x y)
  (cond ((eq (caar y) x) (cadar y))
        ('t (assoc. x (cdr y)))))

(defun eval. (e a)
  (cond
    ((atom e) (assoc. e a))
    ((atom (car e))
     (cond
       ((eq (car e) 'quote) (cadr e))
       ((eq (car e) 'atom)  (atom   (eval. (cadr e) a)))
       ((eq (car e) 'eq)    (eq     (eval. (cadr e) a)
                                    (eval. (caddr e) a)))
       ((eq (car e) 'car)   (car    (eval. (cadr e) a)))
       ((eq (car e) 'cdr)   (cdr    (eval. (cadr e) a)))
       ((eq (car e) 'cons)  (cons   (eval. (cadr e) a)
                                    (eval. (caddr e) a)))
       ((eq (car e) 'cond)  (evcon. (cdr e) a))
       ('t (eval. (cons (assoc. (car e) a)
                        (cdr e))
                  a))))
    ((eq (caar e) 'label)
     (eval. (cons (caddar e) (cdr e))
            (cons (list. (cadar e) (car e)) a)))
    ((eq (caar e) 'lambda)
     (eval. (caddar e)
            (append. (pair. (cadar e) (evlis. (cdr e) a))
                     a)))))

(defun evcon. (c a)
  (cond ((eval. (caar c) a)
         (eval. (cadar c) a))
        ('t (evcon. (cdr c) a))))

(defun evlis. (m a)
  (cond ((null. m) '())
        ('t (cons (eval.  (car m) a)
                  (evlis. (cdr m) a)))))
qulinxao ★★☆ ()
Ответ на: from LISP 1.5 PM :( от qulinxao

Ты бы хоть пояснил, что это. Еще одна реализация лиспа на лиспе?

delete83 ★★ ()
Ответ на: from LISP 1.5 PM :( от qulinxao

Я же сказал, что Лиспа пока не знаю, поэтому не пойму, в чем цимес. Запихнул это в Common Lisp, как я понимаю, определился ряд функций, а что теперь сделать-то нужно?

proud_anon ★★★★★ ()
Ответ на: комментарий от quiet_readonly

Не путай helloworld и требуемое ТС ВАУ!!1

anonymous ()

\> функциональщину
\> LISP
\> LISP реально могуч
\> уделал своей ... императивные языки

Ухты, сколько стереотипов в одном посте!

\> продайте мне Lisp

Может быть, лучшим способом будет использование инструмента, который наиболее подходит для решения конкретно *твоих* задач, не? CL - императивный нефункциональный язык, (сюрприз) достаточно простой для освоения (намного проще того же Ruby). Хорошо идет под траву^W решение слабо детерминированных задач, почти так же хорош для прототипирования как и Python (но заметно шустрее). Из явных преимуществ - макросы, достаточно перманентный синтаксис, REPL, скорость, количество реализаций, искаробочный CLOS. Минусы - отсутствует вменяемое русскоязычное сообщество, с библиотеками / фреймворками тоже туго + первичная сложность настройки IDE (defacto emacs & slime) и мозга на восприятие s-expressions.

alienclaster ★★ ()

Сколько уже таких тем было, а все равно кто-то периодически еще один экземпляр создает.

korvin_ ★★★★★ ()
Ответ на: комментарий от bhfq

Завидуете что про хаскель не пишут?

Про Haskell их в 2 раза больше

Sholy ()

Книги читать уже не модно.

dave ★★★★★ ()
Ответ на: комментарий от bhfq

Завидуете что про хаскель не пишут?

А при чем тут хаскель?

korvin_ ★★★★★ ()

Ты хочешь, что-то типа этого?

http://habrahabr.ru/post/126606/

Так и сделай по-подобию - приведи для начала свои варианты ВАУ-кода на языке, который знаешь и сделай вброс: - А лисперам слабо?

le_legioner ★★ ()
Ответ на: комментарий от le_legioner

Что-то меня это не очень впечатлило:

Удвоение списка:
(map (curry * 2) (build-list 10 (λ (x) x)))

Haskell:

double = map (*2)

dmfd ()
Ответ на: комментарий от dmfd

Haskell

Не путай лисп и хаскель. Лисп - макросистема генерации машинного кода. Хаскель - синтаксический сахар над расширенной System F. Кардинально же разные подходы!

Macil ★★★★★ ()
Ответ на: комментарий от le_legioner

приведи для начала свои варианты ВАУ-кода на языке, который знаешь и сделай вброс: - А лисперам слабо?

Негодный подход. «На асме бесконечный цикл выполняется за пять секунд. А лисперам слабо?»

Xenesz ★★★★ ()

Я вот пытаюсь понять, так ли хорош Лисп, как его малюют?

Хорош для троллинга. Язык уже давно умер, но энтузиасты насилуют уже изрядно подостывший труп.

red_eyed_peguin ()

приведите, пожалуйста, пример кода на ЛИСПе (своего или чужого), который бы вызывал вау-эффект в форме «Вау! LISP реально могуч!»

Зависит от того, что ты уже знаешь. Если ты не видел ничего, кроме плюсов, то вау-эффект будет почти от всего, кроме синтаксиса. Если ты питонщик, или, чего доброго, жабоскриптер, то вау-эффектов будет мало, у тебя может возникнуть крамольная мысль «это они спёрли из питона/жабоскрипта». Если ты хаскеллист, то от Лиспа у тебя будет сплошной рвотный рефлекс: «и вот это они называют языком высокого уровня?»

Miguel ★★★★★ ()
Ответ на: комментарий от red_eyed_peguin

А то. По насилуешь lisp - узнаешь еще несколько идей для «принципиально нового языка программирования».

Deleted ()
Ответ на: комментарий от Macil

Хаскель - синтаксический сахар над расширенной System F.

Даже Haskell 98 богаче System F. В частности, в System F нельзя написать Y-комбинатор. В Хаскеле можно (не используя его самого даже неявно).

Miguel ★★★★★ ()
Ответ на: комментарий от Miguel

Даже Haskell 98 богаче System F

Вообще-то никто не использует чистую System F.

Macil ★★★★★ ()
Ответ на: комментарий от Macil

Вообще-то никто не использует чистую System F.

Э... и что?

Miguel ★★★★★ ()
Ответ на: комментарий от Miguel

У вас похожие ники, и оба без аватарок. Спева подумал что кто-то говорит сам с собой.

vladimir-vg ★★ ()
Ответ на: комментарий от vladimir-vg

У вас похожие ники, и оба без аватарок. Спева подумал что кто-то говорит сам с собой.

И у обоих по четыре звезды =)

korvin_ ★★★★★ ()

Не видел лучше библиотеки для test-driven development, чем Midje (https://github.com/marick/Midje). На не-лиспах обычно для каждого теста приходится писать кучу boilerplate-а, а тут просто (fact выражение => результат). Если для теста нужно подменить код какой-нибудь функции, это тоже делается немногословно (fact выражение => результат (provided (функция аргументы) => результат))

nozh ()

Если вы создаете такой тред, значит вам на самом деле не нужен Лисп.

Код должен решать какую-нибудь практическую задачу.

Maxima, Jacal, http://dynamo.iro.umontreal.ca/~gambit/wiki/index.php/Real-world_software_and..., http://hop.inria.fr/

Лично мне, например, удобно читать код на Лиспе, к тому же его легко привести к читаемому виду, если автор совсем наркоман.

Кроме того, s-выражения — удобная конструкция для хранения данных. Например, чтение и запись DSSSL выполняется элементарно.

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

buddhist ★★★★★ ()

Посмотри PAIP. Я сам только начал его читать, но сразу обратил внимание, какой там красивый код.

power ()
Ответ на: комментарий от Macil

Хаскель - синтаксический сахар над расширенной System F

Во-во. Я боюсь, как бы диабет от него не получить :)

buddhist ★★★★★ ()
Ответ на: комментарий от nozh

Пока не понял, чем оно удобнее тех же питонячьих unittest-assert`ов.

power ()
Ответ на: комментарий от buddhist

Я боюсь, как бы диабет от него не получить :)

Ну, диабет ты от него не схватишь, а вот разнообразные травмы ЧСВ получить легко.

Macil ★★★★★ ()
Ответ на: комментарий от alienclaster

CL - императивный нефункциональный язык,

Мультипарадигменный с нечистой функциональной составляющей

скорость, количество реализаций,

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

ados ★★★★★ ()

Трудно удивить человека, не зная его интересов, но попробую.

Все примеры реализуется средствами самого языка (http://software-lab.de/down.html), без привлечения сторонних библиотек.

Вот кусок кода реализующий конечный автомат в несколько команд и пример его использования:

Пример 1

(state 'var (sym|lst exe [. prg]) ..) -> any
    Implements a finite state machine. The variable var holds the current state as a symbolic value. When a clause is found that contains the current state in its CAR sym|lst value, and where the exe in its CADR evaluates to
    non-NIL, the current state will be set to that value, the body prg in the CDDR will be executed, and the result returned. T is a catch-all for any state. If no state-condition matches, NIL is returned. See also case, cond and 
    job.
   
    : (de tst ()
       (job '((Cnt . 4))
          (state '(start)
             (start 'run
                (printsp 'start) )
             (run (and (gt0 (dec 'Cnt)) 'run)
                (printsp 'run) )
             (run 'stop
                (printsp 'run) )
             (stop 'start
                (setq Cnt 4)
                (println 'stop) ) ) ) )
    -> tst
    : (do 12 (tst))
    start run run run run stop
    start run run run run stop
    -> stop

anonymous ()
Ответ на: комментарий от anonymous

Пример 2 Следующий код определяет несколько таблиц, а также задает различные индексы и связи между ними. (Естественно, ссылочная целостность обеспечивается автоматически на основе этого описания ). Кроме этого определяются отображение табличных данных на классы языка и дан пример описания метода класса. В самом низу - небольшой отчет за год, где вместо декларативного SQL используется не менее декларативная разновиднось пролога, скрещенного с императивным лиспом.

# Item
(class +Item +Entity)
(rel nr (+Need +Key +Number))          # Item Number
(rel nm (+Fold +Idx +String))          # Item Description
(rel sup (+Ref +Link) NIL (+CuSu))     # Supplier
(rel inv (+Number))                    # Inventory
(rel pr (+Ref +Number) NIL 2)          # Price
(rel txt (+Blob))                      # Memo
(rel jpg (+Blob))                      # Picture

(dm cnt> ()
   (-
      (or (: inv) 0)
      (sum '((This) (: cnt))
         (collect 'itm '+Pos This) ) ) )

# Order
(class +Ord +Entity)
(rel nr (+Need +Key +Number))          # Order Number
(rel dat (+Need +Ref +Date))           # Order date
(rel cus (+Ref +Link) NIL (+CuSu))     # Customer
(rel pos (+List +Joint) ord (+Pos))    # Positions

(class +Pos +Entity)
(rel ord (+Dep +Joint)                 # Order
   (itm)
   pos (+Ord) )
(rel itm (+Ref +Link) NIL (+Item))     # Item
(rel pr (+Number) 2)                   # Price
(rel cnt (+Number))                    # Quantity

# calculate the total count of sold items:
(let Cnt 0     # Counter variable
   (pilog
      (quote
         @Nr 2
         @Year (cons (date 2007 1 1) (date 2007 12 31))
         (select (@Pos)
            ((nr +Item @Nr (itm +Pos)) (dat +Ord @Year pos))
            (same @Nr @Pos itm nr)
            (range @Year @Pos ord dat) ) )
      (inc 'Cnt (get @Pos 'cnt)) )  # Increment total count
   Cnt )  # Return count

anonymous ()
Ответ на: комментарий от anonymous

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

Пример 3

*Ext
    A global variable holding a sorted list of cons pairs. The CAR of each pair specifies an external symbol offset (suitable for ext), and the CDR should be a function taking a single external symbol as an argument. This function
    should return a list, with the value for that symbol in its CAR, and the property list (in the format used by getl and putl) in its CDR. The symbol will be set to this value and property list upon access. Typically this function
    will access the corresponding symbol in a remote database process. See also qsym and external symbols.
   
    ### On the local machine ###
    : (setq *Ext  # Define extension functions
       (mapcar
          '((@Host @Ext)
             (cons @Ext
                (curry (@Host @Ext (Sock)) (Obj)
                   (when (or Sock (setq Sock (connect @Host 4040)))
                      (ext @Ext
                         (out Sock (pr (cons 'qsym Obj)))
                         (prog1 (in Sock (rd))
                            (unless @
                               (close Sock)
                               (off Sock) ) ) ) ) ) ) )
          '("10.10.12.1" "10.10.12.2" "10.10.12.3" "10.10.12.4")
          (20 40 60 80) ) )
    
    ### On the remote machines ###
    (de go ()
       ...
       (task (port 4040)                      # Set up background query server
          (let? Sock (accept @)               # Accept a connection
             (unless (fork)                   # In child process
                (in Sock
                   (while (rd)                # Handle requests
                      (sync)
                      (out Sock
                         (pr (eval @)) ) ) )
                (bye) )                       # Exit child process
             (close Sock) ) )
       (forked)                               # Close task in children

anonymous ()
Ответ на: комментарий от buddhist

Я-то всегда считал, что «синтаксический сахар» - нарушение общности синтаксиса в угоду какой-то узкой конкретной цели. В том подмножестве хацкеля, которое я знаю, из такого, пожалуй, только list comprehensions и deriving. Даже do blocks имеют значительную общность: они работают с любыми монадами, в том числе с теми, что пишу я.

Вот где в моём примере нарушение общности? Или сахаром уже является всё, что отличается от AST, записанного с помощью круглых скобочек?

dmfd ()
Ответ на: комментарий от dmfd

«синтаксический сахар» - нарушение общности синтаксиса

Да ну, а можно пруф с таким определением.

anonymous ()
Ответ на: комментарий от anonymous

Википедия:

Specifically, a construct in a language is called syntactic sugar if it can be removed from the language without any effect on what the language can do: functionality and expressive power will remain the same.

dmfd ()
Ответ на: комментарий от dmfd

И? Что-то не вижу здесь _нарушение общности_.

anonymous ()
Ответ на: комментарий от anonymous

Конструкции, не увеличивающие «functionality and expressive power», как правило, делаются для решения конкретных задач. Можно работать со списками через обычные do и >>=, поэтому list comprehensions не обязательны. Но они есть, и они нарушают общность, поскольку работают (AFAIK) только для списков. Я может и слишком лихо перескочил с причины на следствие, но ключевое слово здесь: «как правило».

_нарушение общности_

Wakaba mark здесь не работает.

dmfd ()
Ответ на: комментарий от power

Пока не понял, чем оно удобнее тех же питонячьих unittest-assert`ов.

Меньше слов писать, код получается яснее.

nozh ()
Ответ на: комментарий от lllnk

Лучше покажи, как в такой нотации будет выглядеть какая-нибудь привычная математическая формула ^___~

dmfd ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.