LINUX.ORG.RU

Не учите Common Lisp!

 ,


1

7

Хочу предостеречь форумчан от изучения Common Lisp. Возьмите самую лучшую имплементацию — SBCL и скомпилируйте следуюущие лямбды:

;; Взятие элемента по индексу x из массива x
(lambda (x) (aref x x))
;; Взятие элемента по индексу y из массива x и прибавление к x
(lambda (x y) (+ x (aref x y)))
;; Один из путей выполнения: прибавление X к NIL
(lambda (x y) (+ x (funcall (lambda (x) (if x 0 x)) y)))

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

Минус коммон лиспа как языка — слишком разрешательский стандарт. Почти сплошь и рядом там фразы вроде «Эффект, производимый объявлением inline, определяется реализацией» или «Реализация вольна игнорировать то-то и вместо этого делать то-то». Из-за этого разработчики того же SBCL будут игнорировать твои баг репорты, где из-за неправильного поведения компилятора (с точки других опубликованных алгоритмов) твой код будет работать раза в 2 или 3 медленнее, чем должен бы.

Написали бы в стандарте «реализация ДОЛЖНА поступать так-то и так-то», и можно было бы тыкать разрабов носом в это место и требовать корректного поведения. А раз написали «реализация может делать, что ей захочется», то и прижучить их нельзя. В итоге все занимаются чем хотят, кроме починки багов.

Короче, учите языки с хорошей теоретической базой и статической типизацией. Байкам @lovesan не верьте ни одной.



Последнее исправление: dura4ok11 (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Не понял как работает

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

(def ps (partition-all 2 {:a {:A 1} :b {:B 2} :c {:C 3}}))                                   
;; (([:a {:A 1}] [:b {:B 2}]) ([:c {:C 3}]))

(-> ps
    first
    second
    second
    :B)
;; => 2

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

Кстати, а какую задачу-то решаем? Может, и попроще способы есть? Деление ассоциативных массивов на куски равного размера по своей сути выглядит как-то подозрительно — возможно, кто-то снова наобезьянил с представлением исходных данных? %)

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 4)
Ответ на: комментарий от Nervous

Мне кажется у тебя словарь разрушается (с трудом читаю clojure структуру могу ошибаться), $arr после array_chunk выглядит так:

[
    {
        "a": {"A": 1},
        "b": {"B": 2}
    },
    {
        "c": {"C": 3}
    }
]
И я выбираю поэтому через [0][«b»][«B»], а ты видимо из за разрушение словаря используешь индексы, как сделать что бы словарь сохранялся? И ты мог выбрать в Clojure итоговый массив по first get :b get :B

Кстати, а какую задачу-то решаем? Может, и попроще способы есть?

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

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

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 5)
Ответ на: комментарий от MOPKOBKA

Clojure программисты не справились

Вот сюда посмотри. Правильно выбранное представление и подходящие под задачу структуры данных творят настоящие чудеса.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Мне кажется у тебя словарь разрушается

Он теперь нарезанная на куски по два последовательность пар ключ-значение, да. Если надо, можно собрать обратно — но я не уверен даже, что его надо было делить на куски в первую очередь. Какая задача решается? %)

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

ugoday хотел array_multisort 1 в 1

Заняться больше нечем шоле, чем похапешные каракули один в один переписывать со всеми их родовыми травмами. Будет нормальная задача — возможно, будет и интерес.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от Nervous

Ок, так нельзя, не написав дополнительно кода. Что не удивительно, мало у каких языков есть столь прекрасные и выразительные структуры! Хотя вот например InterSystems Caché в чем то даже интереснее.

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

Тебе это кажется логичным потому что ты привык к Clojure, а я думаю в PHP более интуитивно. В PHP словарь делится просто на куски по 2, сохраняя элементы, пары (key value), а в Clojure оно сначала делит на куски по 1 паре (key value) а потом эти пары еще раз делит на массивы по 2.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 4)
Ответ на: комментарий от MOPKOBKA

мало у каких языков есть столь прекрасные и выразительные структуры [как похапешные массивы]

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

мало у каких языков есть

Возможно, это жжж неспроста? %)

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

Возможно, это жжж неспроста? %)

Конечно, обычный парадокс Блаба

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

Ну, давайте глянем на кожуру от банана - Clojure.

