LINUX.ORG.RU

Почему на Common Lisp пишут в императивном стиле?


0

1

Недавно начал читать PCL (до этого изучал Scheme) - не могу привыкнуть к императивщине. По-моему, Лисп просто создан для того чтобы быть функциональным языком программирования :)

Связано ли это как-нибудь с тем фактом, что CL является «промышленным стандартом» Лиспа?


Ответ на: комментарий от linuxfan

сядь и напиши на хваленом лиспе какую-нибудь простенькую утилитку, которой так не хватает в повседневной жизни.

Какой утилиты ты хочешь на Общем Лиспе? Ты просто не сможешь этого сделать! И знаешь почему? Потому что Общий Лисп вырос быть компилятором горячего, обновляемого кода в рамках своего образа, а не скриптовым языком для одноразовых программ (хм, хотя можно).

Самое естественное использование CL это SBCL в качестве постоянно работающего сервера вычислений. Чтобы скриптить на CL нужно сначала загрузить все пакеты и сохранить образ (save-lisp-and-die, будет `$ Ваша-Платформа-Со-Всеми-Прибамбасами Скрипт.Лисп'), после чего запускать скрипты с помощью --script. Либо написать приложение которое будет отправлять скрипты на выполнение SBCL как серверу вычислений.

quasimoto ★★★★
()
Ответ на: комментарий от ander-skirnir

> mapcar - да, но слишком громоздко и появляется

дополнительная логика.


Обычно нет, ибо позволяет обходиться без lambda, запись которой в CL громоздка.

reduce - нет.


Да.

При этом, можно в рамках одной конструкции сочетать map/reduce/filter и ещё много чего.

archimag ★★★
()
Ответ на: комментарий от ander-skirnir

mapcar - да, но слишком громоздко и появляется дополнительная логика. reduce - нет.

Это потому что, формально, mapcar производное от reduce ;)

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

> позволяет обходиться без lambda, запись которой в CL громоздка.

http://ander-skirnir.blogspot.com/2010/11/x-i.html

reduce - нет.

Да.

Можно пример адекватной _правосторонней_ свёртки на loop/iterate? Кстати, это еще одно преимущество ФВП - когда ты видишь mapcar, reducе и так далее, ты сразу понимаешь, что конкретно делает этот код, а видя loop/iterate, нужно вчитываться.

ander-skirnir
()
Ответ на: комментарий от ander-skirnir

> http://ander-skirnir.blogspot.com/2010/11/x-i.html

Если каждый будет подобным образом издеваться над ридером, то будет очень плохо, всем. Кстати, я вообще не стал вникать в код dwim.hu по той причине, что они настолько «переточили», что вообще хрен поймёшь что там написано.

Можно пример адекватной _правосторонней_ свёртки на loop/iterate?


Не увернен, что правильно понимаю, что такое «адекватная правосторонняя свёртка», но пример с multiply я приводил выше. Он же является просто сахаром над более общей конструкцией reducing.

когда ты видишь mapcar, reducе и так далее, ты сразу понимаешь,

что конкретно делает этот код, а видя loop/iterate, нужно


вчитываться.



Абсолютно тоже самое сразу видишь. Больше, в реальном коде, а не на факториалах, iterate читается гораздо проще, и пишется проще, и правится проще. Только не надо смешивать loop и iterate, loop убог, а iterate божественен.

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

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

Кстати, iterate тоже впихивает подобный (но без кастомизации) ридер ни о чём не подозревающим пользователям - #L.

Не увернен, что правильно понимаю

Неправильно. Левосторонняя свёртка - (reduce ...), правосторонняя - (reduce ... :from-end t). Вообще, reduce - очень древнее название, сейчас все называют их foldl и foldr. Так вот, reducing в iterate - это только foldl.

loop убог, а iterate божественен

Вообще-то в loop больше фич. Например, `Parallel Binding and Stepping'. Что касается концепции, iterate мне больше нравится, но совсем не нравится слишком переусложнённая реализация с кодоволкером в 4000 строк, когда можно было сделать гораздо проще обычными анафорическими макролетами.

ander-skirnir
()
Ответ на: комментарий от archimag
;;n-ое число фибоначчи начиная с индекса 0
(defun fib (n)
  (loop :for i :to n
        :for a = 0 :then b
        :and b = 1 :then (+ a b) ;;мы не можем сказать :for потому, что
                                 ;; результат будет зависеть о текущего
                                 ;; значения a(только что установленного строкой выше)
        :finally (return b)))
Love5an
()
Ответ на: комментарий от Love5an

Что-то такая форма:

(defun fib (n)
  (iter (for i to n)
        (for a first 0 then c)
        (for b previous a )
        (for c first 1 then (+ c b))
        (finally (return c))))

мне нравится куда больше. Гораздо более чётко и наглядно.

archimag ★★★
()
Ответ на: комментарий от ander-skirnir

> Левосторонняя свёртка - (reduce ...),

правосторонняя - (reduce ... :from-end t)


Я не понял, а что менаешь reverse сделать? Кроме того, что reduce работе только с последовательностями, а iterate с чем угодно.

Вообще-то в loop больше фич


Фичи не считал, но убожество loop они ни в коей мере не отменяют. Про 'Parallel Binding and Stepping' не понял.

не нравится слишком переусложнённая реализация с кодоволкером в 4000

строк, когда можно было сделать гораздо проще обычными


анафорическими макролетами.



Сделай. Там будут возможности расширения, аналогичные iterate?

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

> мне - нет, лишние сущности

Какие ещё сущности? В варианте iterate любой поймёт что написано, даже если он CL второй раз в жизни видит. А в варианте с loop надо понимать «чёрную магию», которая практически не используется на практике.

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

> Я не понял, а что менаешь reverse сделать?

То, что `foldr' и `foldl reverse' - совсем разные вещи.

Сделай. Там будут возможности расширения, аналогичные iterate?

Планирую попробовать. Гибкости и расширяемости такая модель со сравнительно маленькими усилиями позволяет куда больше, чем самопальный кодоволкер. Но вот arnesi вроде очень крут.

убожество loop

А что в loop'е плохого, кроме невозможности вызывать его формы из произвольного уровня вложенности?

ander-skirnir
()
Ответ на: комментарий от Love5an

> А вот iterate-вариант кривой. Лучше уж сделать два (with ...)

и в (do ...) psetf'ить переменные


Потом люди и говорят, что CL это write-only.

archimag ★★★
()
Ответ на: комментарий от ander-skirnir

> То, что `foldr' и `foldl reverse' - совсем разные вещи.

Что-то плохо понимаю о чём-ты, наверное потому, что зачем нужен foldl я знаю, а как используется foldr на практике нет.

Но вот arnesi вроде очень крут.


Чего?

А что в loop'е плохого, кроме невозможности вызывать его

формы из произвольного уровня вложенности?



Да вроде одного это уже достаточно? Кроме того, он ужасно выглядит, плохо читается, плохо форматируется и наполнен магией. iterate же сделан так, что бы предоставить максимальную гибкость и максимально упростить понимание кода даже непосвящённому человеку.

archimag ★★★
()
Ответ на: комментарий от ander-skirnir

> Кстати, по-моему вариант с loop'ом попроще будет для восприятия.

Вариант с loop требует очень чёткого понимания что такое :and, который нужно правильно интерпретировать, а вариант с iterate показывает всё «на пальцах».

archimag ★★★
()
Ответ на: комментарий от ander-skirnir

Тогда уж сразу так

-- |
-- "God made the natural numbers; all else is the work of man"
--                                      (c) Kronecker, Leopold
--
module NaturalNumbers where

import Prelude hiding (sum)

-- |
-- Recursive data type for natural numbers, an inductive definition.
--
data Nat = Zero | Succ Nat
         deriving (Eq)

-- just for shortly
one = Succ Zero

-- |
-- Converting from/to integer.
--
fromInt :: Int -> Nat
fromInt 0       = Zero
fromInt (n + 1) = Succ (fromInt n)

toInt :: Nat -> Int
toInt Zero     = 0
toInt (Succ a) = 1 + (toInt a)

instance Show Nat where
  show = show . toInt

-- |
-- Arithmetic.
--
sum :: Nat -> Nat -> Nat
sum a    Zero     = a
sum Zero b        = b
sum a    (Succ b) = Succ (sum a b)

prod :: Nat -> Nat -> Nat
prod a           Zero        = Zero
prod Zero        b           = Zero
prod a           (Succ Zero) = a
prod (Succ Zero) b           = b
prod a           (Succ b)    = sum a (prod a b)

-- |
-- That's Fibo!
--
fib :: Nat -> Nat
fib a | (a == Zero) || (a == one) = a
fib (Succ a@(Succ b)) = sum (fib a) (fib b)

Можно запастись терпением и даже дождаться F(30). SSC явно тупит :)

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto
N ~ 0 + N*

