LINUX.ORG.RU

ЛОР, помоги выбрать ЯП для обучения

 , , , ,


1

3

Часто слышу просьбу научить программированию. Хотя пока я этим не занимаюсь, мне стало интересно, какой ЯП выбрать для введения в программирование.

Вот к каким мыслям я пришёл:

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

Не Си и не современные коммерческие языки (Java, C#, Go). Си, хотя примитивный в основе, усложнён из-за окружения, в котором используется. Современные коммерческие языки были созданы для решения проблем индустрии. Проблема общая: я хочу преподавать материал по мере нарастания сложности. Если в языке неизбежно приходится использовать классы или printf, то это затруднит объяснение (не хотелось бы слишком часто говорить «потом узнаешь для чего это нужно»), напугает студента (ему придётся писать код, используя возможности, которые он плохо понимает), создаст неправильное восприятие основ (как будто printf — это какая-то важная часть компьютера или ОС).

В целом, я хочу постепенно наращивать сложность и, если задачу можно решить более простым методом, то выбрать этот метод.

Языки, между которыми я выбираю: Pascal и Python.

Pascal устарел и денег не принесёт (обидно), но это и не является основной целью. Целью является программирование, а не современное окружение.

В частности, я не собираюсь задрачивать студента на Delphi или любой «продвинутый» диалект языка. Это противоречит цели. Я рассчитываю на то, что после должной тренировки “bare bones” нужно перейти на современный язык и это будет легко.

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

Питон мне сложнее оценить, потому что я избегал работы с ним.

Если ограничиться императивным подмножеством, без ассоциативных массивов, классов и мета-классов, list comprehensions, HOF, исключений, то выглядит как альтернатива Паскалю. Хотя меня беспокоит динамическая типизация. Типы — очень важная вещь, хотелось бы чтобы язык помог это донести, а не быть типа «ну да, это важно, но ты забей».

Это все мои мысли.

Что касается практики, то я имел несчастье наблюдать как человек впервые знакомился с программированием, изучая Java на javarush. На это было больно смотреть.

Edit: дальнейшие пояснения по теме:

  • Подробнее про то, почему я считаю, что изучение основ и Паскаль хорошо сочетаются: 1
  • Почему не Си и не ассемблер: 1 2
  • Почему Паскаль: 1 2
  • Почему не Питон: 1
  • Целевая аудитория: 1
  • Почему такая размытая аудитория: 1 2
  • Про важность иерархии: 1


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

вообще не собираюсь там что-то «исполнять».

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

ответ - типы нужны только трусам! сразу отметаем как дурацкий

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

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

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

Какой вопрос, такой и ответ. Миллионы скриптов в мире вполне работают без языковых подпорок в виде типизации.

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

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

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

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

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

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

Интересно, на чем написаны всякие популярные социалочки?

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

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

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

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

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

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

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

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

Интересно, на чем написаны всякие популярные социалочки?

абстрактный вопрос. что такое - «всякие популярные социалочки»? про «миллионы скриптов» речь уже была. и с каких пор «всякие социалочки» стали мерилом в разработке больших проектов?

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

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

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

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

так приведи их!…

В педивикии забанили?

Она, кстати, вообще на пыхе написана. Там всё плохо не только и не столько с типами. Но тем не менее.

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

Это теперь мода такая — при отсутствии вменяемых практических аргументов на чатгопоту ссылаться?

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

я даже не поленился и погуглил на чем написаны «всякие социалочки»

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

https://tproger.ru/articles/na-chem-piwut-sovremennye-socseti--sposobnye-vyderzhat-ogromnyj-potok-lyudej?ysclid=m488du5h1v370693708

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

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

https://tproger.ru/articles/na-chem-piwut-sovremennye-socseti--sposobnye-vyderzhat-ogromnyj-potok-lyudej?ysclid=m488du5h1v370693708

Интеренсные выводы сделаны из отсутствующих фактов (в приведенной ссылке)

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

Это теперь мода такая — при отсутствии вменяемых практических аргументов на чатгопоту ссылаться?

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

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

есть разница между хинтами «компилятору»

и свойствами воплощённого обьедка которые препяцтвуют соблюдающему этикет процу процессировать лопаты в землекому а затем известно каким градусником померять

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

мы про хацкель али про индустриальный коболий какой?

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

А с чего бы, для начала, кто-то начал вообще их складывать?

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

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

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

Я знаю, где у меня число, а где строка.

ты разраб одиночка? мало ли что ты там знаешь. вот как ты считаешь - относительный путь к файлу и абсолютный - совместимы по присваиванию?

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

так ты хацкел с милнерами обороняешь

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

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

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

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

ты разраб одиночка?

Я вообще девопс.

мало ли что ты там знаешь.

Достаточно.

вот как ты считаешь - относительный путь к файлу и абсолютный - совместимы по присваиванию?

Естественно. А код, который сам явно не резолвит имя файла перед использованием — говнокод.

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

Естественно. А код, который сам явно не резолвит имя файла перед использованием — говнокод.

Эээ… нет? Потому что это ломает огромную кучу кейсов?

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

Естественно. А код, который сам явно не резолвит имя файла перед использованием — говнокод.

вот потому ты и девопс. потому что когда код уже начал «резолвить» мусор - это уже поздно. у тебя уже самолет может упасть или взорваться атомная станция.

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

Нет, ты всё-таки шизу пишешь. Получили относительное имя файла, перед использованием оттранслировали в абсолютное. Что при этом сломается?

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

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

Короче, завязываю кормить.

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

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

какие есть «четкие алгоритмы» у функции, которой подставили какую-то чушь?

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

функция ждет относительный путь,

А должна ждать reader, который уже автоматом преобразует путь к файлу (не важно асолютный или относительный) в поток символов.

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

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

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

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

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

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

функция ждет относительный путь, ей дают абсолютный.

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

функция ждет градусы цельсия, ей дают фаренгейты и наоборот.

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

какие есть «четкие алгоритмы» у функции, которой подставили какую-то чушь?

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

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

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

да ты чо!!! просто это описывается как разные типы.

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

если есть конструктор фаренгейтов из цельсиев и он верно написан - он сделает нужное преобразование. если не написан - просто будет ошибка.

в твоем же мире - все пройдет гладко. и будет заведомо ошибкой.

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

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

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

Типы это дополнение к документации, чем лучше система типов, тем лучше они описывают код. И тем больше компилятор добавляет проверок, и оберегает программиста от ошибок.

Код меняется, меняется документация, старый код может стать неправильным, новый может писаться по старой документации.

Еще типы это огромный буст для инструментов, и IDE, например автокомплит сразу становится адекватным и точным.

Вот видео с примером функции на C и Rust. На С определение выглядит простым, но не раскрывает важных принципов ее работы, и не защищает от ошибок.

https://youtu.be/WiPp9YEBV0Q?t=537

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

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

Нет, вообще не так. У меня есть число 20. Я его передаю в конструктор фаренгейтов, думая, что это фаренгейты. А это цельсии. Эту ситуацию вообще никак не отловить. Горожением типов ты просто передвигаешь место возникновения ошибки: не при передаче в функцию, а при передаче в конструктор.

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

И что мне мешает передать цельсии в конструктор для фаренгейта?

Компилятор

// Цельсий
struct C { double value; };
// Фаренгейт
struct F { double value; };

C operator ""_C(long double);
F operator ""_F(long double);

// Цельсии в фаренгейты
F c2f(C x) {
    return { x.value * 123 };
}

int main() {
    // Температура в фаренгетах
    auto temp = 10.0_F;
    auto temp_in_f = c2f(temp); // gcc error: could not convert 'temp' from 'F' to 'C'
}

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

Нет, ты всё-таки шизу пишешь. Получили относительное имя файла, перед использованием оттранслировали в абсолютное. Что при этом сломается?

  • Multicall binary. Открывал /bin/mkdir, отрезолвил в /bin/busybox.

  • TOCTOU race. Открывал симлинк, в процессе его атомарно заменили через move, получил гонку на пустом месте.

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

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

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

Тогда все становится ещё более непонятно: зачем резолвить локальные пути? Что это дает, кроме траты времени на обход дерева?

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

Минуточку, а юзер их так же будет вводить? 10.0_F и 10.0_C?

Цельсии и фаренгейты да.

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

Можно их в каком угодно виде передавать. Я не особо понял что это дает. Ты хочешь сразу с буквой C/F, что бы сохранить тип? Можно так, и проверять при входе в функцию. Или сделать num = unpackOnlyC().

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

Преимущество ЦПП тут: Это все понимает IDE, это проверяется статически и при изменении кода тебе укажут на места где это может сломаться, все преобразования выбрасываются компилятором потому что они существуют только в CompileTime.

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

Бывают ситуации, когда у модулей, конфигов и прочего надо поменять вложенность. А они друг на друга ссылаются через ../a/b/c какие-нибудь. Добавить к этому разницу между $PWD и непосредственно каталогом с исполняемым скриптом — и вот уже проще получить корневой каталог в абсолютном виде и резолвить относительно него, чем уповать на какие-то внешние механизмы.

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

а она такой диры не знает. и что ей делать-то?

У процесса есть рабочая директория на этот случай. Вот её и использовать.

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

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

P.S. Это не в рамках срача строгая/слабая типизація. Просто конкретно ваш пример захотелось обсудить.

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

У меня есть число 20. Я его передаю в конструктор фаренгейтов, думая, что это фаренгейты.

Ну с тем же успехом вы можете сказать: „У меня есть число 20, а на самом деле 25, я просто опечатался“. Против лома нет приёма. Зато когда у вас будет результат конструктора фаренгейтов и результат конструктора цельсиев, вас компилятор отругает, если вы захотите сложить их друг с другом.

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

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

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

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

А потом надо написать fopen и какой тип ставить? Или делать две версии fopen? Или передавать вариантный тип?

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

когда с ними в сериализованном виде таскать обозначение этой самой размерности

Где это в моем коде? Или ты так типы назвал? Разницу между твоим подходом, и ЦПП я в комментарии описал.

К предоставляемым самим ЯП типам это не имеет никакого отношения

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

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

Бывают ситуации, когда у модулей, конфигов и прочего надо поменять вложенность. А они друг на друга ссылаются через ../a/b/c какие-нибудь. Добавить к этому разницу между $PWD и непосредственно каталогом с исполняемым скриптом — и вот уже проще получить корневой каталог в абсолютном виде и резолвить относительно него, чем уповать на какие-то внешние механизмы.

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

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

По-моему в zig какой-то такой упорин и есть.

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

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

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

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

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

Совершенно незачем. И именно по этому и нужна проверка.

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

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

Это точно будет медленнее если не применять особые ухищрения и не создавать экстеншены на С. Это точно не будет подхватываться стат.анализаторами и IDE если не писать к ним свои плагины для каждой библиотеки.

Я еще считаю что это выйдет длиннее.

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

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

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

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

тоже мне, архитектор там завелся. архитектура тут вообще не причем.

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

потому являются разными типами по определению.

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

аналогично часы и минуты.

Три часа плюс пятнадцать минут будет три часа пятнадцать минут. Привет.

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

Нет, вообще не так. У меня есть число 20. Я его передаю в конструктор фаренгейтов, думая, что это фаренгейты. А это цельсии.

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

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

Три часа плюс пятнадцать минут будет три часа пятнадцать минут. Привет.

нет. в идеологии, где «все является строкой», это будут или 18 часов, или 18 минут. ибо строки между собой неразличимы. а выбор - часы или минуты, будет делаться в зависимости от времени суток

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

А потом надо написать fopen и какой тип ставить? Или делать две версии fopen? Или передавать вариантный тип?

в fopen параметр вообще строка. если вы хотите использовать fopen «as is». то просто конвертируете любой из типов в строку, явным образом, во имя сильной типизации.

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

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

Будь я психиатром и услышь: „Три часа плюс пятнадцать минут будет 18 часов или 18 минут, в зависимости от времени суток“, то в дурку я бы вас может и не отправил, а вот справку на допуск к автоправам или разрешению на оружие вы бы у меня не получили. Кто его знает, может вы потом людей начнёте давить или в школе сводить счёты с хулиганами. Не хочу брать грех на душу.

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

То есть если этой проверки не будет, я внезапно захочу это сделать?

Можете сделать нечаянно и не заметить, пока ракета не упадёт или химический завод не взорвётся. У вас, в сущности, есть два пути: а) переучить США с фаренгейта на цельсии, с галлонов на литры, и с фунтов на квадратный дюйм в паскали; б) как-то программными средствами исключить возможность обработки неправильных данных в неожиданном месте.

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

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

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

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