Кложура это давняя тайная мечта лисперов - Лисп с нативным интеропом здорового человека. То что Ловсан под .Net пытается сделать своим bike. Сиденья все ещё нет, но на велосипеде уже можно прокатиться, на любителя так сказать. Но мы отвлеклись.

Lisp - мощнейший язык, один из самых мощных, но он - сферический конь в вакууме на ANSI стандарте который не может нормально использовать наработки других языков (ANSI vs IEEE754), а своих современных наработок уровня библиотек как на Java, .Net или C++ просто нет.

Кложура это Лисп, который взяли и с размаху посадили на JVM позволив ему сразу использовать все наработки Java (кложа скрипт может использовать все наработки js).

В итоге получился диалект лиспа со всеми его плюсами и богатейшим приданным от Java доступным сразу.

У языка много интересных фич, но я остановлюсь о трех интересных для меня. Это

  1. гомоиконность - код это тоже данные и наоборот (в php есть жалкое подобие под названием «переменные переменные», $$var) в купе с ленивостью вычисления даёт самый мощный инструмент по созданию кода в мире на текущий момент.

  2. отличная многопоточность без косяков (fpm для php без смерти после запроса)

  3. развитый инструмент для работы с коллекциями (как php с массивами, так кложа с коллекциями)

В итоге получился отличный язык, уделывающий С++ и Java в скорости работы и разработки, но уступающий PHP и JS в скорости разработки (не путать со скоростью работы) под веб тк эти языки заточены под него на уровне команд.

Если бы не PHP, я бы писал на Clojure :)

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

я бы писал на Clojure :)

Если бы я не был женат, я б трахал Натали Портман. В смысле не даст?

Ну что значит, писал бы, кто бы вам за это платил?

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

Ну я обещал написать за Кложуру, я написал, как есть.

Работа по кложуре есть, но на PHP я получаю больше бананов :)

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

гомоиконность - код это тоже данные и наоборот

Какое применение? Какие есть проекты применяющие ее? Что бы вот без нее вышло намного сложнее и неудобнее. Я особой разницы между XML программированием не нахожу.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Какое применение?

Метапрограммирование!

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

Это примерно как с блокнота перейти в home row на lazy vim. Первый месяц дико, потом за уши не оттянешь :)