1 = 0*

a + b  = b + a
a + 0  = a
a + b* = (a + b)*

a * b  = b * a
a * 0  = 0
a * 1  = a
a * b* = a + (a * b)

0 ^ 0  = 0 (like in TFP)
a ^ 0  = 1
a ^ 1  = a
a ^ b* = a * (a ^ b)
quasimoto ★★★★
()
Ответ на: комментарий от anonymous

А еще проще, понятней и быстрее написать

fib(n){int a=1,b=1,c;
       while(--n > 0) c=a+b, a=b, b=c;
       return b;}

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

>В Objective C для этого даже отделили аллокацию от инициализации

Уже было в Smalltalk

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

> нет не лучше, сделаешь домашку, подумай почему

Каникулы же! Подумал, ничего не придумал. В варианте с foldl не нравится список, который игнорируется в лямбде, т.е. по сути и не нужен. В варианте с iterate отсутствуют лишние сущности

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

список сожрётся оптимизатором компилятора

список, который игнорируется в лямбде

сестра, поциенту плохо

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

> список сожрётся оптимизатором компилятора

это-то ладно, но к чему он вообще нужен тогда? iterate красивее имхо

список, который игнорируется в лямбде

сестра, поциенту плохо

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

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

> Раз за разом меня называют невеждой, когда я указываю на очевиднейшие недостатки.