так это ваши проблемы

У меня нет проблем. У меня три часа плюс пятнадцать минут будут три часа пятнадцать минут.

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

в fopen параметр вообще строка. если вы хотите использовать fopen «as is». то просто конвертируете любой из типов в строку, явным образом, во имя сильной типизации.

Я правильно понял, что вы предлагаете следующий путь исполнения:

  1. Взять строку path-to-a-file.
  2. В зависимости от, сконструировать объект AbsolutePath(path-to-file) или RelativePath(path-to-file).
  3. Носиться потом с этими AbsolutePath и RelativePath ни дай Боже им смешаться.
  4. Скастовать из Абсолютного/Относительного пути обратно исходную строку.
  5. Передать её fopen.

?

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

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

ну вот пусть есть функция add_hour_min(hour, min)… «сложить минуты и часы».

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

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

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

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

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

В многих диалектах задается размер переменной db, dd и ее нельзя положить просто так в регистр другого размера без каста. Даже в таких низкоуровневых языках думают о типах!

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

Кхе-кхе zig:

    const file = try std.fs.openFileAbsolute(path, .{ .read = true });
anonymous
()
Ответ на: комментарий от rebforce

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

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

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

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

Есть только мааааленькая проблема: чтобы придумать красивый дизайн, надо знать как язык внутри работает. Потому что «плохой дизайн» это на 90% попытки идти поперек того, как в языке принято что-то делать. Чуваку, которому «A = B + C» сложно понять, это тупо не под силу.

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

а как вы узнали, где часы, а где минуты?

Это уже другой вопрос. Главное, что логически, с точки зрения логики предметной области, сложение часов и минут оправдано. Даже сложение лопат с землекопами оправдано и имеет смысл. Лопата + землеком = один готовый к работе землекоп *). А Лопата + землекоп + бутылка водки = один землекоп, которому нужно получить нагоняй от бригадира. Такая вот арифметика.


  • обратите внимания, результат вычисления выражения тут стоит справа от знака =. Потому что это удобно и наглядно.
ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Можете сделать нечаянно и не заметить

Чтобы этого не происходило, грамотная архитектура приложения куда важнее обмазывания типами.

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

грамотная архитектура приложения

Это сложно. А жизнь и так сложная. Хотелось бы помогайку какую, в конце концов IT должно облегчать жизнь людям, разве нет?

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

Это уже другой вопрос.

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

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

Это сложно.

Это то, чему надо обучать при обучении программированию (тема-то о нём) вместо всяких public static void main.

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

а что за сущьность вообще складывает

это часы бампять себя минутами

али минуты вливаются в часы

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

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

ааааа?

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

Лопата + землеком = один готовый к работе землекоп

то есть 1 + 1 = 1. занимательная арифметика. дело приняло еще более мутный оборот…

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

ну допустим обеденный перерыв наступает в час дня и длится 45 минут. вопрос к знатокам - в какое время закончится обеденный перерыв?

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

защиты от дурака способствуют только нагромождению этих самых дураков

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

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

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

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

ващет это вариант реализации

где землекоп владеет лопатой

и тем отличается от землекопа без владения лопатой

ибо «готовый к работе» в этом тезаурусе отличается от свеженанятого землероя

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

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

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

обеденный перерыв не обладает субьектностью

следует отличать всёж язык профанов и шорткаты в нём от настоящий_речиТМ

и да наступить оп не может ножек нет

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

то есть у нас стало три типа - землекоп без лопаты, лопата и землекоп с лопатой.

вопрос насколько они совместимы между собой? можно ли переменной типа «землекоп_с_лопатой» присвоить значение «землекоп_без_лопаты». и не будет ли это отьявленным очковтирательством?

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

«Вы и так будете постоянно падать с велосипеда, поэтому советуем маленькие колёсики оставить навсегда».

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

это тот самый вопрос.

Ответ на который зависит от задачи и специфики проекта. Может быть любым в общем случае. Даже таким:

> (defn clock-calc-for-alysnix [h m]
    (format "%s:%sPM" h m))
> (clock-calc-for-alysnix "3" "15")
"3:15PM"

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

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

Существует чёткий алгоритм трансляции относительного имени файла в абсолютное.

Причем в виндах с их C:,D: и так далее - он отличается от линуксового. Или вы всё еще не мультиплатформенный софт?

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

то есть 1 + 1 = 1. занимательная арифметика

Вас же в реальной жизни не смущает, что один мужчина и одна женщина образуют одну семью?

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

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

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

вполне возможно. но не в результате суммы нетипизированных значений. :)

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

и актуальный вопрос - два мужчины дают семью?

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

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

Напомнить про спутник, который упал из-за того что она половина программы думала что надо метры, а вторая – что футы?

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

А должна ждать reader, который уже автоматом преобразует путь к файлу (не важно асолютный или относительный) в поток символов.

Можно подумать нельзя корректно разобраться с путями без такой заумности как вы написали. Причем тут «поток символов»? Путь к файлу в распространенных ОС это строка заканчивающаяся нулём.

Таким программистам дай волю,так они изобретут нечто жутко объектное, решающее задачу преобразования путей для всех ОС,существующих в мире с середины прошлого века по сей день. И только потом применят «это» в создаваемой программе. Естествено что в этом мегауниверсальном комбайне будет куча ошибок и он будет тормозить при открытии каждого файла.

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

вполне возможно. но не в результате суммы нетипизированных значений. :)

В моём мире обычно в ЗАГС идут, потом, возможно в Церкви венчаются.

и актуальный вопрос - два мужчины дают семью?

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

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

Это то, чему надо обучать при обучении программированию (тема-то о нём) вместо всяких public static void main.

Современный Hello World на Java кстати выглядит так (весь файл):

void main() {
  System.out.println("Hello, World!");
}
Небывалый прогресс я считаю!

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

Это не заумь, это упрощение. Задача прочитать содержимое файла состоит из нескольких этапов: 1. Понять откуда читать; 2. Прочитать оттуда сырые байты; 3. Как-то проинтерпретировать эти данные и положить их в структуру данных нужного формата. Логично, чтобы за каждый этап отвечала своя функция, реализующая соответствующий интерфейс.

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

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

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

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

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

Ada позволяет задать предельные диапазоны для типов

Проверяется во время компиляции или исполнения?

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

Путь к файлу в распространенных ОС это строка заканчивающаяся нулём.

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

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

