Pull to refresh

Comments 58

Серийные эксперименты? Вообще я еще где то его видел в аниме кажется.
В эндинге Subete ga F ni Naru: The Perfect Insider?


Могло быть в Battle Programmer Shirase, но я не помню такого, либо не обратил внимание.
Может ещё где.

Первое, увы, не смотрел, во втором такого тоже не помню. Мне кажется я видел это где то в относительно свежих вещах.
Для которого Бога?
Спорят викинг и раввин,
Спор заведомо бесплоден:
— Бог — один. И он не Один.
— Один — Бог. И не один.
Раввин и викинг в жарком споре
сошлись на том, что сила в Торе!
Я ещё застал время, когда Лисп был без всех этих let и setq. Когда побочные эффекты были единственным вариантом сделать что-то вне собственного значения возврата (и то могу путать с Паскалем), когда на интуитивном уровне появляось понятие «хвостовая рекурсия», когда рекурсивный подход к решению задач был вообще единственным, и можно было понять рекурсию, пока понимаешь рекурсию… когда единственное место для хранения результатов вычислений — это стек без локальных переменных… много чего было, я тогда проперся конкретно. Мы тогда писали то ли курсовик, то ли лабу — перемножить многочлены от Х, если на входе они в символьном формате вроде «2x^2+3x-6», и из моей группы только у меня хватило мозгов преобразовать формат в лисповские списки (2 2)(3 1)(6 0), потом вычислить, потом преобразовать обратно. Но решили все, хотя бы как-то. Бедный mulisp.com :)

let же может быть тривиально реализован как макрос — например


(let (a (+ 1 2 3)
      b (* 4 5 6))
  (foo (+ a b)))

раскроется как


((lambda (a b) (foo (+ a b))) (+ 1 2 3) (* 4 5 6))

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

let же может быть тривиально реализован как макрос — например

let действительно легко реализуется, но core-форма обычно letrec, и тут уже есть проблемки.

UFO just landed and posted this here
Это точно, можно завернуть так, что потом свой код через длительное время придется разбирать заново.

Это можно на любом ЯП завернуть :)

А вот не было макросов изначально в лиспе! Во всяком случае, в том виде, в котором его нам на третьем курсе преподавали. Восемь функций: lambda, atom, eq, car, cdr, cons, quote, cond — всё. Как только кто-то запилил let/set в лисп, на нем стало возможно писать программы в императивном стиле, с переменными и присваиванием. До того — фиг, только функциональный стиль был доступен. Извращались как могли. Единственным по факту послаблением был defun — обертка над лямбдой. (Правда, честно, так и не осилил пользоваться именно лямбдой… и есть подозрение, что можно написать что-то вроде (defun let (a b) (defun (quote a) nil (quote b))) и будет работать)

Я понимаю, что есть миллион диалектов сабжа, но не верю, что среди них есть такие запущенные )


  1. Если нет макросов — напиши свой макропроцессор. Гомоиконность, как-никак. Пишешь кот, квотишь его, скармливаешь функции преобразования, получаешь другой кот, копипастишь результат куда надо.
  2. Про императивный стиль — и сейчас есть широко распространенные языки, в которых нет мутабельности от слова совсем. И ничего, живут как-то люди.
  3. Defun — это (внезапно) тоже макрос ) То есть

(defun (f a b) (+ a b))

раскрывается в


(def f (lambda (a b) (+ a b)))

  1. Про подозрения — не постиг смысл и идею что у вас там написано, но есть подозрение, что вы хотите накостылить семантику let без макросов через лямбды. Работать будет только если квотировать в месте использования конструкции каждый раз — потому что у лямбды аппликативная редукция в отличие от нормальной у макросов (по-русски, лямбда форсит вычисление своих аргументов, а макрос — нет), и результат придется еще эвалить — только не говорите, что в вашем диалекте не было eval )
Ну вот, пришел спец и макнул носом в лужу. :) По поводу eval — надо копать старые файлы, кажется, наш вариант ПО у меня где-то сохранился ещё, но если defun — макрос, то там, скорее всего, и setq был, и eval, и остальное, но ничего из этого не было в преподанном, и проверялось на отсутствие, сколько мне известно.

