LINUX.ORG.RU

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


0

0

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


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

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

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

Прекрасно в курсе, а вам надо было почитать тред, предже чем брызгать слюнями.
Generic fuctions из CLOS, "Object" в Java и .NET, COM из виндовз.

В хаскеле же его нет.

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

>надеяться на компилятор - последнее дело

Это, как раз, _первое_ дело. Последнее это переписывать на "низком" уровне -- если "первых" не хватило.

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

> Это, как раз, _первое_ дело. Последнее это переписывать на "низком" уровне -- если "первых" не хватило.

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

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

> На C++ пишете, наверное? Про низкий уровень я не писал, писал я про дырявые, глупые и бесполезные абстракции.

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

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

И заодно -- дырявыми абстракции могут быть, да. А вот где в нашей теме упоминались или хотя бы косвенно касались дырявых абстракций?

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

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

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

>> бесполезные абстракции

> Пожалуйста - карринг

O_o

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

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

>писал я про дырявые, глупые и бесполезные абстракции.

И что? Всё равно же "первое дело" -- быстро написать пользуясь максимально "толстыми" для данной задачи абстракциями, и пусть компилер соптимизирует. Не получится у компилера -- убираем самые неугодные руками. Скорее всего это менее эффективный путь только для какой-нибудь риалтаймовой эмбедовщины.

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

> Это такой вид неуклюжих костылей.

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

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

>> бесполезные абстракции

> Пожалуйста - карринг

Гость, объясни пожалуста, каким образом карринг -- абстракция (и от чего -- абстракция).

Народ, кто знает ответ из теории категорий -- пожалуста помолчите. Мне потом будет вас интересно послушать, но пусть гость скажет.

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

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

Верно. Не имеет отношения к дискуссии.

> Но это не гарантировано

Фишка в том, что в Хаскеле за счёт иммутабельности переменных можно проводить гораздо более серьёзные оптимизации. Поэтому Сишное представление о том, что нужно сделать для вызова функции, к Хаскелю неприменимо.

> И к тому же, надеяться на компилятор - последнее дело.

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

>> То, что полиморфизм бывает и рантаймовый - ты явно не в курсе. > Прекрасно в курсе, > Полиморфизм это прикрученные к статике задним числом кривые костыли

Как-то одно противоречит другому.

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

> Фишка в том, что в Хаскеле за счёт иммутабельности переменных можно проводить гораздо более серьёзные оптимизации.

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

НО:

При всем этом, функциональных подходов может быть МНОГО, и построены они д.б. на процедурщине, ограниченной мощной системой типов. А язык, в котором уже все строится на единственном варианте функциональщины -- в топку.

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

Раскрою тему:

При всем этом, функциональных подходов может быть МНОГО, например, не только полный запрет выполнения кода, а выполнение особого, верифицированного кода, и/или автоматическая генерация по этому коду другого кода для поддержки все-таки функциональной парадигмы (ведущей к линейности времени поиска).

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

> При всем этом, функциональных подходов может быть МНОГО, например, не только полный запрет выполнения кода, а выполнение особого, верифицированного кода, и/или автоматическая генерация по этому коду другого кода для поддержки все-таки функциональной парадигмы (ведущей к линейности времени поиска).

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

Ставим монаду IO - получаем произвольную императивщину; ставим монаду Identity - получаем отсутствие каких-либо сайд-эффектов; ставим State - получаем код, который дополнительно может писать в переменную (и читать из неё); ставим Writer - получаем код, ведущий логи... и т.п.

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

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

Я абсолютно НЕ это сказал. Даже если вдруг ты докажешь, что все мои подходы будут эквивалентны монадам, это не значит, что программировать будет удобно именно так.

Процедурщина позволяет сделать поверх себя *разную* фукциональщину, и я не собираюсь ограничиваться именно хаскель-монадной функциональщиной.

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

> Процедурщина позволяет сделать поверх себя *разную* фукциональщину

(пожимая плечами) А функциональщина - разную процедурщину, причём проще.

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

> (пожимая плечами) А функциональщина - разную процедурщину, причём проще.

1. А по-моему разной процедурщины вообще не бывает. Она одна, в отличие от функциональщины.

2. И в чем это проще? Развей тему.

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

>1. А по-моему разной процедурщины вообще не бывает. Она одна, в отличие от функциональщины.

а что значит "разная процедурщина", "разная функциональщина"? можно примеры разностей в функциональщине, которых не может быть в процедурщине?

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

>> 1. А по-моему разной процедурщины вообще не бывает. Она одна, в отличие от функциональщины.

> а что значит "разная процедурщина", "разная функциональщина"? можно примеры разностей в функциональщине, которых не может быть в процедурщине?

Кстати да, присоединяюсь к вопросу.

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

> Кстати да, присоединяюсь к вопросу.

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

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

>реализации процедурщины через функциональщину

слушай, в чём проблема-то? операционная семантика задаётся через State с двумя стеками (операции и результата) и таблицей памяти, синтаксический анализатор - пусть и не такой шустрый как в процедурном варианте,- но пишется без особых усилий (для LR(1) так и вообще генерируется). где сложности?

по сравнению с нутром boost.lambda - сказка. или ты с чем-то другим предлагаешь сравнить? с boost.mpl, например? с felix?

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

> по сравнению с нутром boost.lambda - сказка. или ты с чем-то другим предлагаешь сравнить? с boost.mpl, например? с felix?

boost.lambda делает то, что вы никоим образом не делаете -- дает возможность прозрачно подключить через указатели много чего есть на с++.

Полноценную реализацию функционального программирования на с++ (такой однако нет) можно было бы сравнивать только c реализацией хаскеля, который умел бы безопасно дергать с/с++ функции БЕЗ ffi.

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

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

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

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

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

> а что значит "разная процедурщина", "разная функциональщина"? можно примеры разностей в функциональщине, которых не может быть в процедурщине?

Я все же сегодня сделаю наборосок.

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

Однако создавать иллюзию и ограничивать средства можно существенно по-разному (в зависимости от специфики задачи и от подхода), откуда и вылезают разные функциональщины.

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

> 1. А по-моему разной процедурщины вообще не бывает. Она одна, в отличие от функциональщины.

> 2. И в чем это проще? Развей тему.

a) Собственно, уже сделано. Я понимаю, что уже задолбал слегка, но всё-таки: монады. Каждая монада даёт тебе свою разновидность императивного кода. Какая-то - даёт тебе эквивалент C (IO), какая-то - доступ к одной (и только одной) переменной (State), и т.п.

б) Помимо того, что писать на том, что уже есть, проще, чем на том, чего нет - функциональщина вообще обычно проще.

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

> реализацией хаскеля, который умел бы безопасно дергать с/с++ функции БЕЗ ffi.

Код на Хаскеле:

-- Example: Computing some Fibonacci numbers: fib = do { a <- arrayU[40]; i <- auto 0; a[0] =: 1; a[1] =: 1; for (i =: 2, (i :: EIO Int) < 40, i += 1) $ do { a[i] =: a[i-1] + a[i-2]; }; retrn (a[39]); }

-- Example: Copying stdin to stdout: cat = do { c <- auto 0;

while ((c =: getchar()) >= 0) $ do { putchar(c); }; return (); }

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

Блин, форматирование:

> реализацией хаскеля, который умел бы безопасно дергать с/с++ функции БЕЗ ffi.


Код на Хаскеле:
-- Example: Computing some Fibonacci numbers:
fib = do {
a <- arrayU[40];
i <- auto 0;
a[0] =: 1;
a[1] =: 1;
for (i =: 2, (i :: EIO Int) < 40, i += 1) $ do {
a[i] =: a[i-1] + a[i-2];
};
retrn (a[39]);
}
-- Example: Copying stdin to stdout:
cat = do {
c <- auto 0;
while ((c =: getchar()) >= 0) $ do {
putchar(c);
};
return ();
}

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

