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)
Ответ на: комментарий от monk

как сделать b и c на скобочках?

Воспользоваться тем фактом, что по значению сравниваются (неизменяемые) значения, а (изменяемые) ссылочные типы сравниваются по идентичности.

(let [a  '(1 (2 "ok"))        ;; (immutable) value
      a* (atom '(1 (2 "ok"))) ;; (mutable) reference type
      b  {a 4}
      c  {a* 4}]
  (println (get b a))
  (println (get c a))
  (println (get b a*))
  (println (get c a*))

  ;; two instances of a reference type are not equal, 
  ;; even if they hold the same value (currently)
  (println (get c (atom '(1 (2 "ok"))))))

;; => 4
;; => nil
;; => nil
;; => 4

;; => nil
Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 2)
Ответ на: комментарий от Obezyan
  1. Почти однострочник.
(hash-create
  (iter (for k in keys)
        (for v in vals)
        (collect (list k v))))

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

(hash-create 
  (for (key value) in-hashtable table)
  (unless (gethash key (apply hash-merge tables))
    (collect (list key value))))

Остальные также не особо понятно, зачем именно функциями.

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

Воспользоваться тем фактом, что по значению сравниваются (неизменяемые) значения, а (изменяемые) ссылочные типы сравниваются по идентичности.

А из изменяемого можно получить неизменяемое? В смысле, есть a*, но надо его запихнуть в хэш как значение, а не ссылку.

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

Остальные тоже несложно, но лень.

Точнее, их понять лень.

Вот https://www.php.net/manual/en/function.array-replace-recursive.php : " If a key from the first array exists in the second array, its value will be replaced by the value from the second array.

А в примере array_replace работает именно так, а array_replace_recursive «value will be replaced by the value from the second array» не выполняет.

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

Лиспер пытается осилить PHP, холст, масло, 2025 год.

  • а на Лиспе как такое сделать?
  • да мне понимать даже лень

ну ок, так работодателю и скажете когда подобную задачу решать придётся :)

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

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

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

да мне понимать даже лень

Мне лень понимать документацию, в которой пример противоречит описанию. Если есть нормальное описание, что она должна делать, то реализовать просто.

но объем проверок типов и потраченное время вообще не стоят того

Чего? Каких типов? А вот придумать, где бы мне именно такая функция помогла решить задачу, гораздо сложнее. Почти всегда есть какие-то дополнительные условия, поэтому iter/if/gethash справляется гораздо лучше.

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

Потратив неделю, можно реализовать весь этот список функций плюс извращённый пхпшный синтаксис с «если нет ключа, значит ключ номер позиции». И можно будет переписывать с пхп на лисп простой подстановкой.

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

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

ну ок, так работодателю и скажете когда подобную задачу решать придётся :)

Если работодатель скажет, что нужна функция, которая для каждого ключа в первом массиве, который есть во втором меняет значение на значение из второго, например, если в первом массиве array('citrus' => array( "orange") , 'berries' => array("blackberry", "raspberry")), а во втором массиве array('citrus' => array('pineapple'), 'berries' => array('blueberry')), то она должна вернуть array('citrus' => array('pineapple'), 'berries' => array('blueberry', 'raspberry')), то так и скажу, что у него бред вместо ошибка в постановке задачи.

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

А в примере array_replace работает именно так, а array_replace_recursive «value will be replaced by the value from the second array» не выполняет.

выполняет, кнопочку Run Code нажмите.

В первом массиве

‘citrus’ => array( «orange»)

во втором

‘citrus’ => array(‘pineapple’)

тк ключ citrus есть в обоих массивах, то в первый массив подставляется значение из второго ‘pineapple’. Все как описано в документации.

Это даже обезьян понятно, в чем сложность понимания у лиспера?

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

Вот потому для лисперов работы нет, дело раскрыто :)

на гитхабе под 80к использования этой функции, в различных сферах вплоть до работы с pdf

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

тк ключ citrus есть в обоих массивах, то в первый массив подставляется значение из второго ‘pineapple’. Все как описано в документации.

ключ berries тоже есть в обоих массивах, но вместо значения из второго массива array('blueberry') подставляется какая-то смесь значений.

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

на гитхабе под 80к использования этой функции, в различных сферах вплоть до работы с pdf

Верю. У clojure документация ещё ужаснее, но с ней тоже как-то работают.

monk ★★★★★
()
Ответ на: комментарий от Obezyan
  1. array-combine
(zipmap [:id :name :age] [1 "Joe" "15"])
;; => {:id 1 :name "Joe" :age "15"}
  1. array-diff-uassoc
(require '[clojure.data :refer [diff]])

(first (diff {:a "green" :b "brown" :c "blue", 0 "red"}
             {:a "green" 0 "yellow" 1 "red"}))
;; => {0 "red", :b "brown", :c "blue"}
  1. array-intersect-uassoc
  1. array-uintersect-assoc

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

(require '[clojure.data :refer [diff]])

(last (diff {:a "green" :b "brown" :c "blue" 0 "red"}
            {:a "green" 0 "yellow" 1 "red"}))
;; => {:a "green"}
  1. array-multisort

Не вполне понял, зачем это нужно, если можно просто сделать (map sort arrays) (или (pmap sort arrays), если хочется параллельно), ну да ладно.

  1. array-merge-recursive
  1. array-replace-recursive.php

Думаю, при желании это (и многое другое) несложно запилить с помощью универсального обхода дерева из clojure.walk, но да — однострочника я вам тут не предоставлю. (Рич пока что морозится от предложений добавить в стандартную библиотеку deep-merge — возможно, он прав.)

В общем, за исключением рекурсивного мержа/замены, реально полезных за пределами PHP с его сруктурами (sic) данных из этих от силы половина, и у них в кложе вполне себе есть готовые однострочные аналоги.

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

А из изменяемого можно получить неизменяемое? В смысле, есть a*, но надо его запихнуть в хэш как значение, а не ссылку.

Текущее значение можно — @a*/(deref a*) вернёт его.

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

на самом деле написать и на Лиспе и на кложе это все можно, но

Но непонятно, зачем %)

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

Thanks, but no. Means no. No way.

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

Тогда даже удобнее. Можно в одном словаре и по ссылке и по значению искать.

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

У clojure документация ещё ужаснее

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

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

Ну а как вы хотели? Общаясь с обезьяной извольте оперировать сущностями в категориях бананов.

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

Ну это же элементарно, в первом массиве

«blackberry», «raspberry»

во втором

«blueberry»

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

«blueberry», «raspberry»

Obezyan
()

Ба, магия комментариев к профилям опять сработала.

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

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

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

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

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

самому слабо все реализовать

Всё реализовать нельзя, пупок развяжется. Вот lazy seq в кложе реализует только те элементы, которые реально требуются — потому что ленивая.

Lazy seq молодец, будь как lazy seq.

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

я не стал ещё и гошникам прикормки сыпать, это все равно что бить детей.

Достаточно того что С-шники испарились из темы :)

Скобари хоть отбиваться пытаются от пхп макаки.

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

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

Когда кидаешься писать велосипеды, не изучив уже доступные инструменты — тоже начинаются проблемы, но другого рода. Сцилла и Харибда, понимаешь.

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

Ну это же элементарно, …

Это вы с пальмы свалились и в отмеску хотите, чтобы мы все тоже со стульев попадали?

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

Это вы с пальмы свалились и в отмеску хотите, чтобы мы все тоже со стульев попадали?

Скорее я просто всем к носу банан подвожу, кто-то уже понял, кто-то ещё нет.

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

В человеческом обществе тыкать другому человеку в лицо своим бананом можно только с его согласия. Иначе тюрьма (это что-то типа зоопарка).

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

я не своим, я - с дерева. Загоняешь специалистов в рамки задачи где все - банан, и смотришь как они извивается, сидя на ветке.

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

Не вполне понял, зачем это нужно, если можно просто сделать (map sort arrays)

Ты действительно не понял. Имеется в виду что каждый (под)массив это допустим колонка таблицы. Нужно сделать типа

select col1, col2, col3 from arrays order by col1,col2,col3
no-such-file ★★★★★
()
Ответ на: комментарий от Obezyan

я просто всем к носу банан подвожу

И выясняются удивительные вещи — оказывается, и без бананов вполне можно жить. Даже если ты обезьян простой.

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

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

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

О, а вот и первый порвавшийся. То о чем вы пишите называется развитый функционал работы с массивами данных предоставляемых языком из коробки.

Например, в Python развитый функционал работы с массивами предоставляет отдельная библиотека Pandas. Она тоже по вашему говно?

Подозреваю, что вы очередной С/С++ программист. Обычно они жалко блеят в своём бессилии реализовать подобное что это узко-специализированное и ультра-специфичное говно.

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

без бананов вполне можно жить.

Да разве это жизнь?

Солёный огурец ничем не хуже банана, и даже для здоровья полезнее. Рекомендую.

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

И чем это должно удивить? Функция sort принимает функцию-сортировщик в качестве параметра. Которая уже может сравнивать как угодно.

(defun multicolumn-sorter (comparator columns)
  (lambda (x y)
    (reduce
     (lambda (acc i)
       (if acc acc
	   (funcall comparator (nth i x) (nth i y))))
     columns
     :initial-value nil)))

CL-USER> (sort '((1 2 3) (1 3 6) (1 2 8)) (multicolumn-sorter #'> '(2 1)))
((1 2 8) (1 3 6) (1 2 3))
CL-USER> (sort '((1 2 3) (1 3 6) (1 2 8)) (multicolumn-sorter #'> '(1)))
((1 3 6) (1 2 3) (1 2 8))
CL-USER> 

Т.е. я понимаю, что круто, когда есть большая стандартная библиотека готовых компонент и всё такое, но это же примеры чуть сложнее left-pad’а.

P.S. Допускаю, что тоже неправильно понял исходную задачу. Но уж очень уныло тут всё, чтобы ещё и напрягаться, вчитываясь в пэхапэшную доку.

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

Допускаю, что тоже неправильно понял исходную задачу.

Вроде пример no-such-file с SQL довольно понятен.

Заходим в доку, смотрим первый пример.

Исходный набор данных t:

 (id) | ar1 | ar2
------+-----+-----
  0   |  10 |  1
  1   | 100 |  3
  2   | 100 |  2
  3   |   0 |  4

Применяем

array_multisort($ar1, $ar2);
SELECT id, ar1, ar2 FROM t ORDER BY ar1

Получаем:

 (id) | ar1 | ar2
------+-----+-----
  3   |   0 |  4
  0   |  10 |  1
  2   | 100 |  2
  1   | 100 |  3

Применяем

(let ((ar1 '(10 100 100 0))
      (ar2 '( 1   3   2 4)))
  (format t "~a~%" (sort (list ar1 ar2) (multicolumn-sorter #'> '(1)))))

Получаем:

; ((10 100 100 0) (1 3 2 4))

то есть

 (id) | ar1 | ar2
------+-----+-----
  0   |  10 |  1
  1   | 100 |  3
  2   | 100 |  2
  3   |   0 |  4

Ничего не поменялось. Пробовал разное подставлять в columns =/

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

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

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

(setq data (let* ((ar1 '(10 100 100 0))
		  (ar2 '( 1   3   2 4))
		  (data (mapcar #'list ar1 ar2)))
	     data))

CL-USER> (sort data (multicolumn-sorter #'< '(1)))
((10 1) (100 2) (100 3) (0 4))
CL-USER> (sort data (multicolumn-sorter #'< '(0)))
((0 4) (10 1) (100 2) (100 3))

P.S. Где-то в multicolumn-sorter'е ошибка. Но заведомо понятно, что решение находится в области — передать нужную сравнивалку в функцию sort. Был бы интерес, можно было бы сесть и разобраться чего же конкретно нужно сделать, но … см выше про умение загадывать загадки.

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

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

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

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

отсортировать его с помощью кастомного компаратора (который будет сравнивать нужные поля)

И тормозить.

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

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

(def result-set* [{:id 0 :counter 10 :urgency 1}
                  {:id 1 :counter 100 :urgency 3}
                  {:id 2 :counter 100 :urgency 2}
                  {:id 3 :counter 0 :urgency 4}])

(defn by-counter-asc
  [{counter1 :counter} {counter2 :counter}]
  (compare counter1 counter2))

(def sorted-by-counter (sort by-counter-asc result-set*))

(map :id sorted-by-counter) ;; => (3 0 1 2)
(map :counter sorted-by-counter) ;; => (0 10 100 100)
(map :urgency sorted-by-counter) ;; => (4 1 3 2)

Примерно то же самое. Вероятно, даже более правильное — потому что стабильное (сохраняет порядок записей с одинаковыми значениями поля, по которому сортируем).

Можно, конечно, для этого случая задать и второе поле для сортировки, и третье — нужно просто слегка допилить компаратор.

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

Ахаха, сколько нужно скобарей чтобы реализовать мультисортинг массивов?

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

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

Те пока макаки решают задачу используя специализированные инструменты скобари вынуждены сначала создавать эти самые инструменты :)

Причём не факт что среднестатистический скобарь уровня Ловсанчика сможет накорябать инструмент хотя бы такого же уровня качества как готовый инструмент в другом ЯП.

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

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

в Лиспе эту самою библиотеку надо изобретать с нуля теряя время.

Ничего там не надо изобретать, всё уже изобретено. И sort, и compare, и даже map. Нужно просто в одно действие собрать из этих кирпичиков готовое решение.

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

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

Ничего там не надо изобретать, всё уже изобретено.

@

нужно просто слегка допилить компаратор.

Вы там определитесь :)

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

Но ведь лень — одно из основных достоинств обезьяна %)

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

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

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

Что-то php с мозгами делает видно. Это не в суд или осуждение, у всех бывает профдеформация и безмерно странные вещи становятся логичными и само собой разумеющимися.

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

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

Ну, вот. А я так старался …

ugoday ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.