Потому, что эти недостатки только для невежды очевидны. Лисперы тоже высказывают претензии к лиспам, но они совсем-совсем иного рода. См., например, длинный спор в «Кл быстрее прочих».

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

Там же, если ничего не путаю, какой-то перловик высказывал подобного рода претензии. Предлагал устроить соревнование perl vs cl (причём на перловом поле в обработке текста). Был ует архимагом.

излишнюю многословность, и тормозность (по крайней мере clisp очень медленно подгружает пакеджи), и отсутствие библиотек.

Всё не так.

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

> а не скриптовым языком для одноразовых программ (хм, хотя можно).

Я применял scsh.net для скриптования. Если задача чуть сложнее простейшей склейки текстовых утилит, то в целом использование scsh удобнее, чем традиционный шелл.

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

>Лисперы тоже высказывают претензии к лиспам, но они совсем-совсем иного рода

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

Там же, если ничего не путаю, какой-то перловик высказывал подобного рода претензии. Предлагал устроить соревнование perl vs cl (причём на перловом поле в обработке текста). Был ует архимагом.

Линк будет?

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

> Там же, если ничего не путаю, какой-то перловик высказывал
> подобного рода претензии. Предлагал устроить соревнование perl vs cl

Не, это было в эпическом сраче Приходилось ли вам писать на лиспе. На перле получилось так (код попросили оформить в виде процедуры):

sub count {
   open (FILE, '/var/log/apache2/access_log');
   while (<FILE>) {
      $i++ unless /^192\.168/;
   }
   close FILE;
   return $i;
}

а на CL так:

(iter (for line in-file #P"/var/log/apache2/access_log" using #'read-line)
      (unless (ppcre:scan "^192\\.168.*" line)
        (count line)))

Кто кого уделал мнения несколько разошлись ;)

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

> Потому что лисперы не занимаются ничем полезным, а только клепают

велосипеды. Причем делают они это «для души» (то есть без

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


без оплаты).



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

Линк будет?


Я привёл выше, могу дать более точные, на конкретные посты.

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

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

А как же я? И не велосипеды, и сроки жмут, и требования высокие, и уберпроизводительность требуется, и за зарплату.

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

>Кто кого уделал мнения несколько разошлись ;)

Если кто-то наивно полагает, что CL, то у меня для него плохие новости: победил bash (egrep -v '^192\.168' /var/log/apache2/access_log | wc -l)

Ну и стандартно по-лисповски предназначение аргумента line у count является довольно загадочным.

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

> А как же я?

в каждом правиле есть исключения, он несомненно не имел ввиду, что 100% лисперов бесполезны, только 99.8%

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

> bash (egrep -v '^192\.168' /var/log/apache2/access_log | wc -l)

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

Ну и стандартно по-лисповски предназначение аргумента line у

count является довольно загадочным.



Отнюдь, count стандартная операция iterate, в рамках одного iter может вестись подсчёт разных вещей, который надо как-то отличать друг от друга, поэтому используется такой подход. Это очень хорошо описано в документации к iterate и после беглого с ней знакомства вопросов больше не возникает.

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

Вот пример более сложного использования count:

(iter (for i in sequence)
      (count i into total-count)
      (when (evenp i)
        (count (evenp i) into even-count))
      (finally (return (values total-count even-count))))

Данная конструкция подсчитывает общее количество элементов и количество чётных элементов. Пример, конечно, сильно надуман. Собственно, здесь видно, что аргумент сount используется в качестве маркера, это может быть любое выражение (оно не вычисляется).

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