> какая-то - доступ к одной (и только одной) переменной (State)

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

_________________________________

Теперь насчет функциональщины поверх процедурщины -- простейший способ -- это сделать как в D атрибут pure для функций. Какие будут претензии к этому способу?

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

> а что значит "разная процедурщина", "разная функциональщина"? можно примеры разностей в функциональщине, которых не может быть в процедурщине?

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

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

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

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

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

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

Угу, это делает монада ST. В ней ты можешь писать императивный код, который на выходе станет чистым. Всё, что тебе нужно - это не позволить сайд-эффектам "вылезти наружу"; система типов за этим проследит автоматически.

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

> не мучайся, я совсем не это имел в виду

Ещё один хаскельный пример (честно, это действительно хаскель):

main = runBASIC $ do
    10 GOSUB 1000
    20 PRINT "* Welcome to HiLo *"
    30 GOSUB 1000

    100 LET I := INT(100 * RND(0))
    200 PRINT "Guess my number:"
    210 INPUT X
    220 LET S := SGN(I-X)
    230 IF S <> 0 THEN 300

    240 FOR X := 1 TO 5
    250   PRINT X*X;" You won!"
    260 NEXT X
    270 STOP

    300 IF S <> 1 THEN 400
    310 PRINT "Your guess ";X;" is too low."
    320 GOTO 200

    400 PRINT "Your guess ";X;" is too high."
    410 GOTO 200

    1000 PRINT "*******************"
    1010 RETURN

    9999 END

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

>boost.lambda делает то, что вы никоим образом не делаете -- дает возможность прозрачно подключить через указатели много чего есть на с++

а ещё boost.lambda не позволяет использовать в своих выражениях оператор точку ('.'), потому как его нельзя перегружать - и не заставишь ты его возвращать прокси хоть тресни. не позволяет делать локальные объявления. не поддерживает вложенные лямбды. ну очень прозрачная и удобная библиотека

а главное патчить её - сплошное удовольствие, код Яакко Ярви понятен даже ребёнку, не так ли?

>Полноценную реализацию функционального программирования на с++ (такой однако нет)

не удивительно

>можно было бы сравнивать только c реализацией хаскеля, который умел бы безопасно дергать с/с++ функции БЕЗ ffi

как можно безопасно дёргать грязные функции без FFI?

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

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

в условиях наличия в GHC квазиквотации - одно и то же. транслятор этого языка в хаскель используется в компайл-тайм. тебе дать ссылки на eDSL-реализации nesC и IA-32 в Haskell?

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

угу, потому что в большинстве случаев проще удавиться. или написать на чистом C и не сношать себе мозг

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

>Грубо говоря внешний мир программы процедурен

внешний мир программы - это машина Тьюринга и фон-Неймановская архитектура. к процедурному программированию (фреймам) прямого отношения не имеет

>хотя вы тут можете спорить

с удовольствием причём

>Функциональщина -- это такой хитрый способ создать иллюзию, что мир неизменен

у тебя очень однобокий взгляд на функциональщину; иммутабельные данные и в Java сделать можно, и что - Java внезапно станет ФП-языком?

>или ограничить средства написания проги так

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

>Однако создавать иллюзию и ограничивать средства можно существенно по-разному

почему ты упорно считаешь что ФП - это кастрированная императивщина? это, мягко выражаясь, не так

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

>Теперь насчет функциональщины поверх процедурщины -- простейший способ -- это сделать как в D атрибут pure для функций. Какие будут претензии к этому способу?

это никоим местом к функциональщине не относится. пойдёт такая претензия?

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

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

Меня пока что интересует:

1. Тот пример на хаскеле, который sf так и не привел

2. Сравнение сложности реализации "функциональщина на процедурщине" (ФнП) и наоборот (ПнФ). Под реализацией понимается НЕ компилятор, а реализация строго внутри языка. Речь может идти

ПнФ: это например как на хаскеле через монады

ФнП: это например слово pure как в D c тупой проверкой его компилятором -- здесь меня как раз больше всего интересует ваша критика.

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

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

> это никоим местом к функциональщине не относится. пойдёт такая претензия?

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

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

>1. Тот пример на хаскеле, который sf так и не привел