Я знаю, где у меня число, а где строка

иногда в команде насчитывается больше одного человека.

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

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

Иногда всё-таки команда не состоит из не умеющих читать и писать документацию

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

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

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

У меня есть число 20.

Если это «просто число» (int или float) то да, его можно передать ошибочно в функцию которая принимает int или float.

А вот если это Ada то там такого можно избежать. Подробные объяснения (на русском!) и с примерами можно почитать тут: https://reznikmm.github.io/learn/courses/safe-secure-software-ru/chapters/chapter_02.html

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

а юзер их так же будет вводить? 10.0_F и 10.0_C?

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

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

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

Это цитирования моего работающего примера на С++, там используется подчеркивание.

ЛОР, помоги выбрать ЯП для обучения (комментарий)

temp = 10.0_F;

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

Sub-enums и ограниченные float значения хранимые в виде целых чисел выглядят очень вкусно, в других языках такого не видел. Полезно было бы везде.

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

Полезно было бы везде.

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

(s/def :num/big-even (s/and int? even? #(> % 1000)))
(s/valid? :num/big-even :foo) ;; false
(s/valid? :num/big-even 10) ;; false
(s/valid? :num/big-even 100000) ;; true
ugoday ★★★★★
()
Ответ на: комментарий от ugoday

В С мы это называем assert. Когда это заведено через типы, писанины и ручного контроля меньше.

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

программистам дай волю,так они изобретут нечто жутко объектное, решающее задачу преобразования путей для всех ОС,существующих в мире

Ага. Вот в CL у пути должно быть 6 компонентов: файловая система, устройство, каталог, имя, тип, версия.

(make-pathname :host "KATHY"
               :directory "CHAPMAN" 
               :name "LOGIN" :type "COM"))
=>  #P"KATHY::[CHAPMAN]LOGIN.COM"

И каталог может быть абсолютный как в примере выше или относительный:

(make-pathname :directory '(:absolute "foo" "bar") :name "baz")
#P"/foo/bar/baz"
(make-pathname :directory '(:relative "foo" "bar") :name "baz")
#P"foo/bar/baz"
monk ★★★★★
()
Ответ на: комментарий от monk

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

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

А ведь жизненная задача-то. Обмазалиь вы типами со всех сторон, реализовали тип-«Мужчина», у которого в качестве обязательного параметра — длинна члена в дюймах, для сортировки или чем вы там ещё грязные извращенцы занимаетесь. Продали значит, свой рыночный продукт к нам в ЕС, а тут, внезапно, у мужчины члена не может быть вообще. И что теперь?

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

Ага. Вот в CL у пути должно быть 6 компонентов: файловая система, устройство, каталог, имя, тип, версия.

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

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

А ведь жизненная задача-то. Обмазалиь вы типами со всех сторон, реализовали тип-«Мужчина»,

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

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

то есть тип «семья» у вас определен неточно. отсюда и проблемы.

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

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

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

Если на вопрос: „Ты за Сталина или за Троцкого“, вы ответите it depends, то вас гарантированно расстреляют. Есть вопросы, на которые нужно отвечать твёрдо и чётко, мужественно смотря в глаза товарищу гендеркомисару.

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

Если на вопрос: „Ты за Сталина или за Троцкого“, вы ответите it depends, то вас гарантированно расстреляют.

дожили…неужели в ваших европах все так страшно?

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

Три часа плюс пятнадцать минут будет три часа пятнадцать минут.

Так как часы и минуты не подчиняются правилам десятичной системы счисления то просто сложив 3(часа) и 15(минут) вы получите бессмысленное число 18 непонятно чего. Для правильной работы с часами и минутами надо создать специальный тип который будет хранить в себе числа минут и часов и специальные функции для сложения-вычитания времени. Бывает весьма актуально для всяких административно-бухгалтерских расчетов.

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

В стандартной поставке есть jshell, поэтому можно сократить:

% cat main.java 
System.out.println("Hello World");

% jshell main.java
Hello World

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

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

Хранить проще в unix time. Время вычитать наверное никому особо и не надо, вот работа с датой это полезно, тут лучше взять готовое.

В PHP отличная работа с датой и временем, понимает даже некоторый человеческий ввод:

new DateTime("last day of next month")

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

Да разве ж это страшно, «Зольдатен, фойер!» и всё, капут. Даже больно не будет. Но это не точно конечно. Хуже, если вашим делом займётся берлинская полиция.

Но, ладно, это уже политота пошла. А вопрос хрупкости системы типов — серьёзный. Вы, вот, были уверены, что люди делятся на мужчин и женщин, заложились на это, а потом вжух — новые бизнес требования. И всё по новой рефакторь. Обидно.

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

Вы, вот, были уверены, что люди делятся на мужчин и женщин, заложились на это, а потом вжух — новые бизнес требования. И всё по новой рефакторь. Обидно.

Как это произошло? Использование boolean? Ну это как минимум не интуитивно, кто true а кто false?

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

а) переучить США с фаренгейта на цельсии, с галлонов на литры, и с фунтов на квадратный дюйм в паскали;

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

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

Хранить проще в unix time.

Дополнительная секунда добавляется по астрономическим наблюдениям в конце суток по всемирному времени 30 июня или 31 декабря так, чтобы время UTC не отличалось от UT1 более, чем на ±0,9 секунды. Считается, что в такие дни после времени 23:59:59 идёт 23:59:60[8].

Время вычитать наверное никому особо и не надо,

В смысле? А как, например, начало Страстной Седмицы определять? С вычитанием получается легко и изящно: $ДатаПасхи - 7 дней.

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

Как это произошло?

В детстве нравилось собирать конструктор. Вот такой примерно. Потом математика с физикой в школе хорошо пошли и вот, вжух, сижу тут с вами, придумываю типы данных для описания реальности.

Использование boolean?

Каким типом вы предложите описать размер ноги?

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

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

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

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

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

Встречаются два приятеля:
— Ты, я слышал, машину купил?
— Да, хорошая вещь, теперь везде успеваю. Сегодня за день успел сменить
масло в двигателе, купить новые покрышки, съездить на авторынок за
крыльями, сгонять в автосервис, заехать в автомагазин за тосолом... И
как бы я все это без машины успел?
ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Типизация облегчает рефакторинг, вызванный типизацией.

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

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

Проясните, что будет делать ваша функция если ей на вход подать 32 часа и 65 минут?

Задача экспорта ПО в ЕС решается использованием композиции массива «части тела». Там даже мутанты подойдут в таком случае.

В целом, мне видится, так что противники строгой типизации пропустили лекции по философии касательно понятия «категория». Им кажется, что Аристотель, Кант и Гегель какую-то фигню толкали.

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

Потому что «плохой дизайн» это на 90% попытки идти поперек того, как в языке принято что-то делать.

Вот тут не соглашусь с вами. Тем более про 90%. Плохой дизайн - он плохой вообще независимо от языка. Это так сказать следующий уровень абстракции. К примеру ожидание какого-нибудь события наглухо блокирующее работу интерфейса программы - это плохо на любом языке. Есть такой вобщем-то хороший почтовик Sylpheed,но если он полез за почтой по меееедленному каналу(через сотового оператора) то даже буквы в окне редактирования письма набираться перестают. Полное ощущение повиса. Аналогично,попадаются программы которые ничего полезного не делая тем не менее крутят холостые циклы и жрут электричество. Раньше часто встречалось,сейчас намного реже. Опять от языка не зависит. Даже на сайтах в скриптах попадается,тогда кушать начинает браузер с просто открым этим сайтом. А черезмерное использование глобально доступных переменных для связи между частями программы вместо передачи значений в виде параметров вызываемых функций. Тоже на разных языках такое нагородить можно.

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

в конце концов IT должно облегчать жизнь людям, разве нет?

Облегчения от него ничуть не больше чем новых неприятностей. Особенно если IT оказывается «на госслужбе».

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

1 + 1 = 1. занимательная арифметика.

Если «+» рассматривать как логическое сложение,то есть операцию ИЛИ, то выражение вполне корректно написано.

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

а новый год может наступить?

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

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

Всё хорошо только до тех пор, пока системы типов хватает.

Вот есть функция mapcar. Какой у неё тип? Первый агрумент «какая-то функция», а остальные «какой-то список»? Или надо на языке типов описать что-то вроде «первый аргумент является функцией, принимающей количество аргументов, равное количеству остальных аргументов mapcar, имеющих типы, совпадающие с типами элементов списков, являющихся остальными аргументами, mapcar».

Вот и получается, что на Си вместо типов 0.0..100.0 для доли в процентах и -273,15..+∞ для температуры в градусах Цельсия используют double. Потому что система типов не позволяет.

после некоего навыка это происходит автоматически

Беда в том, что после некоего навыка человек просто перестаёт писать функции, которые не укладываются в систему типов. Он просто теряет возможность их помыслить. Если система типов достаточно мощна, как в Agda или Typed Racket, это не очень критично. Если же она ограничена как в Си или Паскале, то даже простейшую функцию, возвращающую композицию двух функций даже помыслить тяжело.

На Си++ такую функцию можно написать, но у неё нельзя описать тип.

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

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

Безусловно да. Ну так и пишите функции. А выдумали какие-то reader`ы,потоки… Я именно к этому докопался,а не к тому что процитировал.

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

Проверяется во время компиляции или исполнения?

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

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

Дополнительная секунда добавляется по астрономическим наблюдениям в конце суток по всемирному времени 30 июня или 31 декабря так, чтобы время UTC не отличалось от UT1 более, чем на ±0,9 секунды. Считается, что в такие дни после времени 23:59:59 идёт 23:59:60[8].

Unix time прекрасен тем что про все это позволяет забыть.

В смысле? А как, например, начало Страстной Седмицы определять? С вычитанием получается легко и изящно: $ДатаПасхи - 7 дней.

Это уже даты как раз, а ограничение на часы/минуты/секунды мало интересно.

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

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

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

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

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

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

На вопрос ответа не увидел. Если пол был enum, то что мешает добавить еще сколь угодно пунктов?

Каким типом вы предложите описать размер ноги?\

Странный вопрос, ну допустим я продаю обувь. Заведу справочник с размерами, где точно будет указан тип измерения, потому что они бывают разные, и его строковой вид. Числовое представление ОтДо по возможности и желанию.

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

гендеркомисару

лови шпиёна

гендеркомисаро гендерно нейтрально без этого вашего шовена

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

Вот есть функция mapcar. Какой у неё тип?

Посмотри на С++, там есть аналогичная функция.

Вот и получается, что на Си

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

Беда в том, что после некоего навыка человек просто перестаёт писать функции, которые не укладываются в систему типов.

Не верю.

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

Это исходит не из за трудности типов, а из за того что это ненужная шняга которая плохо ложиться на железо.

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

ограниченные float значения хранимые в виде целых чисел выглядят очень вкусно

Там еще и типы с фиксированной точкой есть. Тоже полезная штука. И всё это есть аж с 1983 года. А в 1993 уже был доступен свободный компилятор Gnat (и коммерческий от Meridian Software тоже). В смысле что я сам именно тогда тем и другим пользовался,хотя «Меридиан» под ДОСом лучше работал. Но людям всё равно Лень изучать Аду. Будут продолжать с С++ мучиться.

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

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

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

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

Продали значит, свой рыночный продукт к нам в ЕС, а тут, внезапно, у мужчины члена не может быть вообще. И что теперь?

Указывать нулевую длину например. Например когда у мужчины нет денег на счете в банке указано 0. Хотя существует мнение что без денег это не мужчина а самэц:) https://www.anekdot.ru/id/-10088000/

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

Если пол был enum, то что мешает добавить еще сколь угодно пунктов?

Что указывать в качестве длинны члена для мужчин без члена (зато с сиськами!).

Странный вопрос, ну допустим я продаю обувь. Заведу справочник с размерами, где точно будет указан тип измерения, потому что они бывают разные, и его строковой вид.

И тут в ваш магазин приходит квадробер.

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

Указывать нулевую длину например.

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

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

тут, внезапно, у мужчины члена не может быть вообще

КСЖ!

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

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

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

Будет легче если ты будешь нормально писать, а не как сиделец из дурки. Я читаю с самого начала.

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

Вот и получается, что на Си вместо типов 0.0..100.0 для доли в процентах и -273,15..+∞ для температуры в градусах Цельсия используют double. Потому что система типов не позволяет.

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

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

просто скажите что вам нужно, и не блуждайте в потемках формальной логики

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

mapcar // Посмотри на С++, там есть аналогичная функция.

Где? Как называется, в какой библиотеке? Если речь про std::transform, то он только 2 или 3 аргумента принимает, а не сколько угодно как mapcar. И у неё нет типа, так как она шаблон-макрос.

Не верю.

По себе замечал, когда переходил с CL/Racket на Haskell. Если на CL написанная мною функция, использующая битовое поле, позволяла вызывать себя с числом, списком символов, символом.

(set-state 3)
(set-state :ok)
(set-state '(:wait :red))

то в Haskell строго

setState [Ok]
setState [Wait, Red]

Потому что писать вариантный тип неуклюже (лишнее слово на каждый вызов).

А если вдруг всё-таки надо число, то setState $ intToState 3

Везде, где результат был «значение или ошибка» как в cl:nth, ошибка заметается под ковёр как в Haskell a[x].

а из за того что это ненужная шняга которая плохо ложиться на железо.

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

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

просто скажите что вам нужно, и не блуждайте в потемках формальной логики

auto compose = [](auto f, auto g) {
  return [=](auto x) {
    return f(g(x));
  };
};

Попробуйте написать, не используя auto.

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

а не сколько угодно как mapcar

Напиши пример с 4 аргументами, не понимаю о чем ты.

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

А так и не надо делать. Можешь привести пример использования тоже если это просто.

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

Если ты хочешь обобщенную функцию, то auto в самый раз. Так себе у тебя задача. Кстати, обрати внимание что она удобно без GC не решается.

Дальше нужно будет у std::vector тип элемента зафиксировать, и лишь тем самым подтвердить нужность типизации?

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

Попробуйте написать, не используя auto.

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

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

Если ты хочешь обобщенную функцию

это не обобщенная функция, а просто шаблон для построения конкретных функций.

alysnix ★★★
()
Ответ на: комментарий от monk
#include <iostream>

template <typename X, typename Gr, typename Fr>
struct compose {
  using G = Gr(*)(X);
  using F = Fr(*)(Gr);
  G g; F f;
  compose(G g, F f) : g{g}, f{f} {}
  Fr operator()(X x) { return f(g(x)); }
};

int add10(int x) { return 10; }
float mul125(int x) { return x * 1.25; }

int main() {
  auto f = compose{add10, mul125};
  std::cout << f(5) << "\n";
}

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

Это полезно лишь в динамической программе, но этот конкретный подход не очень, в C/С++ хватает библиотек и приложений которые сначала строят план выполнения, а потом очень быстро и хорошо по нему делают какую то работу.

Если все статическое, то не проще ли написать обычную функцию? В Forth это выйдет даже короче чем композиции из хескелов и лиспов.

: z g f ;
5 z
MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 5)
Ответ на: комментарий от ugoday

Вы должно быть из Питера?

Пока нет. Уже словил вайб, когда туда повторно тянет. Вот цены на мавзолеи припадут, а там посмотрим :)

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

Хранить проще в unix time.

Сильно зависит от области применения. Если например это административно-бухгалтерские расчеты (с этим приходилось иметь дел в 90х) - то вычисление каких-нибудь «номочасов» существенно отличается от астрономического времени. Есть «нормочас»,может использоваться (а может и не) половина нормочаса. Это надо согласовать с бухгалтерским начальством и его сложившейся практикой учета. Не бывает нормоминут и нормосекунд. Поэтому хранить и считать надо в минимальных используемых единицах - если это часы то в часах,если есть половинки то в половинках. И всячески избегать операций деления и округления,которые дают дробные «хвосты»,накапливающиеся к концу отчетного периода. Кстати,правильное округление это две страницы текста в старом математическом справочнике для экономистов. В школьном учебнике вам соврали что это просто. Далее,при переводе нормочасов в количество рабочих смен,которое официально предписывается «производственным календарем»(докУмент,который утверждает Минтруд) - бывают свои казусы. Например ночная работа может учитываться с каким-нибудь коэффициентом. И это я еще далеко не всё перечислил с чем сталкивался.

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

Вспомним Гаусса,который сказал: «Недостатки математического образования с наибольшей отчётливостью проявляются в черезмерной точности численных расчётов» - это к вопросу об использовании числа секунд с 1970 года.

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

Напиши пример с 4 аргументами, не понимаю о чем ты.

* (mapcar 
    (lambda(x y z) (+ x (length y) (car z)))
    '(1 2 3)
    '("ok" "test" "go")
    '((1 2) (3 4) (5 6)))
(4 9 10)
monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Как это произошло? Использование boolean?

Правильнее будет использовать перечислимый тип,который при необходимости не трудно дополнить новыми возможными гендерами. По разным подсчетам сейчас существует от 46 до 78 гендеров. Например Tinder использует 36 гендеров для более точной самоидентификации своих пользователей.

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

Сильно зависит от области применения.

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

то вычисление каких-нибудь «нормочасов» существенно отличается от астрономического времени.

А это не время.

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

Хранить надо так, что бы потом можно было пересчитать %) То есть источники расчетов.

И всячески избегать операций деления и округления

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

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

Время и даты в человеческом виде действительно очень и очень сложная штука, unix time это легко.

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

(lambda(x y z) (+ x (length y) (car z)))

Тут достаточно заменить лисповое определение lambda на void lambda(std::any_container<>), потому что именно как то так твои «аргументы» в нее и будут попадать.

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

А так и не надо делать. Можешь привести пример использования тоже если это просто.

Любой шаблон Си++. На каждую комбинацию типов создаёт по функции.

Если

void qsort(void *base, size_t nmemb, size_t size,
   int(*compar)(const void *, const void *));

имеет одно тело, то std::sort для каждой пары «тип итератора» + «тип функции сравнения» будет создавать по копии тела.

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

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

monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA
template <typename X, typename Gr, typename Fr>
struct compose {

Угу. Типы. Как бы произвольные. Но на самом деле не произвольные, а какие именно сможете угадать, если прочитаете реализацию класса. А при любой ошибке получите «no matching function» без указания, какие типы возможны.

но нужность хотя бы одной композиции еще нужно выяснить

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

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

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

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

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

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

в рамках с++ это шаблон функции, а не функция…

Вот я про то же. А в таком же статически типизированном Haskell это нормальная функция с типом (b -> c) -> (a -> b) -> a -> c. Ограничения системы типов ограничивают возможные алгоритмы.

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

Угу. Типы. Как бы произвольные.

Да.

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

Плохо может назвал, но по сигнатуре можно сделать более понятно. И в IDE видно будет.

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

Я не пишу на С++ вообще, я не знаю его. Просто композиция объективно вредна.

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

Суть же в произвольном количестве?

#include <ranges>
#include <vector>
#include <array>
#include <iostream>
#include <numeric>

int main() {
    std::vector<std::vector<int>> v = {{1,2, 5}, {3,4}, {9}};
    auto r = v | std::views::transform([](auto arr){ return std::reduce(arr.begin(), arr.end()); });
    for (int i : r) {
        std::cout << i << "\n"; // 8 7 9
    }
}

Потому что если суть в разнородной структуре входных данных, то непонятно зачем тут mapcar. Начинать надо с того, как эту структуру хранить, я бы сказал что не надо хранить неопределенную по типу структуру вовсе. Если нужна реально динамика, то она строится поверх статики со своими правилами. Так же и в DB есть строгая таблица но можно перейти к EAV если очень нужно. Думаю работа с таблицами тебе более понятна по роду деятельности, или они тоже динамические у тебя?

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

Любой шаблон Си++. На каждую комбинацию типов создаёт по функции.

Ты не так понял, я просил пример использования твоей композиции в С++ коде.

Шаблон создает не для каждой комбинации, и ничего не мешает обернуть c-qsort-подобную функцию в шаблон.

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

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

В справочник засунь.

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

суть в разнородной структуре входных данных

Именно в них.

то непонятно зачем тут mapcar

Есть

int f(int x, std:string s, std::vector<int> z)
{
  return x + s.length() + z[0];
}

Как сделать

mapcar(f, {1, 2, 3}, {"a", "b", "c"}, {{1,2}, {3,4}, {5}})

?

Или вообще как-то менее уродливо, чем

for(auto i = a.begin(), j = b.begin(), k = c.begin();
    i != a.end() && j != b.end() && k != c.end();
    i++, j++, k++) { f(*i, *j, *k); }
monk ★★★★★
()
Ответ на: комментарий от monk

Как сделать

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

С такой узкой постановкой без контекста, довольно трудно что то ответить, но например я бы рекомендовал перевести сначала это в формат int[][3], а там глядишь даже массив не понадобится, прямо в функции конвертации все вычислишь.

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

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

Ты не так понял, я просил пример использования твоей композиции в С++ коде.

Ответ был на «Вот не уверен, что необходимость копипастить 100500 раз один и тот же код с чуть-чуть разными типами лучше ложится на железо.» / «А так и не надо делать. Можешь привести пример использования тоже если это просто.»

Что касается композиции, она очень активно используется в коде на Haskell. А на Си++ она очень жутко тормозит, поэтому практически неработоспособна.

Шаблон создает не для каждой комбинации, и ничего не мешает обернуть c-qsort-подобную функцию в шаблон.

Для каждой используемой. А если qsort обернуть в шаблон, то обёртка тоже начнёт копироваться на каждую используемую комбинацию типов.

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

Ответ был на «Вот не уверен, что необходимость копипастить 100500 раз один и тот же код с чуть-чуть разными типами лучше ложится на железо.» / «А так и не надо делать. Можешь привести пример использования тоже если это просто.»

А, ну c_qsort элементарно оборачивается в шаблонную функцию.

Что касается композиции, она очень активно используется в коде на Haskell. А на Си++ она очень жутко тормозит, поэтому практически неработоспособна.

Лол, а пруфы есть? Потому что я не представляю какую оптимизацию Haskell может использовать, скорее всего никакую и еще GC сверху.

Для каждой используемой.

Если в машинном коде результат одинаковый то нет.

А если qsort обернуть в шаблон, то обёртка тоже начнёт копироваться на каждую используемую комбинацию типов.

Это не будет отличаться от обычного вызова qsort из С, то есть никакого копирования на самом деле не будет, скорее будет вызов. Ты же понял идею? Вызываем c_qsort() из template функции. Это одна строка в теле.

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

Для начала нужно не допускать что бы у тебя появились такие входные данные.

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

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

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

Так вот, читаешь из файла свою разнородную информацию, потом переводишь в int[][3], потом вызываешь sum. Компилятор векторизирует, память попросту не тратится, ошибки еще на этапе чтения устранены. Твое решение в динамике же выглядит очень нехорошо по сравнению, подходит лишь для однострочника.

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

она сломается с непонятной ошибкой, в рантайме

С очень понятной. Будет известно на каком элементе и из какого аргумента пришли неправильные данные.

в статике такое невозможно.

ЛОР, помоги выбрать ЯП для обучения (комментарий) - сломается, если в элементе третьего массива попадётся пустой массив.

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

С очень понятной. Будет известно на каком элементе и из какого аргумента пришли неправильные данные.

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

ЛОР, помоги выбрать ЯП для обучения (комментарий) - сломается, если в элементе третьего массива попадётся пустой массив.

Так это код не по уму, а наоборот. Вот когда у тебя сумма int[] сломается, тогда жалуйся. А такого не произойдет.

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

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

Опять система типов языка ограничивает возможные алгоритмы.

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

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

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

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

mapcar на системе типов сделать легко, реализуешь заново cons ячейки, реализуешь функции для работы с ними, и будет у тебя повторение динамики. Нужно ли такое? Абсолютно нет, так пишут только те кто не умеют программировать. «Заготовочку» из лиспа выучили, а нормально переписать не могут.

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

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

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

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

В смысле? Эти алгоритмы работают. И типы Typed Racket, например, им не мешают. Мешают типы ограниченных систем типизации.

Например, делает человек расчёт по формуле. Си++ заставляет выбрать между тремя типами: float, double, long double. Хотя с точки зрения задачи числа рациональные.

Или ограничение на int на целые значения, даже если это не указано постановкой задачи.

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

Например, делает человек расчёт по формуле. Си++ заставляет выбрать между тремя типами: float, double, long double. Хотя с точки зрения задачи числа рациональные.

Ну сделай свой расчет в классе с шаблонным параметром NumberType. Добавится только строка template <typename NumberType>, все! И вместо float, double погнал NumberType использовать. В чем проблема то?

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

Например, делает человек расчёт по формуле. Си++ заставляет выбрать между тремя типами: float, double, long double.

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

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

и еще. физическая реальность не может мешать. это максима.

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

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

Аналогично,такой же собирал. Начало 70х.

Каким типом вы предложите описать размер ноги?

Я думаю что перечислимым типом. Потому что множество существующих размеров ограничено и не велико даже если взять вообще все какие бывают. Да и называться они могут не только цифрами, а S,M,XXL и тому подобное.

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

Я думаю что перечислимым типом

В ваш обувной заходит квадробер. Теперь размер ноги — это два размера. Для передних ног и для задних.

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

Ну ты бы в моем ответе разобрался сначала. Я предлагал две таблицы

tbl_product и tbl_shoe_size, к одному tbl_product можно привязать сразу несколько значений. Вообще без изменений в итоге решается.

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

Лол, а пруфы есть?

Беру простую программу на Haskell:

$ cat test.hs
module Main where

import System.Environment

main = do
  [x] <- getArgs
  let n = read x :: Int
  putStrLn . show . sum . filter ((== 0) . (`mod` 2)) $ [1..n]

Перевожу её же на Си++ так, чтобы сохранить использование композиции для суммирования/отбора и компоновки условия.

$ cat ./test.cpp
#include <iostream>
#include <string>
#include <vector>
#include <numeric>
#include <algorithm>
#include <cstdlib>

long long sum(std::vector<int> x)
{
        long long result = 0;
        for(int i : x) { result += i; }
        return result;
}

auto filter(auto f)
{
        return [=](auto a)
        {
        std::vector<int> result;
        std::copy_if(a.begin(), a.end(), std::back_inserter(result), f);
        return result;
        };
}

auto compose (auto f, auto g)
{
        return [=](auto x) {
                return f(g(x));
        };
}

int main(int argc, char **argv)
{
        std::vector<int> v(atoi(argv[1]));
        std::iota(v.begin(), v.end(), 1);
        auto cond = compose([](auto x) { return x == 0; }, [](auto x){return x % 2;});
        std::cout << compose(sum, filter(cond))(v) << std::endl;
}

Компилирую, запускаю

$ ghc -O3 test.hs > /dev/null
$ time ./test 300000000
22500000150000000

real    0m0,553s
user    0m0,338s
sys     0m0,016s
$ g++ -O3 -std=c++20 test.cpp -o test-cpp
$ time ./test-cpp 300000000
22500000150000000

real    0m19,740s
user    0m2,097s
sys     0m2,311s
monk ★★★★★
()
Ответ на: комментарий от necromant

что будет делать ваша функция если ей на вход подать 32 часа и 65 минут?

Зависит от прикладной задачи. Например моторесурс дизель-генератора может быть не то что 32 часа,а тысячи часов. И программа должна уметь вычислять интервалы сервисного обслуживания,то есть выполнять арифметические действия с временем. Равно как и 65 минут могут быть вполне корректным значением в тех случаях когда традиционно используются минуты.

Если же задача предполагает что часов не может быть больше 24,а минут больше 60 то объявляем эти типы с ограничением диапазона значений и ни 32 часа ни 60 минут там оказаться просто не может - Аda сразу сгенерирует исключение.

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

Кринж... Две разные программы, в плюсах ты бенчишь заполнение и копирование памяти, вот это занимает более половины времени выполнения:

std::vector<int> v(atoi(argv[1]));
std::iota(v.begin(), v.end(), 1);

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

Всё хорошо только до тех пор, пока системы типов хватает.

Согласен.

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

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

На Си++ такую функцию можно написать, но у неё нельзя описать тип.

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

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

из-за которого такая странная штука потребовалась

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

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

Unix time прекрасен тем что про все это позволяет забыть.

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

ограничение на часы/минуты/секунды мало интересно.

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

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

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

  1. Racket или Python. Типизация не мешает, но при необходимости есть (Typed Racket и Mypy).

  2. Haskell или Idris. Нормальная типизация, позволяющая решить подавляющее большинство задач.

  3. C++. Если скорость выполнения программы очень критична.

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

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

Так если бы Ada была в числе «малореализованных» то я бы и не возникал. А так она есть и под общеупотребительные десктопные ОС и даже под микроконтроллеры STM32 и AVR(наверно и еще какие-то - просто не интересовался). И даже вроде бы есть вариант компилятора Ады,которые генерирует байт-код для андроидной джава-машины. Хотя я это тоже живьем не видел и не уверен что он бесплатный,только слухи слышал.

и библиотек больше.

В Аде есть штатные средства подключения сишных библиотек(не уверен насчет плюсовых). Я например писал когда-то адские «переходники» для подключения библиотеки C-Scape от Oakland Group - и получился хороший экранный интерфейс. Текстовый конечно так как было это году в 93 и дело происходило в ДОСе. Там правда есть тонкость - пакет с переходниками надо вдумчиво писать вручную чтобы хорошо получилось,а не автогенерировать скриптом как это нередко делают.

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

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

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

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

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

а «более выразительные» языки имеют динамическую типизацию,

Хаскелл Карри поперхнулся чаем. А может и джином. Кто его знает. Хаскелла Карри.

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

Что указывать в качестве длинны члена для мужчин без члена

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

И тут в ваш магазин приходит квадробер.

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

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

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

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

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

max(penis_size) / min(penis_size) внезапно возникает деление на ноль

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

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

а «более выразительные» языки имеют динамическую типизацию,

а вот хаскелл …

Да при чём тут вообще хаскел!

Ну, даже не знаю что и сказать.

любой код на хаскел можно преобразовать в код на си.

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

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

можно же пропускать нулевые

Всё можно. Только это будет сокровенное знание как поперёк системы типов реализовать те или иные костыли, чтобы программа хоть как-то работала. А хотелось бы, чтобы система помогала мне, а не ставила очередные вызовы.

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

И что?

И параметр «размер ноги клиента» явно перестаёт иметь смысл. Ну, либо обретает новый смысл, невыразимой вашей старой системой.

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

откуда немедленно ничего не следует.

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

вот то же самое можно сказать о ваших хаскелах, только другими словами.

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

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

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

Перевожу её же на Си++ так, чтобы сохранить использование композиции для суммирования/отбора и компоновки условия.

сдается что monk не до конца понимает, что делает хаскел под капотом, во что это все компилирует и как упрощает.

оттого «аналог» на с++ есть лишь наивное представление монка о хаскеле. и при правильно написанном коде плюсы закопают хаскель гробовой лопатой

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

ОТМАЗКА: Данным сообщением я не хочу сказать, что С++ лучше хаскеля, хуже хаскеля, вообще как-то сравним с хаскелем и любым другим ЯП и вообще, что данный метод подходит к ранжированию языков. Просто решил проверить в интернетах и нашёл странный необъяснимый факт, делюсь наблюдением.

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

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

вычисление каких-нибудь «нормочасов» существенно отличается от астрономического времени.

А это не время.

Пожалуй даже соглашусь с вами что это не время в обычном понимании,а некие учетные единицы типа каких-нибудь «складометров»(в лесном хозяйстве встречаются). И пожалуй что основная причина в том что к «нормочасам» пытаются применять функции предназначенные для работы именно с временем в физическом/астрономическом его смысле. Так что да - однозначно надо объявлять свой тип с скрытой внутренней реализацией и определять функции для работы с ним. Ада это хорошо умеет.

Хранить надо так, что бы потом можно было пересчитать %) То есть источники расчетов.

Это вы немного про другое - про исходные файлы например. Да,согласен. А я под «хранением» имел в виду в данном случае представление в памяти в процессе работы программы. Например в столь милых мне микроконтроллерах стараются вместо дробных чисел использовать целые. Например вместо 1.5 вольта представляют напряжение как 1500 милливольт. Это фактически получается фиксированный тип у которого положение десятичной точки подразумевается в нужном месте(чтобы потом при выводе на экран нарисовать например). И дело тут не только и не столько в медленности операций с float - современные МК считают весьма быстро. А главное это лучшее сохранение точности при вычислениях. Большие целые числа ведут себя лучше чем маленькие дробные. Хорошая статья(и комментарии к ней) про проблемы чисел с плавающей точкой:https://habr.com/ru/articles/337260/

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

А что C++ программисты так мало зарабатывают?

Те кто много знают зарабатывают неплохо, но большинство работ это наверное перекладывание значений бд на qt.

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

А я под «хранением» имел в виду в данном случае представление в памяти в процессе работы программы.

Это да, в расчетах денежных с float работать нельзя. И даже машинные целые нежелательно, а то скоро зарплаты в рублях снова могут стать миллионными, а какие нибудь итоговые суммы за год совсем заоблачные... В 1С и COBOL правильно сделано.

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

перекладывание значений бд на qt.

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

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

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

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

Вот на range, обгоняет Haskell в два раза на моем компьютере. Так что compose на С++ хороший, в Haskell лучше быть не может, это машинное ограничение.

Я думаю тебе не хватает опыта в статических языках и в С++. Я например С++ тоже не знаю, но бенчмарками копий std::vector не занимаюсь все же.

#include <iostream>
#include <string>
#include <ranges>

template <typename F1, typename F2> struct compose {
    F1 f1; F2 f2;
    compose(F1 f1, F2 f2) : f1{f1}, f2{f2} {}
    auto operator ()(auto x) { return f1(f2(x)); }
};

template <typename T, typename R> R sum(T x) {
    R sum = 0;
    for (R i : x) sum += i;
    return sum;
}

auto filter(auto f) {
    return [&](auto a) {
        return a | std::views::filter([&](auto x) { return f(x); });
    };
}

int main(int argc, char **argv) {
    auto v = std::views::iota(0l, atol(argv[1]) + 1);
    auto cond = compose([](auto x) { return x == 0; }, [](auto x){return x % 2;});
    std::cout << compose(sum<decltype(filter(cond)(v)), long>, filter(cond))(v) << std::endl;
}

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

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

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

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

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

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

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

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

для добавления нового гендера нужно будет каждый раз программу перекомпилировать

Ну они же не каждый день добавляются…

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

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

у меня ссылка не открывается. я за железным занавесом.

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

гендер это тензор в 6-мерном изотопическом пространстве.

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

А где по гендерные нововведения почитать?

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

в России пока не слишком актуально.

Считайте, что тут гендер, это как в России национальность.

Про дроби и проценты в этом вопросе не слышал еще.

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

Ну они же не каждый день добавляются…

Бывает и чаще, так что лучше сразу CI/CD настроить.

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

Теперь размер ноги — это два размера.

И что? Почему дополнительные размеры нельзя добавить в тот же перечислимый тип? «Размер» здесь это не число,а признак,даже не обязательно цифрами названный. Может быть и какие-нибудь S,M,XL. Также как цвет не длиной волны указывают,а названием. Ну разрастётся перечислимый тип до нескольки десятков элементов - не фатально. И выберет себе квадробер что там ему надо и для передних ног и для задних. Обычный человек тоже может две пары башмаков купить. И даже разных размеров для лета и зимы. Или разных производителей,маркирующих свою продукцию по-разному.

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

Вот на range, обгоняет Haskell в два раза на моем компьютере.

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

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

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

Она является странной штукой независимо от языка а сама по себе.

Функция, которая принимает две функции и возвращает третью

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

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

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

Haskell или Idris. Нормальная типизация, позволяющая решить подавляющее большинство задач.

C++. Если скорость выполнения программы очень критична.

На Ada скорость ничем не хуже Си. Уж поверьте мне,писавшему на Meridian ADA под DOS на процессоре 80286 с частотой 12 мегагерц. Там даже небольшая разница быстродействия была заметна глазами и без специальных измерений. Если очень прижмет то многие runtime-проверки в готовой релизной версии программы можно отключить. Мне не требовалось.

При этом более чем нормальная типизация,позволяющая решить подавляющее большинство задач. И это у меня компилятор был стандарта Ada83,в котором еще не хватало полезных вещей которые появились в Ada95. И адская многозадачность под дос-экстендером от PharLap работала весьма ограниченно. А сейчас в стандарте Ады есть много всякой экзотики которая похоже только в каких-то авиакосмических спецприменениях и нужна.

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

это будет сокровенное знание как поперёк системы типов реализовать те или иные костыли

Не понимаю почему пропуск нулевых значений это какое-то «сокровенное знание» и «поперек системы».

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

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

А хотелось бы, чтобы система помогала мне, а не ставила очередные вызовы.

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

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

то он неминуемо делает под капотом инстанцирование шаблонов, навроде плюсов, просто вам этого не показывает.

Нет. В Haskell compose можно хранить в списке, массиве или передать аргументом в функцию.

любой код на хаскел можно преобразовать в код на си

Преобразуйте, пожалуйста

compose f g x = f (g x)
monk ★★★★★
()
Ответ на: комментарий от alysnix

сдается что monk не до конца понимает, что делает хаскел под капотом, во что это все компилирует и как упрощает.

Вопрос был, почему в Си++ не используют compose. Я переписал программу, которая на хаскел использует compose в аналог на Си++, который также использует compose (насколько он возможен в Си++).

Если считаете, что она отличается от хаскелевского оригинала, прошу исправить.

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

С этой версией уже не в разы, но Haskell всё равно быстрее. При том, что обычно он в 2-3 раза медленнее, чем Си++.

$ time ./test 1000000000
250000000500000000

real    0m1,145s
user    0m1,136s
sys     0m0,006s

$ time ./test-cpp 1000000000
250000000500000000

real    0m1,325s
user    0m1,320s
sys     0m0,005s
monk ★★★★★
()
Ответ на: комментарий от watchcat382

На Ada скорость ничем не хуже Си.

Так я не с Си, а с Си++ сравниваю. Как только более-менее абстрактный алгоритм, Ада даёт более медленный код. Потому что в Си++ есть RTVO, UB и && (в смысле, ссылка на правое значение).

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

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

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

В СУБД не просто так в числовом поле может храниться NULL.

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

всё по классикам:

«какого цвета не существующий дракон»

печатльно что самоописываемые объекты сложны в части безопасности их окружения

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

«какого цвета не существующий дракон»

Вовочке дали задание нарисовать ангела. Он нарисовал ангела в кроссовках. Учительница спросила:

  • Ты где видел ангела в кроссовках?

  • А где Вы видели ангела без кроссовок? - ответил Вовочка.

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

Версия на С++ без compose:

$ time ./test-cpp2 1000000000
250000000500000000

real    0m1,014s
user    0m1,013s
sys     0m0,001s
monk ★★★★★
()
Ответ на: комментарий от monk
Как известно, драконов не существует.
Эта примитивная констатация может удовлетворить
лишь ум простака, но отнюдь не ученого. Банальность
бытия установлена слишком давно и не заслуживает
более ни единого словечка… Имеется три типа драконов:
нулевые, мнимые и отрицательные. Все они, как было сказано,
не существуют, однако каждый тип — на свой особый манер.
Мнимые и нулевые драконы… не существуют
значительно менее интересным способом, чем отрицательные.

Станислав Лем. Кибериада. Вероятностные драконы
qulinxao3 ★☆
()
Ответ на: комментарий от monk

Это значит что у тебя медленная реализация <ranges>, или компилятор плохо оптимизирует. В общем переключились с бенча векторов на бенч <ranges>.

Это заметно по цифрам которые ты скинул «без compose». Она примерно такая же медленная как и с compose. Это значит что реализация медленная, а с compose он вызывается как есть.

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

«какого цвета не существующий дракон»

Какого цвета был бы не существующий дракон, если бы он всё-таки существовал?

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

цвет существующего дракона это дракона существующего цвет ( если не зелубой)

каково поведение ли цвета_дракона у дракона чьё существованние возросло(«0->1») !?

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

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

Тут вызов compose на каждую итерацию, ты можешь увеличить его вложенность.

#include <iostream>

template <typename F1, typename F2> struct compose {
    F1 f1; F2 f2;
    compose(F1 f1, F2 f2) : f1{f1}, f2{f2} {}
    auto operator ()(auto x) { return f1(f2(x)); }
};

void test_pure(int argc, char **argv) {
    long r = 0;
    long end = atoi(argv[1]) + 1;
    for (long i = 1; i < end; ++i) {
        if ((i % 2) == 0) r += i;
    }
    std::cout << r << "\n";
}

void test_lambda(int argc, char **argv) {
    long r = 0;
    auto f = [](long x) { return x == 0; };
    auto g = [](long x){return x % 2;};
    long end = atoi(argv[1]) + 1;
    for (long i = 1; i < end; ++i) {
        if ((i % 2) == 0) r += i;
    }
    std::cout << r << "\n";
}

void test_compose(int argc, char **argv) {
    long r = 0;
    auto cond = compose([](long x) { return x == 0; }, [](long x){return x % 2;});
    long end = atoi(argv[1]) + 1;
    for (long i = 1; i < end; ++i) {
        if (cond(i)) r += i;
    }
    std::cout << r << "\n";
}

int main(int argc, char **argv) {
    switch(argv[2][0]) {
        case 'p':
            test_pure(argc, argv);
            break;
        case 'l':
            test_lambda(argc, argv);
            break;
        case 'c':
            test_compose(argc, argv);
            break;
    }
}
% g++-14 -std=c++23 -Ofast main.cpp; time ./a.out 2000000000 p
1000000001000000000

real	0m0,519s
user	0m0,518s
sys	0m0,001s

% g++-14 -std=c++23 -Ofast main.cpp; time ./a.out 2000000000 l
1000000001000000000

real	0m0,520s
user	0m0,519s
sys	0m0,001s

% g++-14 -std=c++23 -Ofast main.cpp; time ./a.out 2000000000 c
1000000001000000000

real	0m0,458s
user	0m0,457s
sys	0m0,001s

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

Хороший вопрос %) должно быть

void test_lambda(int argc, char **argv) {
    long r = 0;
    auto f = [](long x) { return x == 0; };
    auto g = [](long x){return x % 2;};
    long end = atoi(argv[1]) + 1;
    for (long i = 1; i < end; ++i) {
        if (f(g(i))) r += i;
    }
    std::cout << r << "\n";
}
Время примерно такое же как и у всех остальных, разница между всеми тремя неуловима...

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

Что это за меряние писюнами? Результат можно получить умножением (x * x + x) / 2. Лямбды в С++, если не проинлайнятся, то медленнее функций. Еще когда они появились в С++ и коллега начал за них топить, я посмотрел ассемблерный листинг и ужаснулся куче обёрток что создаются над лямбдами.

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

Загадочно

$ g++ -Ofast -std=c++23 test3.cpp -o test-cpp2
$ time ./test-cpp2 1000000000 p
250000000500000000

real    0m1,014s
user    0m1,013s
sys     0m0,001s
$ time ./test-cpp2 1000000000 c
250000000500000000

real    0m1,143s
user    0m1,139s
sys     0m0,005s
$ g++ --version
g++ (Debian 14.2.0-8) 14.2.0

Процессор Intel(R) Celeron(R) J4005 CPU @ 2.00GHz

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

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

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

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

Неужели? Как насчёт того, чтобы вместо читерской лямбды, которую компилятор проинлайнит - попробовать настоящую?

#include <functional>
auto f = [](long x) { return x == 0; };
auto g = [](long x) { return x % 2; };

void test_true_lambda(int argc, char **argv, std::function<long(long)> f, std::function<long(long)> g) {
    long r = 0;
    long end = atoi(argv[1]) + 1;
    for (long i = 1; i < end; ++i) {
        if (f(g(i))) r += i;
    }
    std::cout << r << "\n";
}
        case 't':
            test_true_lambda(argc, argv, f, g);
            break;
jpegqs
()
Ответ на: комментарий от jpegqs

void test_true_lambda(int argc, char **argv, std::function<long(long)> f, std::function<long(long)> g) {

Если именно так, то в 8 раз медленней.

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

void test_true_lambda(int argc, char **argv, auto f, auto g) {

то время такое же, как для test_pure.

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

Мне кажется большинство этих тестов подтверждают надежно лишь одно, что std это большой тормоз. То вектора тормозят, то range, то ламерски лямбды ака std::function...

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

Преобразуйте, пожалуйста «compose f g x = f (g x)»

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

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

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

Попробовал си, и лямбды накостыленные через расширения, еще хуже чем цпп! С их оптимизацией у gcc туго, а с помощью clang не удалось собрать. Так что проблемы с реализацией прямого compose из haskell есть проблемы по производительности.

#include <stdio.h>
#include <stdlib.h>

#define LAMBDA(T, BODY) ({ inline T _f BODY _f; })
#define COMPOSE(T, F1, F2) LAMBDA(T, (T x) { return F1(F2(x)); })

int main(int argc, char **argv) {
    long r = 0, end = atol(argv[1]) + 1;
    __auto_type f = LAMBDA(long, (long x) { return x == 0; });
    __auto_type g = LAMBDA(long, (long x) { return x % 2; });
    __auto_type cond = COMPOSE(long, f, g);
    for (long i = 1; i < end; ++i) if (cond(i)) r += i;
    printf("%ld\n", r);
    return 0;
}
C = 0m1,154s
Haskell = 0m0,101s 
MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от MOPKOBKA

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

Вы используете nested functions, которые не стандарт, а GCC расширение. У Clang есть подобное, но называется blocks и имеет другой синтаксис.

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

Надо godbolt смотреть весь код. Замена типов ничего особо не дает, ну эта реализация лямбд далеко не самая эффективная вообще.

На блоках дает 0m0,791s, что в 7 раз медленнее хескела.

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

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

Нужна функция, принимающая аргументами две функции f и g и возвращающая функцию от одного аргумента x, которая возвращает f(g(x)).

В терминах Си должно работать такое:

typedef int (*func)(int x);

void call(func f)

int f(int x) { ... }
int g(int x) { ... }
func compose(func f, func g) { ... }

int main()
{
   call(f);
   call(g);
   call(compose(f, g));
   call(compose(g,compose(f, g)));
}

это можно сделать даже на си

Вот и напишите, как это можно.

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

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

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

попробуй заменить в сишном коде композ на функцию с прямым вызовом функций f и g. тогда си их заинлайнит и возможно свернет в один if оператор.

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

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

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

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

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

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

Ну допустим «принимать функцию» еще куда ни шло. Функция сортировки вон тоже функцию принимает. Хотя на самом деле указатель на функцию. Но «возвращать функцию»? Что это и самое главное зачем?

Про парадокс Блаба слышали? Вот вы сейчас в нём находитесь.

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

func compose(func f, func g) { … }

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

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

Не понимаю почему пропуск нулевых значений это какое-то «сокровенное знание» и «поперек системы».

Потому что у вас у одного объекта man1.penis_size это число типа int, и у другого объекта man2.pensi_size это число типа int. Но в одном случае число — это число и с ним можно делать всё, что делают с числами, а в другом — специальное значение, маркер особой ситуации, которую нужно обрабатывать отдельно. Хотя с точки зрения системы типов — всё это обычные числа.

Так какого именно поведения вы хотите?

  1. Сущности предметной области должны быть однозначно отображаемы системой типов.
  2. Если уж мы решили упарываться по типам, пусть компилятор за меня проверяет, что я передаю правильные значения.
ugoday ★★★★★
()
Ответ на: комментарий от MOPKOBKA

У хаскеля получается такой код:

ecx = i, eax = end, ebx = r

1:	cmp	rcx, rax
	je	end
	inc	rcx
        jmp	3f

2:	add	rbx, rcx
        inc	rcx
3:	test	cl, 1
        jne	1b
        cmp	rcx, rax
        jne	2b
end:

GCC 13 и выше на -O3 умудряется разанроллить на векторах. При -mno-sse этого делать не будет.

https://godbolt.org/z/sovhcdnPn

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

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

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

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

короче хачкел когда делает композицию (f g) просто инлайнит одно тело функции в другое, потом оптимизирует код и получает результат. и никакой магии.

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

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

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
  long r = atol(argv[1]) >> 1;
  printf("%ld\n", r < 0 ? 0 : r * r + r);
}
$ cc test.c -Os && time ./a.out 1000000000
250000000500000000

real	0m0.000s
user	0m0.000s
sys	0m0.000s
jpegqs
()
Ответ на: комментарий от alysnix

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

Да. Если упаковать compose в список, а потом применять оттуда, то гораздо медленнее.

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

В том-то и дело, что в Хаскеле это рядовая функция. Её можно хранить в переменной или элементом списка.

С другой стороны, вызов функции в Хаскеле не сводится к ассемблерному вызову CALL, там всё чуть сложнее.

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

— На вопрос: «Как живешь?» — завыл матерно, напился, набил рожу вопрошавшему, долго бился головой об стенку, в общем, ушел от ответа.

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

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

Вот с этим всё хорошо.

$ cat test2.hs
module Main where

import System.Environment

compose f g x = f (g x)

main = do
  [x] <- getArgs
  let n = read x :: Int
  let f = (== 0)
  let g = (`mod` 2)
  let cond = compose f g
  putStrLn . show $ (compose sum (filter cond)) [1..n]

Скорость та же самая. Хотя compose не библиотечный и все функции-аргументы в переменных.

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

Именно так. С++ умеет инлайнить вызовы методов, Haskell и Racket умеют инлайнить функциональные цепочки.

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

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

Если от переменных с известным типом, то замедляться не должен, типы же известны будут. Я уже над этим раздумывал.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от jpegqs
#!/bin/bash
echo "250000000500000000"

Ага %) Мы тут проверяем как хорошо С++ позволяет записывать алгоритмы определенным образом. Задача ненастоящая.

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

А сломать оптимизатор можно так:

module Main where

import System.Environment

compose f g x = f (g x)
t = [compose, compose]

main = do
  [x1, x2] <- getArgs
  let n = read x1 :: Int
  let nc = read x2 :: Int
  let comp = t !! nc
  let f = (== 0)
  let g = (`mod` 2)
  let cond = comp f g
  putStrLn . show $ (comp sum (filter cond)) [1..n]
$ time ./test2 1000000000
250000000500000000

real    0m1,145s
user    0m1,134s
sys     0m0,010s
$ time ./test3 1000000000 0
250000000500000000

real    0m51,556s
user    0m51,652s
sys     0m0,130s

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

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

Конечно, конечно. Хочешь банан? %)

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

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

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

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

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

Конечно, конечно.

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

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

давно «с детсва» не играл в шашки

ща пришлось

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

решает шашки

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

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

самомодифицирующийся код самое лучшее что случилось

Во всех рекомендациях по надежному и безопасному программированию использование самомодифицирующегося кода настроятельно не рекомендуется.

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

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

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

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

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

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

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

???

Композиция = получение функции из нескольких функций. Рекурсия = вызов (возможно косвенный) функцией себя с другими параметрами.

Какая между ними связь?

а пайп это просто последовательный вызов функций внешним агентом

Именно. Цитирую ваше сообщение: «сама идея применения цепочки вызовов функций к результатам друг друга».

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

Композиция = получение функции из нескольких функций это и есть рекурсия. потому что в общем случае это можно сделать только вложенными вызовами функции. запись a(b(c(d(x)))) - прям об этом вопиет.

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

то бишь из

a(b(c(d(x)))) 

делать

{
  auto d_ = d(x);
  auto c_ = c(d_);
  auto b_ = b(c_);
  return a(b_);
}

тут функции не вызывают друг друга. но тогда, когда пишете «аналог» композиции на С++ - так и пишите. в виде итерации.

не знаю как там у вас в функциональных языках, но очевидно, что «композировать» можно и рекурсивно, навроде a(b(c(b(a(x)))). такая конструкция будет вычислима, так же как и обычная рекурсия.

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

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

Сделай по-уму scanf/printf.

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

Раскрой мысль, какая ошибка будет в printf?

printf("Good bye %s\n");

Какая ошибка будет? Как сделать «по уму» статическую проверку без хаков компилятора?

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 2)
Ответ на: комментарий от no-such-file

Ошибка будет:

error: format ‘%s’ expects a matching ‘char *’ argument
Хотя printf это как раз отсутствие типизации, ты же наверное знаешь как он работает. А для С++ есть библиотеки с проверками.

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

a(b(c(d(x))))

Не надо так писать если это не олимпиадная задача или «чистая наука» какая-нибудь(но там уже под вопросом).

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

Сделай по-уму scanf/printf.

При выводе - отдельными функциями преобразуем числа в строки,потом складываем строки и выводим куда надо. Формат при преобразовании каждого числа(отдельном!) задаем числовыми аргументами соответствующей функции - сколько знаков всего,сколько до/после десятичной точки. «Разбор форматной строки» и «неопределенное количество аргументов неопределенного типа» - не требуется.

Ввод существенно сложнее - надо читать входные данные в строку,проверяя допустимую длину,потом тщательно заниматься их разбором примерно по типу того что делают yacc+lex - это позволит выявлять некорректность данных. Если нашлись корректные данные,например числа - преобразуем и присваиваем. Да, писать придется больше чем воткнуть один scanf,зато надежность намного выше.

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

какая ошибка будет в printf?

Неприятность printf в том,что количество и типы его аргументов определяются не описанием самого printf,а содержимым его форматной строки,которая сама один из аргументов. Поэтому нормальная проверка типов при компиляции невозможна. Функции,принимающие на входе «неизвестно сколько неизвестно чего» - это однозначно плохо.

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

Надо писать (comp a b c d).

Для тех компиляторов которые могут это развернуть в последовательный вызов функций - можно и так. Я имел в виду что не надо «так» писать на обычном Си.

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

Ошибка будет

Это компиляторный хак. Допустим я хочу реализовать «по уму» format из ЛИСПа про который компилятор крестов ничего не знает. Мои действия?

А для С++ есть библиотеки с проверками

Показывай.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от watchcat382

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

Многовато приседаний. Кроме того, числа в строки это боксинг на коленке. Т.е. вместо int ты получаешь Integer, который Object и умеет себя печатать. Неоптимально, как и любой боксинг.

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

Хватит бредить, ты сам про printf написал, я тебе ответил что там типов нету, два раза, тебе не хватает двух раз что бы понять? Тема printf со статикой вообще очень слабо связана, однозначно его подход из С это не «по уму».

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

Многовато приседаний.

Да не особо.

Кроме того, числа в строки это боксинг на коленке. Т.е. вместо int ты получаешь Integer, который Object и умеет себя печатать.

Ну вот абсолютно не имел в виду какие-то там объекты! Просто функцию,которая принимает на вход само число, две цифры которые указывают сколько цифр печатать всего и сколько из них после десятичной точки,ну и строку куда результат положить. В микроконтроллерном софте так и делают. Потому что тащить в прошивку громоздкий универсальный printf и форматные строки к нему - слишком расточительно. (а десятичная точка нужна потому что считать могут как 1500 милливольт,а выводить как 1.500 вольт) Вот микроконтроллерный народ пишет про преобразование чисел в строку,да еще и с указанием размеров и тестами скорости: http://we.easyelectronics.ru/Soft/preobrazuem-v-stroku-chast-1-celye-chisla.html

А еще форматные строки для printf оказываются зависимыми от разрядности системы и если нужна переносимость то требуют вставления макросов типа

printf("%" PRIu32 "\n", n);

Об этой особенности printf многие не знают вообще,в результате код,написанный для 64-битного линукса печатает мусор на 32-битном,ну и наоборот. В любительских проектах этот глюк встречается очень часто.

watchcat382
()
Ограничение на отправку комментариев: