LINUX.ORG.RU

Зачем нужны динамические языки?


0

0

Собственно не пойму. Вроде обещают более быструю разработку, но за счет чего? За счет того, что не надо писать тип при объявлении переменной? Так это ведь глупость, никакой скорости разработки это не добавит. Естественно, такие языки можно использовать только для прототипирования, но не проще ли сразу использовать язык, который обеспечит и скорость разработки и скорость выполнения, тем более, что динамический язык принципиально нельзя ускорить (имеется ввиду компилятор)? (я имею ввиду современные языки с выводом типов)

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

>> Макры из функций вызывать вроде можно. А функции из макр?
> Конечно.


Тогда всё не так плохо :)
А чем они тогда различаются кроме иллюзорной грани comiple-time/run-time? Иллюзорной потому, что компиляторы нынче умные, а всё, что может быть вычислено во время компиляции не все программисты так обозначат.

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

> кстати, никто ещё не додумался реализовать CL (или хотя бы CLOS) на Tcl? было бы забавно

XOTcl вроде бы с CLOS-а срисовывали.
К слову, а что в них такого разного? Меняй круглые скобки на квадратные и всего делов :) Шучу, конечно, но сикповские упражнения почти символ-в-вимвол можно на Tcl переписать.

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

>Но дело-то свое он сделал.

главня фишка JHC не в том, что он генерит C, а в том - как он это делает. не думаю что CFront когда-нибудь был эффективней современного GCC

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

>XOTcl вроде бы с CLOS-а срисовывали

а ядрёное OO в Tcl 8.6 срисовали с XOTcl :) жаль, мне всегда был более по нраву Snit

>К слову, а что в них такого разного?

AST против текста. списки против строк. в остальном всё то же самое

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

>> XOTcl вроде бы с CLOS-а срисовывали
> а ядрёное OO в Tcl 8.6 срисовали с XOTcl :) жаль, мне всегда был более по нраву Snit


Емнип, от снита в нём тоже многое осталось. В любом случае, кто ж нам запретит снитом пользоваться, это ж не педон какой-нибудь ;)

>> К слову, а что в них такого разного?

> AST против текста. списки против строк. в остальном всё то же самое


Мне категорически интересно, есть ли в лиспе [info body]. А то в вики пишут, что этой фичи тикля у лиспа нет.

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

> Мне категорически интересно, есть ли в лиспе [info body]. А то в вики пишут, что этой фичи тикля у лиспа нет.

Нету. Исходник за собой CL не таскает.

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

>> Мне категорически интересно, есть ли в лиспе [info body]. А то в вики пишут, что этой фичи тикля у лиспа нет.
> Нету. Исходник за собой CL не таскает.


Ушёл лопаться от гордости :D

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

> А чем они тогда различаются кроме иллюзорной грани comiple-time/run-time?

Ну нифига себе! :)

> Иллюзорной потому, что компиляторы нынче умные, а всё, что может быть вычислено во время компиляции не все программисты так обозначат.

Вот этим и отличается: макросы генерят текст программы (в том числе), а функции не генерят.

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

> Ушёл лопаться от гордости :D

А как вообще из чисто машинного кода можно достать исходный текст? %) Лисп (мой любимый SBCL) - обычный, достаточно эффективный компилятор в маш.код.

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

> главня фишка JHC не в том, что он генерит C, а в том - как он это делает

Как знать, как знать... ИМХО, JHC выполняет только ФП-специфичные оптимизации. Это такой извращенный способ подключиться к бэкенду GCC. Им просто в падлу было писать компилятор Хаскеля на Си :)

> не думаю что CFront когда-нибудь был эффективней современного GCC

Cfront был настолько эффективен, насколько был эффективен компилятор второй стадии. В Си++ того времени просто не было специфичных оптимизаций.

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

>Как знать, как знать... ИМХО, JHC выполняет только ФП-специфичные оптимизации. Это такой извращенный способ подключиться к бэкенду GCC. Им просто в падлу было писать компилятор Хаскеля на Си :)

GHC тоже может выдать код на C; у JHC это получается несколько лучше

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

>А чем они тогда различаются кроме иллюзорной грани comiple-time/run-time?
Отличий фактически только два - они раскрываются при компиляции и не вычисляют свои аргументы.
А внутреннюю функцию макроса можно получить через (macro-function macro-name)

guest-3484-2009
()
Ответ на: комментарий от mv

> А как вообще из чисто машинного кода можно достать исходный текст? %) Лисп (мой любимый SBCL) - обычный, достаточно эффективный компилятор в маш.код.

Я привык разделять выразительные и производительные языки. И лисп тут не исключение.

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

> Вот этим и отличается: макросы генерят текст программы (в том числе), а функции не генерят.

Тогда определи, что значит "генерят текст программы". Я добавление новых языковых структур и без макр делать умею на eval/uplevel.

gaa ★★
()
Ответ на: комментарий от guest-3484-2009

>> А чем они тогда различаются кроме иллюзорной грани comiple-time/run-time?
> Отличий фактически только два - они раскрываются при компиляции и не вычисляют свои аргументы.


Кто мешает функциям '(аргументы) не вычислять? И кто мешает оптимизирующему компилятору раскрывать то, что не помечено как макра?

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

На самом деле есть в стандарте есть функция function-lambda-expression, но она implementation-dependent, в том же SBCL она всегда выдает NIL. В CLISP она работает, но при компиляции дефинишн тоже теряется. Но если уж хочется, никто не запрещает написать такое:

guest-3484-2009
()
Ответ на: комментарий от guest-3484-2009

Или даже не defun-extended, а просто defun переназначить (а внутри соответственно вставить cl:defun)
И, к примеру, перекомпилировать библиотеки/другой код, чтобы оттуда определения тоже сохранились.

guest-3484-2009
()
Ответ на: комментарий от guest-3484-2009

> На самом деле есть в стандарте есть функция function-lambda-expression, но она implementation-dependent, в том же SBCL она всегда выдает NIL.

Значит на неё надеяться нельзя.

> В CLISP она работает, но при компиляции дефинишн тоже теряется. Но если уж хочется, никто не запрещает написать такое:


А поддерживать актуальность содержимого хеш-таблицы лично МакКарти будет?

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

> Тогда определи, что значит "генерят текст программы". Я добавление новых языковых структур и без макр делать умею на eval/uplevel.

(defmacro foo (op &rest args)
  (cond ((stringp op)
     `(format nil "~{~a ~}" ',args))
    ((numberp op)
     `(+ ,@args))
    (t (error))))

(foo 1 2 3)
=> 5
(foo "say" "hello" "motherfucker")
=> "hello motherfucker "
(foo 'bar)
=> error

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

> А поддерживать актуальность содержимого хеш-таблицы лично МакКарти будет?

А что с ней может случиться?

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

>> А поддерживать актуальность содержимого хеш-таблицы лично МакКарти будет?
> А что с ней может случиться?


В неё может что-то не записаться. Как я понял, это обёртка к defun.

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

>И кто мешает оптимизирующему компилятору раскрывать то, что не помечено как макра?
Если вы про инлайн, то он не гарантирован даже в лиспе. С другой стороны, можно написать макрос, с использованием того же once-only, который бы работал как гарантированно инлайнящаяся функция.

>Кто мешает функциям '(аргументы) не вычислять

Очень красиво получится, ага.
(with-open-file `(in ,(get-filename) :direction :output :if-exists ,(what-to-do-if-exists)) `(write ,(get-data) in))
Какие тут синтаксические абстракции?
И к тому же, это будет в рантайме. Оверхед неслабый, однако. Ну и мелочи, вроде того, что макросы поддерживают вложенные списки агументов.

guest-3484-2009
()
Ответ на: комментарий от gaa

> В неё может что-то не записаться. Как я понял, это обёртка к defun.

Это захват имени defun в текущем пакете. Всё, что через него пройдёт, попадёт в хэш.

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

> Макрос в зависимости от типа первого аргумента выдаёт тот или иной текст программы.

За разъяснение спасибо, но определения отличий я так и не увидел.

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

> За разъяснение спасибо, но определения отличий я так и не увидел.

Если под отличиями понимается твоё вот это:

> Тогда определи, что значит "генерят текст программы".

...то пример показывает, как макрос генерит текст программы. Что такое генерация и текст программы по отдельности понимаешь? Вот, а их сочетание даёт непосредственно подразумеваемый смысл - макрос на выходе вместо себя даёт текст программы, который потом съест компилятор :)

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

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


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