можно повторить постановку задачи? тут уже так нафлудили, что шиш найдёшь :(

>2. Сравнение сложности реализации "функциональщина на процедурщине" (ФнП) и наоборот (ПнФ). Под реализацией понимается НЕ компилятор, а реализация строго внутри языка. Речь может идти

ядрёна вошь, что такое "реализация внутри языка"? eDSL? пока ты не прояснишь своё понимание этого момента, дискутировать с тобой бессмысленно. потому как вот это -

>ФнП: это например слово pure как в D c тупой проверкой его компилятором -- здесь меня как раз больше всего интересует ваша критика

это ни разу не функциональщина

можно на D в локальную переменную сохранить функцию, созданную на лету как композицию двух-трёх других функций? let f = a . b . c in ...? можно на C++ реализовать вложенные лямбды? замыкания? новую синтаксическую конструкцию (for else из Python'а, например)?

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

>Почему тогда подмножество этого языка будет не функциональным языком?

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

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

> тебе тезис Чёрча-Тьюринга о чём-нибудь говорит

А ты читал хотя бы мои посты в этой ветке, и хотя бы тот пример с регулярными выражениями -- речь шла не о вычислимости вообще, а о экспоненциальном/линейном времени.

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

>Это ты ее зачем-то приплел

это пример попытки реализовать кусочек ФП в императивном языке. со всеми вытекающими ограничениями. я ещё на boost.mpl предлагал посмотреть, там тоже весело. и на felix

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

>> Почему тогда подмножество этого языка будет не функциональным языком?

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

Почему фиксированный порядок делает субъязык ВДРУГ нефункциональным? Ведь у нас в субъязыке все функции чистые.

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

>> Это ты ее зачем-то приплел

> это пример попытки реализовать кусочек ФП в императивном языке. со всеми вытекающими ограничениями.

НЕПРАВИЛЬНО. это пример реализовать ФП в языке с бедной системой типов и низкими возможностями метапрограммирования, со всеми вытекающими ограничениями.

императивность тут никоим боком.

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

>А ты читал хотя бы мои посты в этой ветке

не все

>пример с регулярными выражениями

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

>экспоненциальном/линейном времени

оптимизация есть везде, и в ФП тоже. наивный парсер CF-грамматики в ФП имеет экспоненциальную сложность по времени, мемоизация уменьшает её до кубической, частичные вычисления - до квадратичной. последняя на сегодня версия regex-tdfa для Haskell имеет линейную сложность по времени

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

>Почему фиксированный порядок делает субъязык ВДРУГ нефункциональным? Ведь у нас в субъязыке все функции чистые

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

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

> можно на D в локальную переменную сохранить функцию, созданную на лету как композицию двух-трёх других функций? let f = a . b . c in ...? можно на C++ реализовать вложенные лямбды? замыкания? новую синтаксическую конструкцию (for else из Python'а, например)?

Мне так кажется, что этот вопрос сводится к одному -- можно ли в языке делать замыкания? Вообще говоря, замыкания -- это вопрос почти чисто синтаксический. Ну да ладно.

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

И чем субъязык из чистых функций будет не функциональным языком?

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

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

короче, выдай свой критерий.

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

>Мне так кажется, что этот вопрос сводится к одному -- можно ли в языке делать замыкания?

неправильно тебе кажется. про композицию ответишь что-нибудь? про синтаксическую (семантическую, вообще говоря) конструкцию? в ФП это делается элементарно

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

> можно повторить постановку задачи? тут уже так нафлудили, что шиш найдёшь

http://www.linux.org.ru/jump-message.jsp?msgid=3594542&cid=3600072

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

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

> неправильно тебе кажется. про композицию ответишь что-нибудь? про синтаксическую (семантическую, вообще говоря) конструкцию? в ФП это делается элементарно

А по-моему ты лишнего тратишь свою энергию на стрельбу по площадям. Давай разберемся с самого начала -- с критериями ФП.

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

>короче, выдай свой критерий

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

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

>А по-моему ты лишнего тратишь свою энергию на стрельбу по площадям

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

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

Причем я спрашиваю твое личное мнение, которое может отличаться от википедии.

In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data.

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

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

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

Далее я формулирую типа теоремы: если в имеративный язык добавить по мелочам pure/closure/... то он поимеет подможнество, изоморфное функциональному языку, причем изоморфное достаточно прямо (а не криво).

Это я и хочу обсудить. Для начала.

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

>treats computation as the evaluation of mathematical functions

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

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.27.7800

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.14.8661

>Причем я спрашиваю твое личное мнение, которое может отличаться от википедии

да ты хоть бы уже википедию читал внимательно

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

>Далее я формулирую типа теоремы: если в имеративный язык добавить по мелочам pure/closure/... то он поимеет подможнество, изоморфное функциональному языку, причем изоморфное достаточно прямо (а не криво)

ну докажи. докажешь - приходи :)

>Это я и хочу обсудить. Для начала.

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

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

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

Правда, "императивное наследие", скорее всего, помешает тебе навесить многие другие фишки, полезные, но для "звания функционального языка" необязательные - что, увы, скажется на результатах, которые ты в результате получишь. Скажем, ту же Software Transactional Memory реализовать полностью на нечистом языке... не представляю, как. Возможно, DDC справился бы с этим, но чтобы кто-нибудь ещё - вряд ли. Но, в принципе - да, подмножество, изоморфное (в некотором смысле) функциональному языку у тебя будет.

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

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

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

Ну тогда остается только тема с тем примером, который на хаскеле не дали.

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

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

Я же полагаю, что можно навесить все фишки при наличии либо достаточно мощной макросистемы, либо если изначальный язык был изначально чем-то типа "чисто имеративного лиспа". Т.е. все те неприятности, которые например упомянал jtootf про буст -- они вовсе не императивное наследие, а синтаксическое.

Пример: если бы оператор . в с++ имел бы еще и другую синтаксическую версию a.b <===> subfield(a,b) то проблем бы у буста с ним не было (?)

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

>> ФнП: это например слово pure как в D c тупой проверкой его компилятором -- здесь меня как раз больше всего интересует ваша критика

> это ни разу не функциональщина

> можно на D в локальную переменную сохранить функцию, созданную на лету как композицию двух-трёх других функций? let f = a . b . c in ...?

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

> можно на C++ реализовать вложенные лямбды? замыкания?

Без доработки компилятора - нет.

> новую синтаксическую конструкцию (for else из Python'а, например)?

Нет. Но это в в любом не-ленивом языке нельзя сделать, будь он даже функциональный.

А почему именно такой (странный, ИМХО) список требований?

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

> Я же полагаю, что можно навесить все фишки при наличии либо достаточно мощной макросистемы, либо если изначальный язык был изначально чем-то типа "чисто имеративного лиспа".

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

Так, например, если мы не можем заставить компилятор проверять "чистоту" функции (скажем, тот же атрибут pure), то Software Transactional Memory не реализуется вообще, либо является чрезмерно подверженной труднообнаружимым ошибкам. Если можем - то надо ли нам вообще то, что не pure, если интересные вещи (не только STM) требуют pure? Либо нам надо забить на интересные вещи из функциональных языков и делать другие интересные вещи, из, например, императивных языков - тогда, опять-таки, непонятно, зачем был этот pure.

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

DDC - диалект Хаскеля, умеющий сайд-эффекты и отражающий тип сайд-эффектов в типе (пардон за перегрузку термина "тип") самой функции. Скажем, тип функции map в нём таков, что из него очевидно: map f даёт только такие сайд-эффекты, которые даёт функция f, и никакие другие. Если f - чистая функция, то map f - тоже чистая.

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

>> новую синтаксическую конструкцию (for else из Python'а, например)?

> Нет. Но это в в любом не-ленивом языке нельзя сделать, будь он даже функциональный.

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

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

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

В формулировке "если пользовтель ограничивает себя работой в этом подмножестве" меня это устроит (чужие либы тоже либо должны быть отмечены pure, либо должны считаться грязными)

> Вопрос: а надо ли тогда всё остальное вообще?

Надо. Доказывать я это здесь не буду.

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

> Надо. Доказывать я это здесь не буду.

Это, как раз, самое интересное.

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

> Либо нам надо забить на интересные вещи из функциональных языков и делать другие интересные вещи, из, например, императивных языков - тогда, опять-таки, непонятно, зачем был этот pure.

Можно в одних местах делать одно, а в других -- другое.

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

>>> новую синтаксическую конструкцию (for else из Python'а, например)?

>> Нет. Но это в в любом не-ленивом языке нельзя сделать, будь он даже функциональный.

> В Лиспе можно (и это, фактически, основная фишка Лиспа).

Макросом? Тогда в любом языке можно.

> В Форте можно

Форта не знаю, так что ХЗ.

> Смолтоке, как я понимаю, можно.

Кодовым блоком? Ну дак это специальная ленивая конструкция.

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

> Можно в одних местах делать одно, а в других -- другое.

И мы, фактически, получаем два очень слабо связанных языка. Не проще сразу взять два языка вместо одного?

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

>> новую синтаксическую конструкцию (for else из Python'а, например)?

> Нет. Но это в в любом не-ленивом языке нельзя сделать, будь он даже функциональный.

Если у тебя есть замыкания, это спокойно делается. (кстати, надо будет попробовать это на с++0х с препроцессором, но полноценно, конечно, не получится из-за слабой системы типов)

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

> И мы, фактически, получаем два очень слабо связанных языка. Не проще сразу взять два языка вместо одного?

И тут мы приходим к тому, о чем я -надцать раз говорил. Атрибут pure можно в некоторых случаях ОПРАВДАНО выставить, даже если компилятор не согласен.

насчет DDC -- обязательно гляну его систему типов (вообще, как я и писал уже, хаскель нужен в основном чтобы изучать)

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

> Макросом? Тогда в любом языке можно.

Не в каждом языке есть собственная макросистема, да ещё достаточно богатая. Да, конечно, можно использовать что-то вроде m4... но тогда нам будет ОЧЕНЬ трудно добиться того, чтобы эта конструкция вела себя именно как конструкция языка.

> Кодовым блоком? Ну дак это специальная ленивая конструкция.

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

Впрочем, соглашусь, Смолток несколько не в кассу.

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

> Нет. Но это в в любом не-ленивом языке нельзя сделать, будь он даже функциональный.

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

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

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

> Нет. Но это в в любом не-ленивом языке нельзя сделать, будь он даже функциональный.

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

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

>> Макросом? Тогда в любом языке можно.

> Не в каждом языке есть собственная макросистема, да ещё достаточно богатая.

Это философский вопрос - считать ли макросистему частью языка. Мое мнение - не считать.

Правильное расширение достигается с помощью чисто языковых средств, как в твоем примере с Бейсиком-в-Хаскеле (насколько я понял, там преропроцессор не использовался).

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

>Ну тогда остается только тема с тем примером, который на хаскеле не дали

если у меня счас не сгорит железо - пример сделаю. ну во всяком случае постараюсь :)

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

>А почему именно такой (странный, ИМХО) список требований?

навскидку то, что я использую в Haskell и не могу (очевидным образом) сделать в C++

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

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

А если есть ленивые вычисления, то не надо делать замыкания из блоков.

>> Нет. Но это в в любом не-ленивом языке нельзя сделать, будь он даже функциональный.

>Вообще (это не столько даже тебя касается) видно, как люди совершенно неправильно строят граф зависимостей фич языка

В чем неправильность построенного мной графа (и как он выглядит %))?

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

>Меня прямо таки удивляет, что называешь эту гипотезу абсурдной. По-моему она вполне очевидна, я даже и не предполагал, что ее придется кому-то доказывать

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

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

>все те неприятности, которые например упомянал jtootf про буст -- они вовсе не императивное наследие, а синтаксическое

как по мне, так семантическое. синтаксис-то тут при чём?

>изначальный язык был изначально чем-то типа "чисто имеративного лиспа"

Tcl? :)

>если бы оператор . в с++ имел бы еще и другую синтаксическую версию a.b <===> subfield(a,b) то проблем бы у буста с ним не было

если бы его по-прежнему нельзя было перегружать - были бы

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

>> можно на D в локальную переменную сохранить функцию, созданную на лету как композицию двух-трёх других функций? let f = a . b . c in ...?

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

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

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

> Это философский вопрос - считать ли макросистему частью языка. Мое мнение - не считать.

Зависит, естественно, от макросистемы. В Лиспе она интегрирована с основным языком, в C - нет, в C++ - нечто промежуточное (я имею в виду, естественно, не #define-ы).

> Правильное расширение достигается с помощью чисто языковых средств

В том-то и дело, что в Лиспе и в Форте макросистема - чисто языковое средство.

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

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

Ы?

Или ты хочешь сказать "как и замыканий"?

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

> А если есть ленивые вычисления, то не надо делать замыкания из блоков.

При условии, что у тебя еще есть дополнительно 2. eval 3. AST, а ведь их может и не быть.

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

>> А если есть ленивые вычисления, то не надо делать замыкания из блоков.

> При условии, что у тебя еще есть дополнительно 2. eval

Я не знаток Хаскеля, но не припомню там eval. Впрочем, можно считать, что он там условно есть.

> 3. AST, а ведь их может и не быть.

Это не нужно.

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

SELFIX:

При условии, что у тебя еще есть дополнительно AST, а ведь его может и не быть.

Мне кажется, что лучше без него...

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

Вообще я чуствую тормозить начал.

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

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

> А если есть ленивые вычисления, то не надо делать замыкания из блоков.

Ладно, еще возражения:

* ленивые вычисления вообще нам не нужны, нам нужны только ленивые вычисления аргументов-в-виде-блоков-кода

* в случае for( ; ; ) тебе придется перевычислять блоки кода, я не уверен, что это входит в понятие "ленивый язык"

кстати, как там в D? оно перевычисляется? я не помню

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

> навскидку то, что я использую в Haskell и не могу (очевидным образом) сделать в C++

Я догадывался, и потому просил тебя выдвинуть собственное видение, а не из википедии.

Хорошо бы выкатил более полный список.

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

>Хорошо бы выкатил более полный список.

в смысле - того, чего мне не хватает в C++? или чего, какой список? я несколько потерял нить беседы :(

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

> А если есть ленивые вычисления, то не надо делать замыкания из блоков.

f(lazy int i);

f(lazy void x); // забавно но по смыслу возражений нет

f(lazy int i) throw;

В последнем случае, если окажется, что i может вызвать исключение, компилятор ругнется. По-моему f( int i() ) throw; выглядит гораздо прямее.

Хотя я еще сомневаюсь...

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

> в смысле - того, чего мне не хватает в C++? или чего, какой список? я несколько потерял нить беседы

И то, и другое, и можно без хлеба (С) Винни-пух

1. Неприятные места плюсов

2. Те хорошие фишки, которые ты считаешь "функциональными" (на проверку они могут оказаться не такими, но не беспокойся об этом).

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

>f(lazy void x);

а когда force произошёл - оно какого типа стало?

вообще это больше на futures похоже - из C++0x. да и для D реализация была, находил как-то

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

>в смысле, могут оказаться не чисто функциональными

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

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

> было бы ещё совсем здорово, если бы в тред вернулись лисперы, и дали бы ещё макр на подумать и о них тоже...

Лисперы в столь поздний час или спят или зохавывают мир, им не до тебя :)

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

>Лисперы в столь поздний час или спят

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

>им не до тебя

увы. но я ещё надеюсь

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

> а когда force произошёл - оно какого типа стало?

void конечно! (ради побочного эффекта юзается)

> вообще это больше на futures похоже - из C++0x.

нет, тут ничего в отдельной нитке не запускается

> да и для D реализация была, находил как-то

в Д можно так писать, только не знаю насчет void и перевычисляются ли они -- надо разобраться

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

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

Лисперы давно в нирване, с тобой на лоре как раз общается написанная ими сонливая макра.

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

>> было бы ещё совсем здорово, если бы в тред вернулись лисперы, и дали бы ещё макр на подумать и о них тоже...

> Лисперы в столь поздний час или спят или зохавывают мир, им не до тебя :)

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

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

>Они интересные вещи говорят, но в практическую ценность чего-то из лиспа я не верю

практическую ценность CL (да и Scheme, в общем-то) я наблюдаю регулярно, во вполне себе продакшен-коде. практического использования Qi не видел ни разу - ни лисперами, ни функциональщиками

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

>Лисперы давно в нирване, с тобой на лоре как раз общается написанная ими сонливая макра.

я подозревал!

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

Кстати, gaa, ключевые аргументы нужны, но нихрена не понятно, как взаимодействовать с функциями, расчитанными на позиционные аргументы. И еще надо как-то вводить название ключевых параметров в сигнатуру функции. Я это как-то еще не додумал.

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

>ну конечно. а что?

то есть на самом деле это процедура. со связанными аргументами. у нас тут call by name или мемоизация? сколько раз побочные эффекты получить можно?

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

> то есть на самом деле это процедура. со связанными аргументами. у нас тут call by name или мемоизация? сколько раз побочные эффекты получить можно?

Как там в Д, я не помню.

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

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

Если используется редко --- оставить как есть, если часто --- написать Ъ-обёртку (что-то сиплюсплюсом запахло, откройте форточку :) ).

> И еще надо как-то вводить название ключевых параметров в сигнатуру функции. Я это как-то еще не додумал.


Для динамических языков сигнатура вроде бы ни к чему, а для сиплюсплюса как-то так:

class CoolFun {
public:
CoolFun();
~CoolFun();

void setDir (const string &);
void setMailBox (const string &);

list<Messages> operator ();
};

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

Кстати, помня твоё желание видеть гибкия язык с простым вызовом функций из внешних библиотек: http://wiki.tcl.tk/1197

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

>> то есть на самом деле это процедура. со связанными аргументами. у нас тут call by name или мемоизация? сколько раз побочные эффекты получить можно?

>Как там в Д, я не помню.

если много раз, то надо ещё как-то контролировать идемпотентность сайд-эффектов :) в Slice (IDL для ZeroC ICE), помнится, для этого отдельный квалификатор ввели

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

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

> Для динамических языков сигнатура вроде бы ни к чему, а для сиплюсплюса как-то так:

Ну во-первых для плюсов (как всегда, гы-гы-гы) есть костыль, который дает именованные параметры, например messages(dir="asdf",mailbox="input"), а я веду речь (как говорил ден73) о языке мечты, где все правильно сделано.

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

> Ну во-первых для плюсов (как всегда, гы-гы-гы) есть костыль, который дает именованные параметры, например messages(dir="asdf",mailbox="input"), а я веду речь (как говорил ден73) о языке мечты, где все правильно сделано.

Значит да, они должны быть частью сигнатуры.

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

точнее даже можно так:

int dir=1; int messages=2;

vector<string> m = ns::messages(dir="asdf",mailbox="input");

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

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

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

Придумай мне хоть какой-нибудь макрос в Хаскелле (ты же его честь отстаиваешь в этом бреду на последних страницах?), который бы имел синтаксис основного языка и полноценно (с рекурсивными экспандами, сессно) выполнялся бы ещё в компайл-тайме. Очевидно, что все варианты препроцессоров и темплейтов на макросы не тянут.

Например, в CL макрос loop или iter (уже не CL, к сожалению) в компайл-тайме макроэкспандом разворачивается в код, который выполняет только то, что этим макросом описано, т.е. натурально генерирует исходный код для компилятора.

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

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

> Придумай мне хоть какой-нибудь макрос в Хаскелле , который бы имел синтаксис основного языка и полноценно (с рекурсивными экспандами, сессно) выполнялся бы ещё в компайл-тайме. Очевидно, что все варианты препроцессоров и темплейтов на макросы не тянут.

К слову, а что это в лиспе за разброд и шатание с макросами? Почему они не являются типичной процедурой основного языка? А то получается неравномерность как у плюсов с их темплейтами.

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

> Что ты имеешь в виду под разбродом и шатанием?

То, что макра!=функция. Я ведь не ошибся и это на самом деле так?

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

Фактически, макрос - это функция. Она выполняется в компайл-тайм и оперирует исходным текстом.

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

> Фактически, макрос - это функция. Она выполняется в компайл-тайм и оперирует исходным текстом.

Ну вот, собственно, это мне и кажется "шатанием". Как-то неоднородно.
Получается две возможности решения одного и того же (через макры и функции), что может привести к неудобствам при попытке два этих метода смешать. Да и с кодом макры в райтайме не поработаешь.

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

> Ну вот, собственно, это мне и кажется "шатанием". Как-то неоднородно. Получается две возможности решения одного и того же (через макры и функции), что может привести к неудобствам при попытке два этих метода смешать.

Не понимаю, про что ты?

> Да и с кодом макры в райтайме не поработаешь.

Почему это?

(eval '(defmacro entity (x) `,x)) или (eval (read-from-string "(defmacro entity (x) `,x)"))

(macroexpand (entity 1))

=> 1, NIL

Всё то же самое.

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

>Придумай мне хоть какой-нибудь макрос в Хаскелле (ты же его честь 
отстаиваешь в этом бреду на последних страницах?), который бы имел 
синтаксис основного языка и полноценно (с рекурсивными экспандами, 
сессно) выполнялся бы ещё в компайл-тайме. Очевидно, что все варианты 
препроцессоров и темплейтов на макросы не тянут. 

cnst 0 str = lift str
cnst n str = do e <- cnst (n-1) str
                [| \_ -> $e |]

вот объясни мне, чего тебе тут не хватает? Haskell? Haskell
компайл-тайм? компайл-тайм. и рекурсивный сплайс, используемый для
объявления функции n переменных

>Я, кстати, видел плюсатый код знакомого маньяка, который в 
компайл-тайме считал простенькое мат.выражение. Но являло это собой 
полное говнище в исходниках, компилировалось только одним компилятором 
с определённым патчсетом и жрало памяти просто неимоверно. И всё равно 
это даже отдалённо не макросы :)

это всё чудесно, и я тоже такое писал. вот только в Haskell оно
попроще получается. эдак на порядок

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

cnst 0 str = [| str |]
cnst n str = [| \_ -> $(cnst (n-1) str) |]

упрощённый вариант того же шаблона

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

> вот объясни мне, чего тебе тут не хватает? Haskell? Haskell компайл-тайм? компайл-тайм. и рекурсивный сплайс, используемый для объявления функции n переменных

Что-то типа.

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

>> Ну вот, собственно, это мне и кажется "шатанием". Как-то неоднородно. Получается две возможности решения одного и того же (через макры и функции), что может привести к неудобствам при попытке два этих метода смешать.
> Не понимаю, про что ты?


Макры из функций вызывать вроде можно. А функции из макр? Если нет, то постоянно придётся помнить, что какой-то кусок кода может быть использован в макрах и писать его на макрах.

>> Да и с кодом макры в райтайме не поработаешь.

> Почему это?


То, что ты привёл --- не работа с кодом, а вызов кода на исполнение. Вот в Tcl есть [info body], которая для любой функции вернёт её тело как текст, т.е. исходный код именно в том виде, как я его написал.

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

>Вот в Tcl есть...

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

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

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


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

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

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

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

gaa ★★
()
Ответ на: комментарий от 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 ★★★★★
()
Ответ на: комментарий от 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 ★★★★★
()
Ответ на: комментарий от 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
()
Ответ на: комментарий от guest-3484-2009

>Вот, например, loop:
>(25 первых чисел фибоначчи)

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

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

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

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

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

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

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

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


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

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

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


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

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

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

Круто, спасибо.

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

>Сделать с телом функции можно что угодно, это обычный список

в REBOL тоже список, в Tcl это обычная строка; вот интересно, а в Рефал что?

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

>А еще можно через m4. Даже круче строк и eval получается.

ну и славненько

>Тогда Си вообще самый-пресамый метаязык, выходит.

в связке с m4 - в принципе неплохо, да. а можно определение труЪ-метапрограммирования? а то сложно спорить о сферическом коне в вакууме

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

> А еще можно через m4. Даже круче строк и eval получается.
> Тогда Си вообще самый-пресамый метаязык, выходит.


Фуфло хоть не компилируется в отличии от :]

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