Obezyan
()
Последнее исправление: Obezyan (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

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

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

дописывание и отладка кода в момент выполнения

Избавь Господь! Эдак они на лоб фонарик прилепят и ночью косить заставят (с)

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

Кстати, а как эта самая гомоиконичность (прости Аллах!) поддерживается ИДЕшками? Есть хотя бы автокомплит, промолчим пока про более интеллектуальную помощь. Я помню, какая это боль писать плагины для имакса на листе в имаксе. Вроде родной язык для редактора, а языковая поддержка уровня нано

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

Кстати, а как эта самая гомоиконичность (прости Аллах!) поддерживается ИДЕшками?

Вот тут ваши опасения оправданы. Поддерживается REPL режим в Emacs и ещё паре специализированных иде в лучшем случае выглядевших как notepad++

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

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

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

Можно реализовать Threading Macros, см: https://docs.racket-lang.org/threading/index.html или https://clojure.org/guides/threading_macros

Если лень по ссылкам ходить, то вкраце: код, который обычно записыватеся справа-налево abs(sin(double(max([1 2 3 4])))), переписывается более естественным способом: слева направо. Получается похоже на shell-скрипты c pipes.

Вот, как мы пишем cat file | gunzip | grep | sed | awk | sort | uniq, иммея в виду, что поток данных проходит через последовательность обработчиков, так и в лиспе

CL-USER> (~>> '(1 2 3 4 5)  
	      (mapcar (lambda (x) (expt x 2)))
	      (remove-if #'evenp)
	      (apply #'+))
35

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

Благодаря скобочкам на весь трюк

(defmacro ~>> (x &rest forms)
  "Thread a value (x) through forms as the final argument."
  (if (null forms)
      x
    (destructuring-bind (f &rest head-args)
        (car forms)
      `(~>> (,f ,@head-args ,x) ,@(cdr forms)))))

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

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

Сильнейшая рефлексия

А зачем она нужна? Все же лучше покажи мне проект реальный.

REPL на живую

Зачем он нужен?

дописывание и отладка кода в момент выполнения

Там состояние уже неправильное, при ошибке я ВСЕГДА хочу что бы после исправления программа была перезапущена. Иначе я могу забыть что то дописать, или не учесть что структура уже поменялась, работать не с теми данными.

Объяснить тяжело

Просто, «Talk is cheap. Show me the code» как говорил Линус.

Это примерно как с блокнота перейти в home row на lazy vim. Первый месяц дико, потом за уши не оттянешь :)

После введения UTF-8 я с радостью использую notepad.exe в качестве редактора кода. Мне понятно почему лисперам нравится Emacs и сложные редакторы, на нем писать без спец.софта невозможно, но на нормальных языках то...

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от ugoday

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

Вроде не сильно больше, вот, как тебе?

<?php
function pipe() {
  $x = null;
  foreach (func_get_args() as $arg)
    foreach (explode('|', $arg) as $cmd)
      $x = is_callable(trim($cmd)) ? call_user_func(trim($cmd), $x) : eval("return $cmd;");
  return $x;
}

echo pipe('10 | sin | cos | number_format($x, 3)'), "\n";

// Или вот так
echo pipe(10, 'sin', 'cos', 'number_format($x, 3)'), "\n";

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от MOPKOBKA

Зачем он нужен?

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

Obezyan
()
Последнее исправление: Obezyan (всего исправлений: 1)
Ответ на: комментарий от Obezyan

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

PHP запрос отрабатывает 0.001 секунду, мне проще кнопку «Обновить» в браузере нажать, через 0.00005 секунд я увижу работает код или нет.

То о чем ты говоришь, называется xdebug, там можно тоже выполнять программу построчно, заходить выходить из функций, выполнять какой угодно код, изменять данные, продолжать выполнение после этого.

А что делают лисперы когда они создали неправильные структуры в своем REPL, пишут код для их исправления помимо исправления в самом коде? Ну перезапускать же нельзя, нужно продолжать работать в образе.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 3)
Ответ на: комментарий от MOPKOBKA

Я совсем не знаю php, так что подскажите у кого ошибка, у меня или у вас:

$n = 4;
function plusn($x){ 
  return $x + $n; 
}

echo pipe('10 | plusn');

Warning: Undefined variable $n in php shell code on line 1
10

а я ожидал, что 10 + 4 будет 14. Но может не понял чего.

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

В PHP нельзя просто так использовать глобальные переменные, добавь:

 function plusn($x) {
+  global $n;
   return $x + $n;
 }
Считаю это минусом PHP, люблю глобальные переменные, но их нужно помечать перед использованием обязательно.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 4)
Ответ на: комментарий от MOPKOBKA

Вы не учли что у них компилируемый язык в байт код JVM.

PHP - интерпретируемый язык, там xdebug рулит, это понятно (я его уже лет 15? использую).

У них в наших терминах продвинутый вариант xdebug с readline extension и интерактивным шеллом php -a где скачаешь по коду и дебажешь/меняешь без перезапуска, удобнее и быстрее чем просто xdebug.

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

Ну так и в xdebug дебажишь и меняешь без перезапуска, там как в любом приличном отладчике есть остановка по исключению. Я преимущества REPL именно не увидел, вот был бы он в PHP, что бы мне это дало? Как именно ускорило бы отладку?

Если это только для компилируемых языков преимущество, тогда ок, тогда понятно. А в PHP оно вроде бы и так все меняется.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 3)
Ответ на: комментарий от MOPKOBKA

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

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

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

Можно их поменять в редакторе, и выполнить в xdebug, эффект тот же самый, хотя намного проще поменять и обновить вкладку браузера.

Возможно «перемотка времени» удобная если начать ее использовать, я знаю что в Visual Basic ее нахваливали, но сам не пользовался. Учту, может когда нибудь дотянутся руки попробовать.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от ugoday

Тему замеров производительности пхпшникам лучше обходить стороной

Это сильно протухшая игра. Вот актуальная. Как видишь, это кложуристам лучше ходить стороной.

no-such-file ★★★★★
()
Ответ на: комментарий от Obezyan

Не показывайте им как написать лисп на пхп!

Это было бы лучшее из его применений, с большим отрывом.

P.S. И это уже произошло: https://phel-lang.org/, так что выходные снова свободны.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Я особой разницы между XML программированием не нахожу.

Разница в том, что XML программирование нужно руками реализовать, т.е. по сути написать свой язычок для интерпретации XML. А в ЛИСП такое из коробки, намного гибче и ещё и с компиляцией.

no-such-file ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Круто, с декларацией global работает. А как сложить два числа?

php > echo pipe('10| +1');
1
php > echo pipe('10| 1+');

Parse error: syntax error, unexpected token ";" in php shell code(5) : eval()'d code on line 1
php >
ugoday ★★★★★
()
Ответ на: комментарий от no-such-file

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

pineapple
()
Ответ на: комментарий от no-such-file

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

Вот как в Lisp удобно пометить что поле в defstruct имеет специальное имя при экспорте в формате ABCD? И чем это будет удобнее?

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 3)
Ответ на: комментарий от MOPKOBKA

Вот как в Lisp удобно пометить что поле в defstruct имеет специальное имя при экспорте в формате ABCD?

Вроде бы plist специально для этого придумали. В чём проблема? Тут ещё большой вопрос, должно ли это быть фичей структуры, или сериализатора. Мне вот не нравятся эти хинты прямо в структуре.

Ну на XML буквально не программируют, он для аннотаций скорее, настройки

Буквально программируют. Например тот же набор для твоего pipe можно брать из конфига в xml/yaml. Прикручивают туда if-else и понеслось.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 2)
Ответ на: комментарий от no-such-file

Вроде бы plist специально для этого придумали. В чём проблема? Тут ещё большой вопрос, должно ли это быть фичей структуры, или сериализатора. Мне вот не нравятся эти хинты прямо в структуре.

plist это же словарь просто как в php?

Взглянув на структуру сразу можно увидеть какие поля за что отвечают, как преобразуются, я считаю это хорошо. В С есть X макросы для этого. Как CL может более эффективно решить эту проблему?

Буквально программируют. Например тот же набор для твоего pipe можно брать из конфига в xml/yaml. Прикручивают туда if-else и понеслось.

Ну на таком базовом уровне программируют, это да. Вот как Common Lisp эффективно решает задачу взять конфиг yaml и выполнить его?

Компиляция это явно плюс, если нужна скорость, в C/C++ некоторые библиотеки для всяких сложных вычислений имеют jit, удобно когда это из коробки.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 3)
Ответ на: комментарий от MOPKOBKA

plist это же словарь просто как в php?

Да, но он прикручивается на символ.

Вот как Common Lisp эффективно решает задачу взять конфиг yaml и выполнить его?

Выкидываем yaml, пишем на CL. Очевидно же.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от no-such-file

Выкидываем yaml, пишем на CL. Очевидно же.

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

Разве нельзя просто сделать (eval (yaml-to-sexp «file.yaml»))? Ну а между этим фильтр и свои конструкции проставить.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от MOPKOBKA

Разве нельзя просто сделать

Можно, но зачем? Синтаксис s-exp не сильно сложнее json, а уж тем более xml.

теряется возможность ограничить конфиг простым языком, за счет которого потом можно произвести оптимизации, переставить pipe или скомбинировать их

Это уже проблемы человека. Не пиши сложные конфиги.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Ну если не писать сложные конфиги, то есть ли отличие от php, где config.php это лишь

<?php
return [
  ...
];

Что дает гомоисконность? Возможность yaml -> s-exp мне казалась интересной, но видимо я ошибался, и это не то что кажется чем то интересным для лисперов.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Возможность yaml -> s-exp мне казалась интересной, но видимо я ошибался, и это не то что кажется чем то интересным для лисперов.

Если ты хочешь чтобы конфиг был именно yaml и именно компилялся статически, то тогда преобразование в s-exp актуально. Разница с php или Си именно в том, что там компиляться может только код языка, а yaml можно читать и парсить только в рантайме. (Ну или прикручивать отдельно кодогенерацию).

Но я как раз считаю, что это и не нужно. Пиши конфиг на самом языке, нафиг тебе сдался этот yaml для статического конфига? Вот если конфиг читается динамически, т.е. его можно обновлять в процессе работы программы, то это другое дело. В ЛИСПе его конечно можно компилять и в данном случае, но мне кажется смысла особого нет.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.