gaa ★★
()
Ответ на: комментарий от guest-3484-2009

>> И кто мешает оптимизирующему компилятору раскрывать то, что не помечено как макра?
> Если вы про инлайн, то он не гарантирован даже в лиспе. С другой стороны, можно написать макрос, с использованием того же once-only, который бы работал как гарантированно инлайнящаяся функция.


Не про него. А про то, что такое разграничение может помешать возможным оптимизациям.

> И к тому же, это будет в рантайме. Оверхед неслабый, однако.


Я уже говорил про выразительные и эффективные языки.

> Ну и мелочи, вроде того, что макросы поддерживают вложенные списки агументов.


А что в этом такого особенного?

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

> Ладно, код мы получили. Теперь давайте его перестроим и всунем куда-нибудь в другую функцию, ведь он нам не просто для любования даден.

Давайте :) Что с ним делаем и как именно встраиваем? :)

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

>> Ладно, код мы получили. Теперь давайте его перестроим и всунем куда-нибудь в другую функцию, ведь он нам не просто для любования даден.
> Давайте :) Что с ним делаем и как именно встраиваем? :)


Ну пусть добавляем на каждую строчку логгинг информации о том, сколько раз она проходилась. Эдакий coverage tool.
Или добавляем время начала/время конца для профилирования.
Или брейкпоинт шмякаем.

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

>> Тогда определи, что значит "генерят текст программы".
> ...то пример показывает, как макрос генерит текст программы. Что такое генерация и текст программы по отдельности понимаешь? Вот, а их сочетание даёт непосредственно подразумеваемый смысл - макрос на выходе вместо себя даёт текст программы, который потом съест компилятор :)


Ну и чем оно отличается от

(if (= param 1)
(lambda (x)
(echo x " -- jopa"))
(lambda (x)
(echo x " -- not jopa")))

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

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

>Я уже говорил про выразительные и эффективные языки.
Вот именно, лисп позволяет выразительность и эффективность совмещать.
>А что в этом такого особенного?