> А фуфло, это у вас, стало быть, ошибки типов опять?
> Хаскелеводы банальны до невозможности.


Ну почему. Скобки там лишние, запятые, собачки, двоеточия нехватающие ;]

У Вас ошибок вообще не бывает, судя по постам.
Иначе я просто не могу обьяснить тягу сгенерить их всеми доступными способами.
В lisp среде сторонние библиотеки не принято обновлять?

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

>У Вас ошибок вообще не бывает, судя по постам.
Бывает, однако, ошибки они, видите ли, двух видов бывают - аппаратные, логические и опечатки. От первых не спасет ничего, от вторых вас типизация тоже не особо охраняет, от третьих - только от передачи в функцию строки вместо числа(и другого подобного). А вот макросы в лиспе сводят на нет третьи, и в то же время уменьшают вероятность вторых, т.к. выводят абстракцию на качественно новый уровень, позволяя мыслить в терминах решаемой задачи и не отвлекаться на низкоуровневые детали и детали реализации.
>Иначе я просто не могу обьяснить тягу сгенерить их всеми доступными способами.

А я вот не могу понять стремление бегать в стальных валенках.
>В lisp среде сторонние библиотеки не принято обновлять?

А это тут причем?

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

> В lisp среде сторонние библиотеки не принято обновлять?

