Несколько причин освоить CL даже если вы не планируете писать на нем в будущем

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

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

    Но сейчас я пришел к выводу, что это утверждение всё же верно.

    Поверьте.
    Новых идей в языках программирования не появлялось с середины 90х, то есть как раз с момента стандартизации Common Lisp.

    Если вы возьмете в руки одну из современных реализаций CL, такую как SBCL, более-менее разберетесь со стандартным ANSI CL и его расширениями, предоставляемыми реализацией, то вы постигнете и поймете от и до такие парадигмы программирования, как:
    • Императивная и ее вариации (в CL даже goto есть! а уж остальные средства управления control flow в нем заруливают аналоги из всех других языков)
    • Структурная (без комментариев)
    • Объектно-ориентированная и ее вариации (От замыканий до CLOS)
    • Функциональная(CL поощряет локализировать побочные эффекты и писать по возможности без них)
    • Событийно-ориентированная (которая сводится к коллбэкам, то есть объектам функций)
    • Обобщенная (см. в конце статьи про полиморфизм)
    • Метапрограммирование (ведь это лисп! Сама программа есть объект языка)
    • До определенной степени, параллельное программирование
    • И так далее, и тому подобное — используя средства языка, которые прямо реализуют предыдущие парадигмы, и скрепляя все макросами, CLOS и condition system, вы сможете внести в язык что угодно, начиная с логической парадигмы и встроенного пролога, и заканчивая визуальным программированием.


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

    В принципе, это верно даже для Си, так как я на своем опыте убедился, что работа с FFI и встроенным ассемблером помогает понять Си и обычные ассемблеры больше, чем даже работа с ними самими.

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

    До определенной степени, современные реализации CL помогут разобраться с общими для всех языков техниками оптимизации кода, со многими низкоуровневыми концепциями(см. выше про Си), с многопоточным программированием, и вообще с параллелизмом(все знают откуда у Google взялась идея MapReduce?), и даже с принципами построения сложных систем(хотя это, конечно, больше приходит с опытом).

    Я говорю только про языки и общие концепции программирования, не говорю про конкретные фреймворки и библиотеки, и какие-либо вещи, ортогональные собственно языковым концепциям, но возможно, вы также будете продуктивнее осваивать их, замечая паттерны, знакомые вам по лиспу, и поэтому структурируя информацию быстрее. Лично мне как-то давно некоторый опыт с CL помог лучше понять суть и назначение XML, а как-то еще — помог разобраться с организацией и общими принципами построения графических интерфейсов и GUI-фреймворков.

    Еще есть хаскель, да, который, говорят, тоже «просветляет». Но лично я считаю хаскель некоторым синтаксическим сахаром над парочкой базовых концепций, которые на самом деле доступны и в лиспе, только в более общем, и, от этого, менее заметном, и естественно, менее обязательном, виде. Эти концепции:
    • Паттерн-матчинг(ну ADT, да, но ADT по сути нужны только для паттерн-матчинга), который суть разновидность динамической множественной диспетчеризации.
    • Ленивость, которая сводится к потокам(streams) и замыканиям.
    • Полиморфизм(который, по сути, и является причиной наличия в хаскеле всей этой шелухи с типами). Параметрический полиморфизм это, концептуально, подмножество динамической типизации, а ad-hoc — диспетчеризации по типам(которая в лиспе может достигаться как банальными if+typep, так и более мощными механизмами, типа CLOS). Кто-то скажет — но ведь в хаскеле он в compile-time! Да, но я не считаю это чем-то таким особенным — если припрет, можно и макросов написать, и перенести операции над типами в compile-time и в лиспе(и нет, для этого не надо будет изобретать новый язык «поверх» CL, просто надо будет работать с объектами «лексических окружений», которые, хотя конкретный их формат в стандарте не оговорен, во всех основных реализациях присутствуют и информацию о типах предоставляют), правда тогда придется работать только с подмножеством системы типов CL, так как в общем виде она неразрешима даже в динамике, как я уже выше говорил.

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 49

      +1
      Овладей этим хабр :) Погроменк с тобой.
        +4
        А можно про «помог лучше понять суть и назначение XML» подробнее? Может быть я на этот язык как-то иначе смотрю.
        • UFO just landed and posted this here
            0
            ну, как-то так, да :)
            +2
            ...

            ....



            (response
            (items
            (item ...)
            ...))

            И XML, и S-expressions представляют собой по сути динамически типизированное дерево некоторых элементов. XML постоянно пытаются использовать как что-то большее, например, разрабатывают XSLT-движки. В Лиспе у вас из коробки тот же самый XML (хоть и записанный иначе) и куча средств для его обработки. В частности, многие лисповые фреймворки «переизобретают» HTML, заменяя треугольные скобки чем-то вроде [:html [:body :bgcolor "green" [:div ... ] ... ]] (Clojure).
              +2
              Пардон, не знал, что Хабр не переваривает теги даже в коде. Первый пример должен был выглядеть так:

              <response>
              <items>
              <item>
              ....
              </item>
              ...
              </items>
              </response>
                0
                > [:html [:body :bgcolor «green» [:div… ]… ]] (Clojure).

                В Yaws Эрланга тоже есть подобная вещь, называется ehtml:

                {ehtml, {html, [], [{body, [{bgcolor, "green"}], [{div, [], ...}]
                         }]
                }}
                
              +26
              «Боже, это не конфигурационные файлы, это исходники!» :)
                +4
                Радует, что есть такие увлечённые люди в области CL, да ещё и любящие делиться знаниями и взглядами. Уверен, мы ещё много от вас услышим (в хорошем смысле этого слова).
                  +21
                  Вот уж не соглашусь на счёт Хаскелла. Во-первых, описание типов в Хаскелле — это половина стадии проектирования программы. Если в Лиспе (в том числе и CL) всё крутится вокруг потоков данных и функций, их преобразующих, то в Хаскелле всё крутится именно вокруг строгой типизации. Например, вы начинаете проектировать веб-сервис. На Лиспе вы сразу представите функции «receive-request» и «send-response», а что и как пересылать — это уже будет видно потом. На Хаскелле вы в первую очередь задумаетесь о типах сообщений, затем о типах внутри серверов, и только потом о том, как всё это связать. Типизация в Хаскелле — это одновременно и средство выражения идеи, и надёжный верификатор — программу на нём сложно заставить скомпилировать, но если получилось, то почти наверняка она работает правильно. Лиспу в корне чужда такая идеалогия — а, вы можете построить свою систему для описания и верификации ADT, свои классы типов, загнать всё в макросы и заставить выполняться во время компиляции, при этом отказавшись от большей части преимуществ самого Лиспа, но в таком случае зачем всё это? Всё, что вы получите — это тот же Хаскелл, только со скобочками и кучей заморочек.
                  Соответственно, CL очень слабо помогает в изучении языков типа Haskell. А если пойти дальше и вспомнить про автопрувер Coq, то тут Лисп вообще ни к селу, ни к городу.

                  Во-вторых, ленивость не сводится к потокам и замыканиям. Чтобы ленивые вычисления не давали некорректных результатов, нужна как минимум гарантия немутабельности обрабатываемых данных, а CL её не даёт. Вообще ленивость возможна только в декларативном программировании, где не существует ни понятия времени, ни понятия последовательности действий. CL же со своей мультипарадигменностью не способен поддерживать декларативность на нужном уровне. Вернее технически то способен, но всё равно не поощрает.
                  Так что тут тоже промах — CL вряд ли научит человека ленивым вычислениям.

                  • UFO just landed and posted this here
                      +7
                      Ну, во-первых, в Clojure ленивость по большому счёту ограничивается ленивыми коллекциями, а это ленивые коллекции в той или иной ипостаси есть практически в любом языке — итераторы и потоки в Java, генераторы и file-like objects в Python и так далее. Полноценная ленивость — это в первую очередь нормальный (не аппликативный) порядок вычисления, т.е. то самое «ничто не будет вычислено, пока его результат не понадобится». Ленивые конструкции есть во всех языках (например, if, or, and), но программисты на «стандартных» языках редко задумываются о том, что ту же идею можно распространить шире.

                      Во-вторых, я всё же склоняюсь к мнению, что Clojure — это довольно чистый функциональный язык. По крайней мере условия немутабельности данных в нём сохраняется практически всегда — из способов изменить данные в Clojure: STM и transients по факту всегда локализованы внутри одной функции, так что внешне неизменяемость не нарушается; Java interop составляет обычно небольшую часть кода и сводится к обмену (немутабельными) результатами операций между Java и Clojure; I/O — он и в Хаскелле I/O, тут уже от изменяемости никуда не уйдёшь. Так что на полную декларативность, конечно, рассчитывать не приходится, но отдельные элементы и операторы в Clojure ввести всё-же можно (например, memoize или новые ленивые логические операторы).

                      Насчёт ленивых версий Scheme ничего не скажу — насколько я помню, есть несколько исследовательских имплементаций и даже одна серьёзная реализация продакшн-уровня. Но как-то я не слышал о большой их распространённости, так что предполагаю, что получилось не очень хорошо. Хотя и в Scheme, и в CL есть куча встроенных средств (типа delay и force) для организации ad-hoc ленивости, это да.
                      +1
                      >Во-первых, описание типов в Хаскелле — это половина стадии проектирования программы.

                      Ну так, по-другому там просто нельзя, физически.

                      >Лиспу в корне чужда такая идеалогия — а, вы можете построить свою систему для описания и верификации ADT, свои классы типов, загнать всё в макросы и заставить выполняться во время компиляции, при этом отказавшись от большей части преимуществ самого Лиспа, но в таком случае зачем всё это?

                      Ну, не в макросы даже, а в compiler-макросы скорее. Хотя можно и в макросы. И это будет часть языка, по прежнему.

                      А вообще, да — нафиг оно не надо. Вот был проект Qi, так им никто не пользовался. Потому что «родной» стиль разработки гораздо удобнее, и отдавать динамику за гарантии того, что в рантайме мы ни в коем случае не сможем даже попытаться сложить баранов с телегами — крайне сомнительное удовольствие.

                      >Во-вторых, ленивость не сводится к потокам и замыканиям

                      Ок, к input-потокам и к замыканиям, не меняющим окружение. Я хотел это написать еще в статье, но подумал, что это очевидно.

                      >CL же со своей мультипарадигменностью не способен поддерживать декларативность на нужном уровне. Вернее технически то способен, но всё равно не поощрает.

                      Ну, декларативность и ленивость+чистота это ортогональные концепции.
                      Если нарисовать график, будет как-то так:

                                            процедурный       
                                                       ^                        
                                                        |
                      императивный <-----+------> декларативный
                                                        |
                                                        v
                                           функциональный
                      


                      Декларативность == описываем требуемый результат, а не то, как этот результат получить. Функциональный язык, даже чистый, вполне может быть и императивным(да я бы сказал, тот же хаскель, по большей части, и есть такой язык).

                      В лиспе декларативность обеспечивается макросами и CLOS.
                      Например, для того чтобы определить класс, нам по идее(и в кишках CLOS это и происходит) надо
                      сделать как-то так:
                      (setf (find-class class-name)
                              (make-instance metaclass-metaobject
                                                       :name class-name
                                                       :direct-superclasses (list superclass1-metaobject
                                                                                               superclass2-metaobject ...)))
                      

                      и это императивный путь.

                      Но в реальности, мы обычно пишем в файле как-то так:
                      (defclass class-name (superclass1 superclass2 ...)
                        (...)
                        (:metaclass metaclass-name))
                      

                      И вот это — декларативно.

                        0
                        отступы в <source> сбились почему-то
                        ну, и так понятно
                          +5
                          Понял вашу идею, но я немного про другое определение императивности/декларативности (русская Википедия, кстати, говорит о двух разных определениях декларативного языка). На мой взгляд, основные характеристики императивного программирования — это:

                          1. Наличие состояния объекта.
                          2. Описание программы в виде последовательности действий.

                          В противовес этому, декларативное программирование — это:

                          1. Отсутствие состояния.
                          2. Описание программы в виде фактов (констант, значений, собственно фактов, как в Прологе) и отношений между ними (логических, математических).

                          То есть, например, если вы пишете факториал на Java, вы даёте компьютеру инструкции: «циклически повторяй: умножь переменную result на n, затем уменьши n на единицу, если n > 1 — повтори» и т.д. Если же пишете на Haskell, например, то это будет что-то вроде: «факториал от 1 равен 1, факториал от числа n > 1 равен этому n, умноженному на факториал (n — 1)». В первом случае у вас есть 2 переменные result и n, которые хранят состояние на данный момент выполнения. Во втором — вы просто описываете некое отношение между вещественными числами и называете это отношение factorial. В конце вы говорите компьютеру вычислить для вас факториал числа 100, но не составляете для него какого-то конкретного списка действий — вы даёте ему свободу сделать это любым удобным для него способом (не на физическом уровне — там, ествественно, всё жёстко прописано, но на логическом). Компьютер при этом может действовать как математик — посмотреть, что ему нужно для вычисления того, что попросили, начать вычислять это, не вычисляя рядом стоящие, но ненужные задачи (например, другие аргументы функции). Математик не создаст побочных эффектов — всё, что он делает, — это вычисляет. Математик не изменит начальные данные, так что другие математики могут не беспокоиться за корректность своих собтсвенных вычислений над теми же данными.

                          Так вот, к чему я всё это. Common Lisp плох для такого декларативного, математического описания задачи. На Common Lisp вы не можете позволить компьютеру вычислять некое значение тем способом, который он сам выберет. Последовательность действий важна. Возможны побочные эффекты. Начальные данные могут меняться. Всё это сильно ломает допущения, принятые в чистом функциональном программировании, а значит делает более выгоднями другие средства (например, повторное использование структур данных вместо мемоизации). Это не хорошо и не плохо, это — другая парадигма. Common Lisp её не поощрает, и поэтому, увы, не сильно поможет при изучении Haskell.

                          А вообще очень хороший обзор возможностей различных языков, конечно же, представляет MIT-овский курс 6.001. Ну, тот, старый, который ещё на Scheme. Вот там и ленивые вычисления, и обычные, и императивное, и декларативное, и объектно-ориентированное, и мета-программирование, и чего только не описано. Теории категорий, правда, нет, ну да ладно :)
                            +1
                            но я немного про другое определение императивности/декларативности
                            Да, я понимаю. Это определение почему-то очень распространено в ф.п.-кругах, и почему-то считается там за единственное верное определение декларативности. Почему они узурпировали определение декларативности и связали его с функциональщиной — мне непонятно.

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

                            >«факториал от 1 равен 1, факториал от числа n > 1 равен этому n, умноженному на факториал (n — 1)»
                            Ну вот это то, что я бы назвал функциональным, но императивным подходом. Тут есть конкретный алгоритм. Да, нет циклов, нет изменяемого состояния, но есть описание последовательности необходимых вычислений.
                            Декларативно будет — «факториал это произведение числе от 1 до n»

                            Декларативность может быть и процедурная.
                            Пример — SQL INSERT. Мы не описывает алгоритм вставки, мы говорим, что нам надо вставить и куда, и всё. Побочные эффекты есть, ничего не вычисляется, как функция, но производятся некоторые действия. Тем не менее, это декларативная конструкция.
                            Или тоже еще один пример — Make. Makefile — описание последовательности действий, но описание декларативное.

                            Вобщем, декларативность, как я уже сказал, это описание требуемого результата, и поэтому, кстати, ни один язык общего назначения полностью декларативным быть не может.
                            Полностью декларативными могут быть только языки разметки и всякие DSL.
                              0
                              Как приятно слушать рекомендации прочесть SICP от человека который прочел SICP и ничего не понял. Наверное не дочитал до 4й главы.

                              Именно в словах кроется магия — в таких, как «абракадабра», «Сезам, откройся» и проч., — но магические слова из одной истории перестают быть таковыми в следующей. Настоящая магия состоит в том, чтобы понять, когда и для чего слово сработает; трюк в том, чтобы выучить трюк. А слова эти состоят из букв нашего алфавита: пара дюжин закорючек, которые мы способны черкнуть пером. Вот где ключ! И сокровище тоже, если только мы сумеем его заполучить! Как будто… как будто ключ к сокровищу и есть само сокровище!

                              Суть лиспа заключается в том что это просто средство которое придает абсолютно любой структуре данных абсолютно любую семантику и затем производит вычисление в соответсвии с этой семантикой. Т.е. лисп фактически описывает любую задачу чисто декларативно и позволяет компьютеру вычислить некое значение тем способом который он сам выберет. В оригинальном лиспе хочу заметить любая «чисто императивная» программа имела природу чисто декларативной программы потому что любая такая программа фактически была иммутабельной структурой данных которая преобразовалась в другую иммутабельную структуру данных чистыми функциями в соответствии с семантикой императивных вычислений.
                                0
                                Ого, на пороге 2016 года получить ответ на коммнетарий 2011-ого — это почти что машина времени.

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

                                В общем, давайте не заморачиваться, а лучше пить шампанское и планировать следущий год ;)
                          +9
                          слишком много фанатизма.
                            +3
                            Перечитал пост, фанатизма не нашел. Автор рекомендует изучить новый инструмент, аргументируя и приводя его достоинства. В утверждении «Лучше быть умелым и умным, чем программистом на одном языке» — тоже слишком много фанатизма?
                              0
                              >Автор: love5an

                              Это как-бы намекает нам. Это же главный лиспер ЛОРа!
                                0
                                когда это им стал? :)
                              –10
                              Проблема с CL/хаскелем и прочим, что это скорее академические языки, и люди, которые пишут про них статьи, пишут такую забористую хрень, что ее понять не могу иногда даже я.

                              Вот из википедии например:

                              > Алгебраи́ческий тип да́нных — в теории программирования любой тип, значения которого являются значениями некоторых иных типов, «обёрнутыми» конструкторами алгебраического типа

                              Это же скороговорка для разминания языка, вроде How many wood would a woodchuck chuck.

                              А если бы писали нормально, понять бы было в разы легче. Ничего необычного и сложного в замыканиях, ленивых вычислениях или списках нет. Это интересные подходы, конечно, когда они описаны нормальным языком (чего я еще не видел). И, конечно, важно давать примеры реализации (например, взяв обычную функцию из Си, и разместив локальные переменные не в стеке, а в куче, мы легко получаем из функции замыкание. Прибавив сюда указатель на объект, получаем делегат, ну а список делается через хранниее указателя на следующий элемент, и т.д).

                              А еще, как я понимаю, у академических языков плохо с производительностью. Например, реализация массива или хеш-таблицы на чистом лиспе подразумевает использование списка внутри, а поиск по списку — вещь весьма неспешная. Что-то я не вижу на Лиспе ни ORM, ни шаблонизаторов, ни систем виджетов.
                                +10
                                >Проблема с CL/хаскелем и прочим, что это скорее академические языки

                                Хаскель — да, но CL — нет. Это как раз наиболее практичный и наименее академический из всех диалектов лиспа. Это промышленный стандарт, ANSI INCITS 226-1994 (R2004), созданный, причем, на деньги американских военных(DARPA — они бы не стали вкладываться в академический язык).

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

                                У академических — возможно, у CL — нет. Все основные реализации CL компилируют в машинный код, а ведущие реализации могут по производительности сравниться с java -server или даже с Си и С++.

                                >Например, реализация массива или хеш-таблицы на чистом лиспе подразумевает использование списка внутри, а поиск по списку — вещь весьма неспешная.

                                В CL хэш-таблицы и массивы есть в стандартной библиотеке.

                                >Что-то я не вижу на Лиспе ни ORM, ни шаблонизаторов, ни систем виджетов.

                                А они есть.

                                «Не видно» их потому, что язык, по сравнению с мейнстримом типа C++, PHP или Java — распространен невероятно мало.
                                  +6
                                  Брр, бред. Вообще, судя по значку «Тролль» в вашем профиле, мне не следовало бы отвечать, но по поводу отдельных высказываний всё-таки отвечу, чтобы наивный читатель не получил такое заблуждение.

                                  Про академичность — смотрите «Практику функционального программирования», там куча примеров промышленного использования. Плюс статьи Пола Грэма, плюс поиск по языку на GitHub и т.д. Так что языки вполне себе активно используются.

                                  Про хэш таблицы — в Common Lisp из коробки, мутабельны; в Scheme/Racket — из коробки, как мутабельные, так и немутабельные; в в Clojure — из коробки, немутабельны, плюс джавовские мутабельные, плюс куча других мэпов. Даже немутабельные мэпы реализованы эффективно и поддерживают стандартные операции за то же O(1) время. Никаких списков.

                                  Про ORM: habrahabr.ru/blogs/programming/130617/
                                  Про шаблонизаторы: lib.store.yahoo.net/lib/paulgraham/bbnexcerpts.txt

                                  Про всё остальное: Гугль.
                                    +5
                                    Это ответ на сообщение уровнем выше, конечно же.
                                    0
                                    Haskell — тоже нет, в общем-то. Вот Agda, Coq, Isabelle, Epigram — да, академические языки (хотя читал я о проекте, в котором web писался на Agda); Haskell же — наиболее практичный из функциональных.
                                  +5
                                  «причиной наличия в хаскеле всей этой шелухи с типами...»
                                  Шелуха с типами, говорите? Видимо, теория категорий и высшая алгебра — тоже шелуха. Как и такие незначительные преимущества строгой типизации, как:
                                  • Повышение производительности программ
                                  • Отлов огромного количества ошибок: например, вот таких.
                                  • Облегчение отладки, тестирования и сопровождения программ
                                  • Типы — это очень мощная система документации. По типу функции и её названию чаще всего можно догадаться, что она делает

                                  Ну, и наконец, выведение типов позволит вам избавиться от лишней писанины, а хорошая IDE — легко посмотреть тип любого значения.
                                  Но возможность переизобрести велосипед с квадратными колёсами на LISP'е, видимо, гораздо ценнее всего этого.
                                  //Не имею ничего против LISP'а как такового. Имею — против излишнего фанатизма.
                                    +2
                                    > Видимо, теория категорий и высшая алгебра — тоже шелуха.

                                    Нет. Но дело в том, что к хаскелю они имеют весьма отдаленное отношение.

                                    > Повышение производительности программ

                                    Сама по себе статическая типизация этого не гарантирует.
                                    Но в CL, кстати, есть опциональные декларации типов, вот почитайте, там внизу, какой код ведущие компиляторы могут генерировать:
                                    love5an.livejournal.com/357147.html

                                    >Отлов огромного количества ошибок: например, вот таких.

                                    Я не вижу там ссылок на то, что статическая типизация помогает отловить такие ошибки.
                                    Вообще, это wishful thinking.
                                    Такие ошибки ловятся, если вообще ловятся, сложными статическими анализаторами кода, а не тупым хиндли-милнером. Статическая типизация не предотвращает от ошибок сложнее «случайно складываем слонов с китами», она не спасает от опечаток, не нарушающих типизацию, она не спасает от ошибок в логике, а последних двух типов ошибок — большинство.

                                    >Облегчение отладки, тестирования и сопровождения программ
                                    По сравнению с чем? С Си? C++? Возможно. Возможно даже с питоном.
                                    Но по сравнению с CL — ни в коем случае. Вы просто не пробовали разрабатывать код на CL(это видно по неправильному устаревшему написанию «LISP»), в SLIME, например — ни один статический язык с ним по удобству разработки, отладки и тестирования не сравнится.

                                    >Типы — это очень мощная система документации. По типу функции и её названию чаще всего можно догадаться, что она делает
                                    Об этом гораздо лучше можно догадаться по имени функции и прикрепленному докстрингу, подробно описывающему назначение функции и ее аргументов.

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

                                    >а хорошая IDE — легко посмотреть тип любого значения.
                                    SLIME(см. мой предыдущий постинг) может и это, и даже большее, и ему для этого статическая типизация, как можно понять, не нужна.
                                      +2
                                      Нет. Но дело в том, что к хаскелю они имеют весьма отдаленное отношение.

                                      У Хаскелля, например, есть своя категория. Да и вообще.
                                      У меня есть небольшой примерчик, как легко и просто в Хаскелле можно определить алгебраические структуры, вроде кольца, с помощью typeclass'ов. Я уж молчу про то, что всё это можно применить, например, к тестированию программ. Я как раз пишу дипломную работу на эту тему ^_~

                                      Сама по себе статическая типизация этого не гарантирует.

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

                                      Я не вижу там ссылок на то, что статическая типизация помогает отловить такие ошибки.

                                      Главное правильно её готовить. Подобное поведение можно реализовать и с помощью АТД или классов.

                                      тупым хиндли-милнером

                                      Мне уже дурновато становится от количества НЕНАВИСТИ к статической типизации, которую вы продуцируете. ^_~

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

                                      Я не видел статистики по этому поводу. Опечатка, не нарушающая типизацию — не думаю, что это действительно многочисленный класс ошибок. Надо исхитриться, что называется.
                                      Ошибки в логике, говорите?

                                      Но по сравнению с CL — ни в коем случае. Вы просто не пробовали разрабатывать код на CL(это видно по неправильному устаревшему написанию «LISP»), в SLIME, например — ни один статический язык с ним по удобству разработки, отладки и тестирования не сравнится.

                                      Я повторяю — я не против LISP'а. Просветите же меня, грешного, чем же мне поможет динамическая типизация в отладке, тестировании и сопровождении? Именно она, а не весь LISP.

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

                                      Что не отменяет того факта, что типы являются автоматически генерируемой частью документации в языке с выведением типов. Масла много не бывает :)

                                      А когда у нас динамическая типизация, ее просто изначально нет.

                                      Как нет и преимуществ статической типизации, перечисленных выше.

                                      Поймите, я рад, что вы увлечены LISP'ом (да, мне привычно писать так) и пытаетесь просветить окружающих. Но не надо думать, что одного вашего увлечения хватит, чтобы решить спор, который длится уже ооооочень долго. На данный момент, для разработки сложных систем статическая типизация необходима. Для работы с гетерогенными данными — тоже. Для изучения алгоритмов и теоретических исследований — в большинстве случаев она удобнее. Я не претендую на то, что моё мнение — единственное и абсолютно верное. Но я увлечён и занимаюсь именно этой частью computer science и пока для меня всё выглядит как-то так.
                                        0
                                        У меня есть небольшой примерчик, как легко и просто в Хаскелле можно определить алгебраические структуры, вроде кольца, с помощью typeclass'ов. Я уж молчу про то, что всё это можно применить, например, к тестированию программ. Я как раз пишу дипломную работу на эту тему ^_~


                                        А можно этот примерчик в студию? Меня более всего интересует проверка аксиом (ассоциативность операций, наличие нейтральных элементов, наличие обратных по сложению, невырожденность). Желательно, конечно, не QuickCheck'ом, как у Пипони, а с помощью системы типов.
                                          0
                                          Это всего лишь proof of concept. Цель была — сделать универсальный вычислитель выражений для выражений, определённых над кольцами. Проверки аксиом нет посему. Но пример для демонстрации type class'ов неплохой.
                                            0
                                            Это мило, но не очень интересно в смысле защиты статической типизации. Сколько-нибудь полноценная символьная алгебраическая система на Haskell получается несколько cumbersome — как, например, DoCon. CAS без статической проверки аксиом без особого труда можно сделать и на C++.
                                              0
                                              Ну, полноценные системы всегда получаются «cumbersome» ^_~
                                                0
                                                В рамках обсуждения цель использования высокоуровневых языков как раз в улучшении данной систуации, n'est-ce pas?
                                                  0
                                                  Ситуация улучшается, но мы ещё далеки от идеала ^_~
                                      0
                                      Ну, не знаю. Излишняя типизация, по-моему, тоже вредна. Производительность в том же Clojure, о котором упоминали выше, достигается за счет проставления небольшого числа аннотаций в коде. Причем подход в этом случае сугубо прагматичный: запускаем профайлер, находим узкие места, расставляем аннотации, повторяем. Обычно одного раза хватает, чтобы по производительности приблизиться к Java -server. Причем, даже не делая этого, мы получаем достаточно солидную скорость.

                                      Насчет пунктов 2 и 3 советую посмотреть презентацию Rich Hickey с StrangeLoop 2011. Там он как раз и говорит о том, что ни типы, ни тесты, не панацея. У всех наших багов есть одно уникальное свойство: они проходят все тесты и не ловятся компилятором. Типизация как защита от ошибок — переоцененное преимущество. На собственном опыте разработки на JavaScript могу сказать, что ошибки типизации возникают только на очень-очень ранних этапах работы с языком и пропадают уже после пяти дней использования.

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

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

                                      Лучшие IDE всегда были для Smalltalk — языка с динамической типизацией. Там понятия «среда разработки» и «среда выполнения» тождественны. Значит, вы можете в работающей системе заглянуть внутрь, осмотреть граф объектов и изменить фрагменты кода, чтобы исправить ошибку. Ни один современный язык вам не даст такой свободы.

                                      Думать о типах? Я думаю о решении задачи. Типы даже в Java или C# — вторичный продукт.
                                      +3
                                      В 6-м классе дали на одну ночь почитать настоящую инструкцию к MS DOS 3.3 на английском которую успел законспектировать шариковой ручкой в тетрадку в клеточку… Это помогло в некоторой мере осознать, что в мире есть что-то более школьного BASIC Вильнюс-86, и в мечтах представить зачем это может быть нужно. Со временем пришли в мою жизнь Turbo Pascal, Delphi, C++ Builder, Java, FreeBSD/Linux/HP-UX, OpenVMS, Cisco, Python, Mac OS, Objective C и еще много других слов. Теперь вот еще и LISP, обходимый ранее стороной, кажется привлекательным для того, чтобы уделить ему часть «процессорного времени».

                                      К чему это я? У каждого свой путь к «прозрению», дающему вдохновение и любовь к избранному делу. Возможно, автор статьи 'споткнувшись' на своем пути о Common Lisp расширил и систематизировал свои знания, таким образом увидя в нем краеугольный камень программирования как науки. Однако, есть определенные сомнения по поводу того, что каждый освоивший CL получит сравнимое удовольствие. Ведь признавать MS DOS 3.3 сейчас моим сокровенным путем к познанию Истины несколько комично, особенно учитывая мнение об отсутствии ее теоретической достижимости.

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

                                      В наши дни оружия массового поражения в виде Java и PHP, отрадно видеть самураев с Lisp, Haskell и Prolog в ножнах — значит есть еще цели для них.
                                        +2
                                        Очень пафосно и красиво, но по существу можно было сказать и короче :)
                                        Однако мысль, которую хочет продвинуть автор топика вероятно (поправьте если ошибаюсь) ускользнула от вас.

                                        Позволю себе напомнить: «все мейнстримные языки, и в особенности, объектно-ориентированные, являются подмножествами CL». И это действительно так, чтобы понять это — стоит уделить немного «процессорного времени» лиспу.
                                        0
                                        По сути, всё правильно, но вот Haskell поливать было совершенно незачем. Сам сейчас пишу на Racket, ибо я — перфекционист, и мне подавай чистоту и порядок, даже в именовании функций. Но к Common Lisp отношусь с любовью, т.к. иногда пишу и на нём, и прочитал Practical Common Lisp — чего и всем остальным желаю, если кто ещё не знаком с CL.
                                        Судя по некоторым комментариям, мифы о Lisp до сих пор в ходу, один из самых забавных — дескать, разрабы компиляторов такие дураки, что хеш-таблицы не догадались сделать нативно, а реализовали через списки. Спасибо, поржал.
                                        Ну и, подобно автору, призываю изучать Common Lisp — язык изумительный, и очень даже стоит того, чтобы потратить время на его изучение. Просто забудьте про мифы и читайте книги.
                                          0
                                          > Сам сейчас пишу на Racket, ибо я — перфекционист, и мне подавай чистоту и порядок, даже в именовании функций.

                                          Хм, а что мешает в других языках именовать все ясно и по конвенции?
                                            0
                                            Мне — ничего, что-то мешает авторам языков (:
                                            Просто во всех стандартных библиотеках Racket именование функций и прочих сущностей подчиняется строгим правилам — например, мутирующие функции оканчиваются на "!", а предикаты — на "?": set!, reverse!, eql?, equal?, number?.. В Common Lisp с порядком хуже: setf, nreverse, eql, equalp, numberp. Да и окончание предикатов на «p» как-то не смотрится.
                                            Впрочем, это всё не настолько страшно, просто Racket мне пока нравится больше. В конце-концов, Lisp я изучаю всего около полугода, и мне проще пока с Racket, благо там библиотек из коробки навалом.
                                              0
                                              Clojure?
                                                0
                                                Может быть, когда-нибудь. Я пока ещё далёк от Java и прочих JVM-based технологий.
                                          +2
                                          Почему-то угадал автора после первых 2 абзацев. Второго настолько упоротого, невежственного и агрессивного фанатика CL в русском коммьюнити просто нет.
                                            0
                                            У тебя все в порядке, чувак?
                                            Просто ты мне это уже раза два писал в juick, и даже вроде в жж.
                                            Выпей транквилизаторов каких чтои, не знаю.
                                              0
                                              Ты уже допилил стартап свой?
                                                0
                                                Пилю
                                            0
                                            Как-то вы макросы совсем вниманием обошли.
                                            Я сколько ни гуглил на эту тему, но никак не развил нужную способность.

                                            Only users with full accounts can post comments. Log in, please.