Удобно. И аргументы проверяет рантайм.
(defmacro my-macro ((arg1 arg2 &rest first-form-args) (arg3 (arg4) &rest second-form-args) &rest rest) `(do-something ...))

ср. with-open-file
(defmacro with-open-file ((var filename &rest open-args) &body body) ...)
и так вот:
(defmacro with-open-file (open-spec &body body)
(assert (and (listp open-spec)
(>= (length open-spec) 2)
(symbolp (car spec)))
"With-open-file: invalid form")
...)

guest-3484-2009
()
Ответ на: комментарий от gaa

> Ну пусть добавляем на каждую строчку логгинг информации о том, сколько раз она проходилась. Эдакий coverage tool. Или добавляем время начала/время конца для профилирования. Или брейкпоинт шмякаем.

Отлично. Я щас домой потопал, но вечерком напишу :)

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

Тем, что лямбды не генерирует.
Макросы они, опять же повторю, для синтаксических абстракций.
Вот, например, loop:
(25 первых чисел фибоначчи)

(loop repeat 25
      for a = 0 then b
      and b = 1 then (+ a b)
      collect b)

в SBCL раскрывает в:

(BLOCK NIL
  (LET ((#:LOOP-REPEAT-629 (CEILING 15)) (A NIL) (B NIL))
    (DECLARE (TYPE INTEGER #:LOOP-REPEAT-629))
    (SB-LOOP::WITH-LOOP-LIST-COLLECTION-HEAD
     (#:LOOP-LIST-HEAD-630 #:LOOP-LIST-TAIL-631)
     (SB-LOOP::LOOP-BODY NIL
                         ((IF (<= #:LOOP-REPEAT-629 0) (GO SB-LOOP::END-LOOP)
                              (DECF #:LOOP-REPEAT-629))
                          NIL
                          (SB-LOOP::LOOP-REALLY-DESETQ A
                                                       (PROG1 0
                                                         (SB-LOOP::LOOP-REALLY-DESETQ
                                                          B 1)))
                          NIL NIL)
                         ((SB-LOOP::LOOP-COLLECT-RPLACD
                           (#:LOOP-LIST-HEAD-630 #:LOOP-LIST-TAIL-631)
                           (LIST A)))
                         ((IF (<= #:LOOP-REPEAT-629 0) (GO SB-LOOP::END-LOOP)
                              (DECF #:LOOP-REPEAT-629))
                          NIL
                          (SB-LOOP::LOOP-REALLY-DESETQ A
                                                       (PROG1 B
                                                         (SB-LOOP::LOOP-REALLY-DESETQ
                                                          B (+ A B))))
                          NIL NIL)
                         ((RETURN-FROM NIL
                            (SB-LOOP::LOOP-COLLECT-ANSWER
                             #:LOOP-LIST-HEAD-630)))))))

(учитывая, что sb-loop::... это тоже макросы)

guest-3484-2009
()
Ответ на: комментарий от jtootf

> и что, это скомпилируется в эффективный код?

Если указать тип a и b, а также сказать компилятору: "оптимизируй", то да, вполне прилично.

mv ★★★★★
()
Ответ на: комментарий от guest-3484-2009

> Тем, что лямбды не генерирует.

Две различных версии кода в зависимости от входных данных. После единовременного выполнения может использоваться без накладных расходов.

> Макросы они, опять же повторю, для синтаксических абстракций.


А я тоже повторю, что синтаксические абстракции можно и без макр ваять.

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

>> и что, это скомпилируется в эффективный код?
> Если указать тип a и b, а также сказать компилятору: "оптимизируй", то да, вполне прилично.


На первые 25 чисел Фибоначчи он должен соптимизироваться в puts "1 1 2 3 5 8 13..." :)

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

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

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

Например, рассмотрим f(a,b) <====> a.b допустим даже на С, а еще лучше на С++. Попробуй формализуй, какому типу принадлежит b !

Понятно, что макросы таких проблем не имеют.

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

>Например, рассмотрим f(a,b) <====> a.b допустим даже на С, а еще лучше на С++

я иероглифа в форме стрелочки не понял. это что такое?

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

> я иероглифа в форме стрелочки не понял. это что такое?

#define f(a,b) a.b

Теперь попробуй описать это функционально, для чего придется выяснить, какой у b тип.

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

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

Ну вот и расскажи, зачем тебе динамика на tcl. (gaa мне дал парочку примеров, там она для метапрограммирования, которое я бы делал вполне типобезопасно по-другому). Так что отрисуй несколько примеров на тикле.

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

> Т.е., на данный момент, Хаскелль - это такая же маргинальщина для мейнстрима, как и CL? С неясным будущим, при том...

Да. Читай Being Lazy With Class и сделай свои выводы.

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

> Ну пусть добавляем на каждую строчку логгинг информации о том, сколько раз она проходилась. Эдакий coverage tool.
> Или добавляем время начала/время конца для профилирования.
> Или брейкпоинт шмякаем.

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

(defun baz (x)
  (multiple-value-bind (name args body)
      (values-list (cdr (read-from-string x)))
    (eval (read-from-string
       (format nil "(defun ~a ~a (time ~a))" name args body)))))

(baz "(defun bar (x) (+ x 2))")

(bar 1)

=> 3

Evaluation took:
  0.000 seconds of real time
  0.000000 seconds of total run time (0.000000 user, 0.000000 system)
  100.00% CPU
  781 processor cycles
  0 bytes consed
  

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

>Ну вот и расскажи, зачем тебе динамика на tcl

если ты про динамику в смысле скриптовости, то смотри ответ выше насчёт Bash. если про систему типов, то вот здесь хорошо сказано:

http://www.yosefk.com/blog/i-cant-believe-im-praising-tcl.html

>там она для метапрограммирования

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

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

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