Принято. Более того, обновленная библиотека может поломать функциональность старой (поищи посты den73 со словом weblock)

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

> Ну так где твой суперпример на хаскеле? Аналог моего на плюсах, но с const T* ?

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

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

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

Вот там sf поставил (мне кажется, в плюсах без лишнего параметра не обойтись, интересно как в хаскеле)

http://www.linux.org.ru/jump-message.jsp?msgid=3594542&cid=3600072

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

> >У Вас ошибок вообще не бывает, судя по постам. > Бывает, однако, ошибки они, видите ли, двух видов бывают - аппаратные, логические и > опечатки. От первых не спасет ничего, от вторых вас типизация тоже не особо охраняет, от

Не согласен :] Гораздо проще ошибиться, когда в языке всего то 2 базовых типа - и те нельзя проверить на правильность употребления до запуска программы без самописных средств(даже если этого кода очень мало). А их для lisp особо не напишешь в свете eval и перегрузки reader-macro (или я не прав?).

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

Классный пример автоматического тестирования функции в haskell - либа QuickCheck. Основываясь на _типе_ инварианта генерирует произвольные входные данные и проверяет его. Как в lisp сделать что-то подобное я не знаю.

Видать, это больше идеологический вопрос :]

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

Звучит как назначение языка программирования как такового. Я с этим тоже не согласен(про всемогущесть макросов, но я верю в их удобство! :]) - надо ж лупасить скобки и функции/макросы с параметрами, нет? Или обычно дело влепить какие-нить reader macros?