Да, я думал именно наколхозить механику let/set через лямбды. Формально решение должно существовать, если макрос является строгой Лисп-функцией, и может отсутствовать, если прикручен извне.

Про императивность — меня учили не разбрасываться памятью, и в 1996м сборка мусора была в зачаточном состоянии, ещё как парадигма только ЕМНИП, как следствие, иммутабельными могли быть только константы, иначе программа быстро исчерпывала память. А так — если прописывать, что при вызове функции под результат каждый раз выделяется память, которую средствами языка потом нельзя поменять, why not.

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


(defn let (l)
      (defn go (l ns es)
            cond (null? (cdr l)) (cons (cons 'lambda ns l) es)
            (go (cdr l) (cons (caar l) ns) (cons (cadr (car l)) es)))
      ((lambda (x) (print "macroexpand:" \n x \n) (eval x))
       (go l nil nil)))

(let '((a (+ 1 2 3))
       (b (* 4 5 6))
       (c (* 7 8 9))
       (+ a a b b c c)))

 => macroexpand:
((lambda (c b a) (+ a a b b c c)) (* 7 8 9) (* 4 5 6) (+ 1 2 3))
1260
Предположу, что вам его преподавали в рамках какого-нибудь курса типа «Функциональное программирование», а Лисп использовали в качестве языка для демонстрации возможностей парадигмы, причём даже не какой-нибудь существующий диалект, а «сферический Лисп в вакууме», в котором ничего императивного использовать нельзя, а про макросы рассказывать просто не нужно, пока дело не дойдёт до написания реальных программ (видимо, курсового практикума). Но интересно узнать, был ли живой в какой-то момент времени диалект, состоящий только из восьми упомянутых примитивов.
В яблочко.

Думаю, в самом начале был такой, но недолго.
Попробую ещё более в яблочко: ВМК, АЯ? :)
Занимательный факт: игровая логика The Last of Us написана на lisp, о чем говорится в видео Unsynced: The Last of Us Melee System

Так же следует обратить внимание на язык Racket (это развитие Scheme/lisp). По сути это полигон развития языкостроения
Так же следует обратить внимание на язык Racket (это развитие Scheme/lisp). По сути это полигон развития языкостроения

Стоит отметить, что некий небезызвестный typescript построен в значительной части именно на базе научной работы команды Racket.


И яп для упомянутого Last Of Us тоже именно на Racket писались (с-но, в Last Of Us, как и в Uncharted, использовался не один язык, а много специализированных диалектов).

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

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

Поклонники Racket особенно плодовиты, там даже шутка у них есть, что в неделю до 8-ми языков изобретают.
Так же следует обратить внимание на Clojure. Который как современный диалект Лиспа, широко используется (CircleCI, Wallmart, Atlassian, etc.) в том числе в крупных продакшн проектах. Например на Clojure написана транзакционная БД Datomic, представленная в AWS.

Например согласно этому опросу/исследованию JVM экосистемы от JavaMagazine, (более 10к респондентов разработчиков) Clojure занимает второе место после Java среди языков использующих JVM платформу.

Не может не радовать что в наши дни современные диалекты как Racket и Clojure имеют такое широкое применение.

Собственно счастлив тем, что использую Clojure ежедневно в работе как Clojure разработчик.

