LINUX.ORG.RU

How Lisp's Nested Notation Limits The Language's Utility


0

0

По данному адресу: http://xahlee.org/UnixResource_dir/writ/notations.html лежат три заметки, сабжевая в конце.

Если вкратце, автор (Xah Lee) пытается сказать, что у Lisp'а есть серьёзные недостатки, вызванные его синтаксисом, и если непривычность вложенных скобок и их некоторая ненатуральность не является технической проблемой и может служить предметом философского спора, то гораздо более серьёзной проблемой является затруднение в написании последовательности из разных функций или их объединении.

В качестве примера приводится как синтаксис из вложенных скобок уменьшает употребление вложенных функций и составление последовательности функций на лету:

ls -al | grep xyz

cat a b c | grep xyz | sort | uniq

являются легко и естественно конструируемыми, в то время как в Lisp, приходится писать что-то вроде:

(uniq (sort (grep xyz (cat a b c))))

или даже

((composition uniq sort (lambda (x) (grep xyz x))) (cat a b c))

Синтаксис языка или способ записи имеет большое значение на стиль кода и мыслительных шаблонов пользователя языка. Это хорошо известный факт, обнаруженный по математическим обозначениям и записям.

И запись f@g@h@x или x//h//g//f или в unix-стиле x|h|g|f куда более общая и лёгкая для кодирования, чем (f (g (h x))) или ((composition f g h) x)

Следовательно, Lisp убирает из шаблонов применение последовательности функций.

Поскольку сам я пока только неспешно изучаю Lisp интересно мнение лисповодов по данной статье.

Во-первых в CL в вызове функци (f a b c) f должно быть _ИМЕНЕМ_ 
функции, т.е. быть либо символов, либо лябмдой. Поэтому должно быть:

(funcall (compose f g h) x)

Применение соврменных приёмов ФП сдерживает и тот факт, что функции 
не являются каррированными, т.е.

Haskell:
g x = ...
f x y = .....
h z = g . f z

в лиспе это записывается только с люмбдами. 

Вообще основная фишка CL - defmacro и связанное с ним (модификация 
read-table, например).

В функциональном стиле гораздо удобнее писать на современных функциональных языках.

Begemoth ★★★★★
()

> В качестве примера приводится как синтаксис из вложенных скобок уменьшает употребление вложенных функций и составление последовательности функций на лету

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

uniq (sort (grep (xyz, cat (a, b, c))));

что, так луче? Разница только в стороне, с которой находится имя функции от скопки, да в наличии запятых. Первое в лиспе имеет важную причину и огромное практическое значение.

> Синтаксис языка или способ записи имеет большое значение на стиль кода и мыслительных шаблонов пользователя языка. Это хорошо известный факт, обнаруженный по математическим обозначениям и записям.

В лиспе способ записи _однообразный_, не зависит от исторически сложившихся странностей. Почему сложение - оператор, а возведение в степень в многих других ЯП - функция, в других - тоже оператор? В лиспе произвола нету.

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

> И запись f@g@h@x или x//h//g//f или в unix-стиле x|h|g|f куда более общая и лёгкая для кодирования, чем (f (g (h x))) или ((composition f g h) x)

Она не более общая и лёгкая, она выглядит более привычной. В лиспе привычность безжалостно принесена в жертву практичности и удобству.

> Следовательно, Lisp убирает из шаблонов применение последовательности функций.

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

> Поскольку сам я пока только неспешно изучаю Lisp интересно мнение лисповодов по данной статье.

Есть сто подобных и почти столько же попыток "исправить" лисп, починить то, что не сломато. Фактически, именно такая запись даёт преимущества и возможности, недоступные в других наречиях, что в какой-то степени было раскрыто в топеге "фраза о лиспе". Другое дело, что их нужно научиться использовать и знание других языков и наречий при этом помогает слабо.

bugmaker ★★★★☆
()

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

>И запись f@g@h@x или x//h//g//f или в unix-стиле x|h|g|f куда более общая и лёгкая для кодирования, чем (f (g (h x)))

Чушь.

seiken ★★★★★
()

Какая-то дурная статья. Аргумент в стиле "у вас скобки не такой формы, как у нас."

grob ★★★★★
()

Если беспокоит много скобок в конце, можно записать, например, так:

(compose-sequence uniq sort (grep xyz) (cat a b c))

где compose-sequence - макрос на четыре строчки, считая строку документации.

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

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

> uniq (sort (grep (xyz, cat (a, b, c))));

а если заменить | на >>=, получим

uniq >>= sort >>= grep xyz >>= cat a b c

Если определить фнукции uniq, sort, grep, cat, то это вполне нормальный код на хаскелле. Дело в том, что хаскелл позволяет определять новые операторы.

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

Ага, а если заменить | на (допустим) $, то можно написать коротенький макрос:

(define-macro (unix->scheme . args)
  (let parse ((rest-args    (reverse args))
              (current-func #f)
              (current-args '()))
    (if (null?  rest-args)
        (cons current-func current-args)
        (let ((term (car rest-args))
              (tail (cdr rest-args)))
          (if (equal? term '$)
              (append (list current-func)
                      current-args
                      (list (parse tail #f '())))
              (parse tail term (if current-func (cons current-func current-args) '())))))))

Получим:

#;11> ,x (unix->scheme cat a b c $ grep xyz $ sort $ uniq)
(uniq (sort (grep xyz (cat a b c))))

Думаю, автора той статьи такой вариант должен удовлетворить :)

ЗЫ: почему-то схема мне не дает использовать палочку '| как символ

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

палочка | это зарезервированая штука в CL. наверное, в схеме тоже

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

Это лишь подтверждает мое утверждение, что основания сила лиспа - в макрах и переопределении read-table, т.е. очень развитых средствах метапрограммирования.

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

А с этим никто и не спорил никогда. Но твоё утверждение состояло в другом - прочитай собственный заголовок.

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

> а вообще за unix->scheme зачот :))

Ну это первое, что пришло мне в голову для названия :)

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

> Это лишь подтверждает мое утверждение, что основания сила лиспа - в макрах и переопределении read-table, т.е. очень развитых средствах метапрограммирования.

Ну так а разве кто спорил? =) Просто такие мощные макры возможны именно благодаря строгому инфиксному синтаксису лиспа. Стоит чуть-чуть нарушить правило (напимер, добавить currying к лямбдам), и все -- количество костылей возрастет по экспоненте, и некогда ясные и простые макры превратятся в ужас типа Template Haskell, а то и препроцессор С :)

ЗЫ: Кстати карринг в частных случаях можно легко реализовать теми же макрами, которые будут дописывать недостающие lambda

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