От языка не так много надо, чтобы на нем можно было реализовавыть собственные fool-proof абстракции. Всё равно полностью абстрагироваться не получается (если только полностью не разделять язык реализации и пользовательский DSL). Влазят какие-то константы, числа, строки, предикаты, функции высшего порядка и в чистом виде присутствуют в свежеслепленном DSL и вытаскивают наружу (ну или между внутренностями, но я хочу проверить хотя-бы часть исходника) эти гадкие базовые типы.

Последний написанный мной классификатор на ruby (:p) предоставлял вообще отдельный микроязык именно для того, чтобы увеличить информативность об ошибках и проверять типы и вычислять простейшие выражения.

> >Иначе я просто не могу обьяснить тягу сгенерить их всеми доступными способами. > А я вот не могу понять стремление бегать в стальных валенках. Мне не нравится эта аналогия. Она не отражает сути.

> >В lisp среде сторонние библиотеки не принято обновлять? > А это тут причем? Просто интересно как происходит процесс познания (например, случайно) немного изменившегося API модуля. Функции с &rest аргументами совсем не радуют :[

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

> > Фуфло хоть не компилируется в отличии от :]

> Ну так где твой суперпример на хаскеле? Аналог моего на плюсах, но с const T* ?

Не могу заставить компилироваться :] (шутка) Как только осилю - сразу запощу.

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

>>>> В плюсах с замыканиями вроде как проблем нет.
>>> Ы?

>>> Или ты хочешь сказать "как и замыканий"?

>> В с++0х уже есть.

>А. Я уж испугался было.


Это не замыкания. Слово clousure в новом стандарте с++0х употреблено для красного словца:

"If a closure object containing references to local variables is invoked after the innermost block scope of its creation, the behaviour is undefined." (http://en.wikipedia.org/wiki/C++0x#Lambda_functions_and_expressions)

Настоящими замыканиями называется то, что не ведёт себя неопределенным образом при выходе из блока, в котором были определены локальные переменные, которое лямбда использует. Это правильнее назвать анонимными функциями -- функциями без имени, которые можно создавать на лету. Это неплохая фича, но это не замыкание. Лямбда должна уметь возвращаться как результат выполнения функции и не разваливаться при этом. Настоящее замыкание - это когда в лямбде замкнут "вид на окружающий мир" из той точки, где лябмда была создана. Если язык позволяет иметь доступ к стеку вызовов (как, например, в динамических языках), то и в лямде этот стек должен храниться и не исчезать, даже если выполнение функции, в которой лямда была создана, давно закончилась, и стек вызовов уже другой. Если бы ламбда была создана внутри объекта, и возвращена как результат одной из его функций и сохранена во внешней переменной, а потом этот объект был бы удалён - что бы тогда делал C++? Видна концептуальная несвовместимость. Весь этот флуд, что вот мол, давайте к "объективщине" и "императивщине" С++ добавим "функциональщину" и получим нечто объемлющее Хаскел и Лисп никуда не годится.

Сомневаюсь, что в С++ когда-либо будут настоящие замыкания. Но и не нужно это в С++. Вредно быть настолько универсальным. Нужно занимать свою нишу и работать над имеющимися проблемами. Тот, кто захочет в С++ или C сделать настоящие замыкания, получит кучу проблем. Такая фича меняет "природу языка". Такая фича достойна создания нового языка.

Кстати, по сабжу.
Динамические языки отчасти и возникли оттого, что захотелось делать мультипарадигменные языки ("императивщину" смешать с "функциональщиной"). Как только мы делаем это смешение, сразу получаем необходимость сборщика мусора. Осталось пожелать
1) ООП,
2) рефлексии + открытости классов,
3) отсутствия типов в сигнатурах функций и объявлениях переменных -- сразу получите Ruby/Python/Lua ...
по каждому из четырех типов я могу ответить, почему (по моему мнению) был сделан такой выбор.
Когда я сам, изучая Tcl, Perl, Ruby, Python, Haskel, пытался эксперименировать с придумыванием новых удобных мне языков программирования (не с целью создать реальный язык, а чтобы лучше понять выбор других разработчиков языков), обнаруживал, что вопросов, где можно повыбирать не так много.

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

> Это не замыкания. Слово clousure в новом стандарте с++0х употреблено для красного словца: "If a closure object containing references to local variables is invoked after the innermost block scope of its creation, the behaviour is undefined."

Гы-гы-гы. Там же совсем рядом написано:

If [=] is used instead of [&], all referenced variables will be copied, allowing the lambda function to be used after the end of the lifetime of the original variables.

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

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

> Вот там sf поставил (мне кажется, в плюсах без лишнего параметра не обойтись, интересно как в хаскеле)

> http://www.linux.org.ru/jump-message.jsp?msgid=3594542&cid=3600072

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

"Чуешь?" (c)

см. http://www.ruby-doc.org/core/classes/Fixnum.html : "if any operation on a Fixnum exceeds this range, the value is automatically converted to a Bignum."

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

> [пытаясь не уходить от сабжа]

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