Автору спасибо за статью. Было интересно читать.
Да про Clojure все знают, это вы как из другой вселенной вещаете :) Обалденный язык, но трудно людей к нему склонить, к сожалению. Сам очень его люблю, у меня коллега в момент слабости тим лида запилил на нем сторонний проект по импорту данных из разны систем. Все классно, работать с ним удовольствие, но одна проблема, как в спринт попадает задачка на добавление туда функционала, если я или другой мой clojure-enabled товарищ заняты на других эпиках, новый человек там теряется и время исполнения задачи умножается на 10, потому что страшно ему, потому что нужно запариваться (pair) со знающими clojure людьми и в итоге есть недовольство. Так мы вирус clojure не внесли в наш Ruby коллектив. Им все хочется на go программировать, если уж экзотику можно. Очень грустно от этого, я моменты программирования на clojure лелею
В текущие проекты сложно такое «пропихнуть», проблема понятна и на слуху, остается только сочувствовать. Но как отдельный сервис иногда может быть альтернативой тому же Go в зависимости от задачи, особенно если это касается работы с данными. Просто Go это мейнстрим, и понятен большинству, не надо сворачивать голову о ФП. Clojure в сравнении с ним крайне маргинальная вещь. С другой стороны в этом можно найти и плюсы.
Не знаю, попадалась ли вам эта статейка — Why Ruby is an acceptable LISP

Так что вы, являясь членом Ruby коллектива, фактически и так пишете на lisp, потому вам и кложа приятна :)

Руби негомоиконный, что, с-но, ставит крест на полноценном метапрограммировании.
Ну и нормальной модели compile-time'а в рубях нет. Хотя, справедливости, ради она и в лиспах только в scheme-derived диалектах есть.

модели compile-time'а

Что вы имеете под этим в виду? SBCL'евское save-lisp-and-die не про это?


(Я сам мимо проходил только Scheme немного знаю).

Про гомоиконность я не утверждал, указал лишь на схожесть, поскольку можно передать блок кода, что дает возможность простого написания DSL с руби-синтаксисом. Компилировать можно crystal который на 90% руби.

Что Вы понимаете под «полноценным метапрограммированием»?
Что Вы понимаете под «полноценным метапрограммированием»?

Это когда можно метапрограммировать легко и просто, в этом случае метапрограммирование становится стандартным способом решения проблем, а написать макрос/микродсл — то же самое, что написать простую функцию (сравните с подходом, когда: "пишем макросы только в том случае, если обычных языковых средств не хватило"). Данное требование накладывает на систему метапрограммирования ряд условий:


  1. Гомоиконность
  2. Понятная и строгая семантика рантайма/компайлтайма
  3. Наличие в стандартной библиотеке возможностей парсинга и генерации экспрешшенов (паттерны, квазицитирование)
  4. Понятная и строгая модель связывания, встроенные средства работы со связыванием, с контекстами (сюда же входит наличие гигиены, как свойства макропреобразования сохранять альфа-эквивалентность, и гибких средств обхода этой гигиены)
  5. Наличие средств обработки ошибок во время макроэкспанда (например, вывод точной позиции в строке и столбце, возможность контроля со стороны того, кто пишет макрос)

можете сами посчитать, скольки пунктам удовлетворяет руби.
Если в сухом остатке — метапрограммировние есть, полноценного нет.

Статью не видел, почитаю, но в моем случае приятность кложи не связана с Ruby.
Я сначала писал 16 лет на Java, потом сьехал на Scala, потом попробовал Clojure а потом переехал в Австралию и два года пишу на Ruby :)

У них их много разных было. GOAL, получается, конкретно под ps2.

«Compass» здесь — циркуль а не компас.
Соответственно вместо «кронциркуль или компас» должно быть «циркуль или кронциркуль»
Причем, это понятно, даже если просто посмотреть на картинку
Мне кажется что современная популярность Lisp'а отчасти обязана его современным потомкам, например Clojure или Common Lisp. Мне посчастливилось работать с Clojure.
В играх тоже бывает. Вот только что заскринил
Скрытый текст
Выше же написано.
Лисп-машины, придуманные в неудобный момент в конце эры мини-компьютеров, но до начала расцвета микрокомпьютерной революции, были высокопроизводительными персональными компьютерами для элиты программистов.

В год выхода SICP Бьёрн Страуструп опубликовал первое издание книги «Язык программирования C++», принёсшей ООП в массы. Несколько лет спустя рынок Лисп-машин рухнул

Было бы очень интересно прочитать, что такое Лисп-Машины, и чем они столь радикально отличались от обычных компьютеров.
Можете прочитать на википедии, взяв оттуда список названий машин и загуглив документацию например на bitsavers. Стоит сказать, что события разворачивались в 70-х и тогда еще небыло понятия «обычный компьютер». Были только большие ЭВМ и очень большие.

Если очень коротко, в процессор (реализующий принцип CISC) лисп-машин был встроен программно-аппаратный модуль поддержки сборщика мусора (ускорение сборки мусора было до 1000 раз), а так же возможность обычному пользователю добавлять новые машинные инструкции в процессор.

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

Было бы интересно видеть в статье пометку: а сколько же это "гора памяти" в те времена.


Заметку сделать вот в этом месте:


В августовском номере от 1979 года, посвящённом Лиспу, главные редактор восторгался новыми машинами, разрабатываемыми в MIT, «с горой памяти» ( XXXКбайт, — прим. ред.)
Погуглил, и получил ссылку на… Хабру:
habr.com/post/190082
В 1988 эта же компания представила миру линейку Ivory, первым представителем которого был XL400. Эти же компьютеры были уже 40-битными и позволяли адресовать 16ГБ памяти

А ведь обычным программам тогда более чем хватало 640kb…

Лисп классный, но скобки перед функцией меня убили. Так и писал:
add ( 2 *мат* backspace backspace ctrl+left ( ctrl+right 2 3 )
:(

Автор бы выложил в статье пример кода, и тогда без слов стало бы понятно, почему он в своё время угас и почему сейчас есть некоторое возрождение.
Судя по всему, интерес, похоже, угас потому, что ФП, в 1988 году, хотело 16GB памяти (пруф habr.com/post/190082 ), в то время как всем остальным хватало 640kb.

Он из-за AI Winter угас. А 16gb — это лишь максимально адресуемая память. На данный момент для 64 битных систем она, с-но, порядка 16 эксабайт, но это не значит, что столько актуально требуется :)

А в комментах хоть кто-нибудь раскроет в чем же собственно плюсы языка для пользователя, те программиста что с ним работает?
Ну все есть функция, ок. А что можно быстро и легко сделать на лиспе и что потребует ощутимо больше усилий, например на питоне или джаваскрипте?
Сейчас, в 2018, в питон и js уже давно перекочевали фишки лиспа такие как: функция как первоклассный объект, итераторы, неопределенное (бесконечное) число аргументов функции, лямбды, сборка мусора, нетипизированные переменные, REPL. Есть возможность сделать eval к строке с кодом на питон или js, но вот выполнить какие-то глубоки преобразования кода, не просто, для этого нужны пакеты работы с AST. Больше встает вопрос а так ли часто это необходимо?

Поэтому сейчас довольно трудно сравнить. Всё течет, всё меняется.
Сказать что, что-то быстрее и легче чем на python можно сделать, особенно если нету настроенной среды не могу. Но у Common Lisp есть стандарт и несколько высококачественных реализаций, как коммерческих — Franz, LispWorks так и открытых — SBCL, CCL(Clozure Common Lisp), ECL, CLISP, которые его выполняют, что гарантирует переносимость кода и библиотек, которых тоже очень много. Если сравнивать с питоном, то нет проблем с многопоточностью и быстродействие значительно выше.
RLisp в Reduce 3.3 www.reduce-algebra.com язык моего диплома и кандидатской, вспоминаю с благодарностью: это было откровением свыше после написания собственных списочных процедур для операций над полиномами в символьном виде на языке Pascal! Уже не вспомню, как система попала ко мне на дискеты, но вместе с книгой Дэвенпорт «Компьютерная Алгебра» перевернула отношение к вычислениям вообще и символьным — в частности.
UFO just landed and posted this here
Машинные коды. Умеет всё и хорошо, но о-очень многословно, и чтобы точную реализацию чего-то создать, надо о-очень постараться. Да и умеет он «всё» только в пределах одного класса устройств. Вот и пользуются разными приближениями — где-то многословное, но почти без потерю в скорости, где-то не очень, но с компенсирующими механиками, где-то эмулятор, где-то ещё какой-то подход.
Sign up to leave a comment.

Articles