З.Ы. у нас тоже есть числа произвольной точности c +-/*

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

> Гы-гы-гы. Там же совсем рядом написано: > If [=] is used instead of [&], all referenced variables will be copied, allowing the lambda function to be used after the end of the lifetime of the original variables.

А вот и не ГЫ-ГЫ-ГЫ. Одно дело copied, и совсем другое дело, когда две разные лямбда реально шарят одну и туже локальную x переменную после того, как вычисление функции вообще закончилось. И еще, представьте разные ситуации с несколькими лямбдами и несколькими тредами. Выберем средней сложности -- создана лямбда A типа [=x] и сохранена в глобальную переменную, которой паралельно воспользовался другой тред, выполнил, и в результате выполнения эта переменная x была изменена. Но наш исходный тред завел еще обыкновенную лямбду B типа [&x] и тоже её выполнил, и эта лямбда тоже меняет переменную x. ... развейте тему дальше сами, оцените то количество глюков и непоняток, которые придется разрулить всем компиляторам этого нового стандарта. Кстати, зашаривание локальных переменных между двумя замыканиями с целью зашаривания и обмена данными - это классика в динамическом программировании.

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

> А вот и не ГЫ-ГЫ-ГЫ ... зашаривание локальных переменных между двумя замыканиями с целью зашаривания и обмена данными - это классика в динамическом программировании.

гы-гы-гы

boost::shared_ptr<Foo> ptr = new Foo(.....); и дальше спокойно шаришь ptr между двумя замыканиями после выхода из функции

идея сохранять стэковый фрейм -- это spagetty stack и неэффективно

З.Ы. жаль в жцц 4.4 еще замыканий нет, а то бы дал рабочий пример в 10 строк.

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

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

Да понимаю я ваши разборки, понимаю. И они на меня тоску наводят. Сам устраивал такие разборки.

> З.Ы. у нас тоже есть числа произвольной точности c ++

Я в курсе. А теперь внимание вопрос: чего тогда не используете, а флудите? Отвечу сам: полюбили всей душой машиный уровень. Вы и машина -- одной крови. Есть ли Bignum, который используют _БОЛЬШИНСТВО_ пакетов в дистрибутиве Linux? Нету. И как же после этого вам абстрагироваться от конечности типа int, если вы используете сторонние библиотеки, где этот тип используется? Хрен абстрагируешься. Так и будете всю жизнь об этом помнить, учитывать разные разрядности архитектур и т.д. и т.п. Собственно, помнить об размере int - это нормально для kernel и огромного класса задач. Мне просто давно уже такие задачи не попадались. Признаюсь, область моих интересов довольно специфическая.

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

> Я в курсе. А теперь внимание вопрос: чего тогда не используете, а флудите?

что и доказывает, что разборки ты наши не понял, елки палки.

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

> > А вот и не ГЫ-ГЫ-ГЫ ... зашаривание локальных переменных между двумя замыканиями с целью зашаривания и обмена данными - это классика в динамическом программировании.

> гы-гы-гы

Нет, снова не ГЫ-ГЫ-ГЫ.

> boost::shared_ptr<Foo> ptr = new Foo(.....); и дальше спокойно шаришь ptr между двумя замыканиями после выхода из функции

> идея сохранять стэковый фрейм -- это spagetty stack и неэффективно

О сложности реализации и эффективности - это отдельный разговор. А вот полезно ли? Оказывается, иногда полезно.

> З.Ы. жаль в жцц 4.4 еще замыканий нет, а то бы дал рабочий пример в 10 строк.

Во первых, нужно сначала дождаться выхода компилятора. Я смогу написать кучу нерабочего кода в 10 строк, который толпы программистов на С++ будут писать и считать рабочим - вот ведь в чём ещё прикол.

Необходимость локальные переменные, которые мы хотим зашарить, оборачивать в shared_ptr<Foo> мне не нравится. Языки отличаются друг от друга не тем, что на них можно сделать (этим они практически не отличаются, так как все они квазитьюрингполны), а выразительностью. Каждая лишняя обертка дорого стоит. Это нужно вопринимать как крепкий прогиб под железячку. Собственно это еще одна причина, которую явно формулируют те, кто слез с С++ и Java -- надоело писать обертки и плодить классы и типы ради каждого плевка.

Вспомним ради чего всё это делается? Хотим прямо в выражениях создавать анонимные функции - то есть хотим видеть код прямо рядом с тем месом, где он нужен, не оформляя всякую мелочь в виде функции или функторов, и не раздавая этой мелочи имён (- не заслужили). Но если при этом я должен заботится о том, чтобы переменную типа int оборачивать shared_ptr'ом, а значит внутри лямбды использовать разименование указателя, то как-то сильно начинает страдать читаемость кода и увеличиваться напряжение мозга программистов, которые читают код друг друга. К тому же я заранее могу не догадаться, что у меня будет использоваться эта локальная переменная для расшаривания. И буду ее использовать обычно. А потом вдруг окажется, что должен создавать ее как new, и везде использовать с *. А может лучше использовать старые добрые всем уже известные функторы?

То, что на С++ возможно всё, я не сомневаюсь. Я сомневаюсь в том, что добавляя к нему новые динамичные фишки, мы получим повышение выразительности и практической используемости языка.

Вспомнил, что основной пример того, когда нескольким лямбдам требуется зашарить один и тот же набор переменных, -- это создание ряда _именованных_ функций, имена которых и значения зашаренных переменных зависят от опций, переданных мета-методу. См. например http://rails.vsevteme.ru/posts/show?id=6407 (часть "10 кю. Пишем правильно"). А это уже неподьёмно стандартными средствами. Попробуйте переписать на С+ хотя бы схематично, опуская принципиально невозможные вещи, код на Ruby, предоставленный в этой части, используя эту технику с shared_ptr. Сравните размер кода на С++ и исходного кода на Ruby. Честно сравните внятность и читаемость.

Ещё по сабжу написано там же в http://rails.vsevteme.ru/posts/show?id=6009

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

> (часть "10 кю. Пишем правильно"). А это уже неподьёмно стандартными средствами. Попробуйте переписать на С+ хотя бы схематично, опуская принципиально невозможные вещи, код на Ruby, предоставленный в этой части, используя эту технику с shared_ptr. Сравните размер кода на С++ и исходного кода на Ruby. Честно сравните внятность и читаемость.

ты просишь ORM для плюсов, я правильно понял? и еще желательно задачу поточнее сформулировать, что требуется.

варианты могут быть: 1. юзать внешнюю прогу для рефлексии 2. не юзать, но тогда названия полей класса я не смогу узнать, и полями класса будут наследники моего класса Object (типы будут обрабатывать правильно)

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

-- :]
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}

import Data.Int

class MyFoo a where       foo :: a

-- some simple non-plymorphic instances for MyFoo
instance MyFoo Int  where foo = 3
instance MyFoo Char where foo = 'z'

-- user-crafted polymorphic typeclass:
class MyBar a where               bar :: a

-- put anything to MyBar!
instance MyBar Double where       bar = 1.2
-- let it be 'const T * ' analogue: constrained polymorphic subtype
-- (could be in MyFoo tho)
instance (Num a) => MyBar a where bar = 4

-- add MyBar as an instance of MyFoo
instance (MyBar a) => MyFoo a where
    foo = bar

--
--

main = do print (foo :: Int)    -- MyFoo Int
          print (foo :: Char)   -- MyFoo Char
          print (foo :: Int64)  -- MyBar (Num a)
          print (foo :: Double) -- MyBar derivative

{-
Справедливсти ради надо отметить, что нельзя определить реализацию _сразу_ для 2х разных полиморфных подтипов (например, всунуть в MyBar еще и Monoid a). Так как они открыты - гад юзер может всунуть туда всё, что захочет и получит неоднозначность: из какого instance брать реализацию?
Собственно у нас почти это и происходит в пересечении у нас { a | Num a} и {Int, Double}, но Int - более кАнктерный и ч0кей, чем Num a, по-этому всё АднАзначнА (прям как в C++ ;], хоть и с расширениями).

Особо интересен случай, когда класс типов полиморфен сразу по нескольким параметрам (multiparameter typeclass) и нужно указать зависимость типов между собой (пример - Regex из regex-base: http://hackage.haskell.org/packages/archive/regex-base/0.93.1/doc/html/Text-Reg
ex-Base-RegexLike.html#t%3ARegexOptions).

Насколько я знаю в C++0x есть(?) только concepts, которые таких зависимостей не могут указывать :p

http://en.wikibooks.org/wiki/Haskell/Advanced_type_classes
-}

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

> О сложности реализации spaghetti stack и эффективности - это отдельный разговор. А вот полезно ли? Оказывается, иногда полезно.

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

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

Я твои кю посмотрел, но так и не понял этого. Ладно, метавопрос:

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

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

> {-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}

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

Еще минорное замечание -- вместо foo надо писать, чтобы было понятнее.

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

template<class T> Num
{
Num<T> operator + (Num<T>& a, Num<T>& b) { compile_time_error("not implemented"); }
};

(в ж++ есть такой compile_time_error, но я его забыл и не могу найти)

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

Еще минорное замечание -- вместо foo надо писать maxbound, чтобы было понятнее.

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

ну вот, я сделал код на плюсах, параллельных твоему хаскелю

// output: 1 2 3 0 0 0xBLABLABLA

#include <iostream>

struct Before { // this class is defined before MaxBound
    operator int() { return 1; }
};

struct MaxBound {
    operator int () { return 2; } 
    operator Before() { return Before(); }
    template<typename T> operator T* () { return 0; }
    MaxBound() {}
};
static MaxBound MAX_BOUND;

struct After { // this class is defined after MaxBound
    operator int() { return 3; }
    After() {}
    After(MaxBound m) {} // for MaxBound only
};
static After after;

template<> MaxBound::operator After* () { return &after; }

int main()
{
    std::cout << (Before )MAX_BOUND <<' '<< (int    )MAX_BOUND <<' '<< (After  )MAX_BOUND <<' '
	      << (int*   )MAX_BOUND <<' '<< (Before*)MAX_BOUND <<' '<< (After* )MAX_BOUND <<  '\n';
    return 0;
}


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

То, что получилось -- очень хрупко (как впрочем ты и писал). Нельзя функции на типах определять через операторы преобразования.

Более прямой способ -- сделать как в яве Class<T>, но чтобы он был либо целым числом, либо адресом статической переменной.

Теперь насчет http://en.wikibooks.org/wiki/Haskell/Advanced_type_classes

Я могу щас сииильно тормозить, но по-моему у плюсов никогда с этим проблем не было. И это все проблемы хаскеля с его явно лишним выводом типов и/или лишним каррингом, нет? (хотя если пытаться юзать карринг, то может они и в плюсах всплывут?)

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

2. Сообщить, что в шаблоне один тип функционально зависит от других никогда не проблема.

Давай разберемся -- это кривые руки хаскелистов, или я ничего не понял? Интересно найти пример на плюсах, где бы это проявилось.

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

может, надо создать отдельную тему Advanced_type_classes vs. C++ ?

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

> Я могу щас сииильно тормозить, но по-моему у плюсов никогда с этим проблем не было. И это
> все проблемы хаскеля с его явно лишним выводом типов и/или лишним каррингом, нет? (хотя

> если пытаться юзать карринг, то может они и в плюсах всплывут?)


Проблем с выводом? У С++ другие проблемы - он выводит мало. Карринг нипричем.

При неверном указании типа итератора вершины в каком-нибудь алгоритме boost graph library генерит ошибку компиляции на 1.5 страницы, причем ошибка якобы НЕ в коде пользователя(ну ладно, он показывает откуда производится инстанцирование), а в бустовом хедере(!) (хотя код boost же нормальный, или не очень? если компилятор словил это хер знает где). Больше напоминает препроцессор.

Что за нас может сделать плюсатый компилятор? Типы аргументов/возвращаемого значения шаблонных функций _определяются программистом_ или явно, или вообще не указываются. Concepts частично решают эту задачу, но надо _самим_ лазить по исходнику и указывать, какие операции должен определять на себе полиморфный параметр. Остается только попытаться собрать нечто, получающееся на пути инстанцирования аккуратно обступая код, который в принципе не собирается. Что-то тут не так.

При явном определении получаем жуткие сигнатуры функций (так как typedef юзать в сигнатурах функций нельзя ;]) или заворачиваем всё в traits (тоже выглядит непрозрачно).

> 1. Всегда понятно, что тип результата функции функционально зависит от типов параметров.

В примере с max_bound это не так.

> 2. Сообщить, что в шаблоне один тип функционально зависит от других никогда не проблема.

Зависимый тип можно просто _определить_ в терминах шаблонного параметра. Более слабых отношений определить нельзя.

В С++ эту задницу с зависимостями/требованиями к полиморфному параметру _полностью_ сгружают на пользователся, а в haskell - на компилятор; и таки да - ghc надо помогать(fundeps), но не делать за него всё.

Что лучше? :]

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

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

> Карринг нипричем.

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

> диагностика

1. да сейчас диагностику ошибок проще не читать. я читаю только номер строки и дальше думаю сам.

2. concepts это (я ошибаться могу) вещь крайне похожая на type classes, откуда ты высосал ее критику -- мне не ясно, при нормальном использовании -- лазить по исходнику надо ровно как в хаскеле (а если с их помощью можно исправить кривую библиотеку ее *пользователю* -- это плюс, а не минус)

> так как typedef юзать в сигнатурах функций нельзя

почему?

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

> В примере с max_bound это не так.

1. max_bound -- это вообще не функция, а мета-функция. За попытку ее реализовать как функцию надо... ну не буду писать.

2. пусть даже функция -- тогда ее сигнатура T max_bound(T) -- таки функционально зависит (id)

> Зависимый тип можно просто _определить_ в терминах шаблонного параметра. Более слабых отношений определить нельзя.

Можно сделать параметр по умолчанию. Но *интересно*, а какие могут быть более слабые отношения? (желательно пример...)

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

> В С++ эту задницу с зависимостями/требованиями к полиморфному параметру _полностью_ сгружают на пользователся, а в haskell - на компилятор

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

> Что лучше?

вместо пиара лучше расскажи про слабые зависимости.

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

s/(хотя и не все)/(хотя и не все удобно)/

т.к. мета язык (шаблонов) -- полный по тьюрингу

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

http://web.cecs.pdx.edu/~mpj/pubs/fundeps-esop2000.pdf - worth reading (всего 15 страниц)

> > Карринг нипричем.

> я таки подозреваю, что при попытке полноценно юзать карринг из-под плюсов полезут хасклелевские траблы.

Это точно про это? http://en.wikipedia.org/wiki/Currying

Из всего, что обычно надо в C++ - это всякие bind1st и друзья (но бывает и хуже :]).Так как все проверки и вывод типов происходят из точки инстанцирования (где все конкретные типы уже известны) - то не нужно решать никаких уравнений с ограничениями, а значит и проблем особых возникнуть не должно.

> > диагностика

> 1. да сейчас диагностику ошибок проще не читать. я читаю только номер строки и дальше думаю сам.

А как хорошо было бы увидеть "ваш T не является инстансом итератора<число>" а не портянку из угловых скобок. MSVC в этом смысле не такой жуткий, как g++ :[

> 2. concepts это (я ошибаться могу) вещь крайне похожая на type classes, откуда ты высосал ее критику -- мне не ясно, при нормальном использовании -- лазить по исходнику надо ровно как в хаскеле (а если с их помощью можно исправить кривую библиотеку ее *пользователю* -- это плюс, а не минус)


type classes - это шаблонные типы в теримнах C++ (template <class T> structFoo<T> {..} + операции нам ними).
concepts - это ограничения на T для операций. В haskell это обычно делается ограничением на полиморфные аргументы типа такого: (+) :: (Num a) => a -> a -> a

Когда concepts проверяются? На стадии разбора кода шаблона или в точке инстанцирования?
Почему нельзя дать программисту по рогам за то, что он вписал не все ограничения, которые использовал в коде шаблонной функции? Это же легко проверить до инстанцирования. Пусть гад напишет, что ему нужен не только random_access_iterator, но и кое-какие арифметические операции над значениями, к которым с его помощью можно добраться. А нельзя, потому что замучаешься описывать. В том же stl такие дикие требования к типам хранимых значений и распределителей памяти, что их вообще фиг чем опишешь (и соблюдешь, шутка :]).

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

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

> > так как typedef юзать в сигнатурах функций нельзя

> почему?

Не знаю. Наверное, чтобы ухудшить и так нездоровое число полиморфных параметров в шаблонах :]

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

>> В примере с max_bound это не так.

> 1. max_bound -- это вообще не функция, а мета-функция. За попытку ее реализовать как функцию надо... ну не буду писать.

:]

> 2. пусть даже функция -- тогда ее сигнатура T max_bound(T) -- таки функционально зависит (id)

FD не значит, что зависимость типа выражается в виде формулы, оно ближе к типам отношений в RDB ({1,many}-to-{1,many})
http://en.wikipedia.org/wiki/Functional_dependency
Может, по-русски оно просто звучит по-другому.

> > Зависимый тип можно просто _определить_ в терминах шаблонного параметра. Более слабых отношений определить нельзя.

> Можно сделать параметр по умолчанию. Но *интересно*, а какие могут быть более слабые отношения? (желательно пример...)

В pdf класс Mult и характер ограничений на a b и c.

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

> В pdf класс Mult и характер ограничений на a b и c.

Я там отнюдь не все понял. Вот пока какие отзывы:

1. Вместо многотипового max_bound нужно было привести пример empty_collection -- который должен с легкостью приводиться к типу любой коллекции.

В плюсах с этим могут быть проблемы, если написать

auto x=empty_collection;

мне хотелось бы иметь возможность так писать, причем тип х должен быть вполне конкретным Collection<T>. Но тут все вилами по воде. Вполне возможно, что auto x=empty_collection<T>; предпочтительнее.

2. Mult. В плюсах опять же мы можем написать

int mult(int, int) {...}
и одновременно
long mult(int, int) {...}

возможно, что компилятор не даст даже варнинга, пока мы не попробуем где-то реально заюзать, например f(mult(a,b))

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

3. ну и в целом пдф-ка интересная, жаль, ты не разжевал ее в удобопонятном для меня виде :-)



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