Здравствуйте, alex_public, Вы писали:
K>>Нет, "использование кода" — это использование обобщенного кода для написания другого обобщенного кода. _>Это уже использование кода человеком, а не компилятором.
И что? У вас получается замкнутый круг — ненужность проверки кода компилятором вы обосновываете тем, что компилятор код не проверяет. Хотя должен проверять и в большинстве языков проверяет.
_>Почему ограничение? )
Потому, что ограничивает написание обобщенного кода, лишая программиста легковесной верификации написанного им кода, которую обычно компилятор и обеспечивает.
_>Только не надо тогда называть эту дополнительную возможность типизацией и как следствие считать её обязательной.
Не нужно из конкретного дизайнерского просчета авторов C++ выводить какие-то космические правила.
Эта возможность и называется типизацией, и "дополнительной" в типизированном языке не является.
_>Если мы говорим про C++, то там обобщённый код полностью проверяется, но только на момент использования.
Что означает "не проверяется", если воспользоваться общепонятным смыслом слова "используется", а не специальным узким значением только для того и придуманным, чтоб выставить баг фичей.
_>На мой взгляд этого более чем достаточно для уверенности в корректности созданного ПО.
Никогда не было недостатка программистов, которые считают, что проверка типов не нужна.
_>Да, для кода используемого для генерации исполняемого кода. А не для кода, просто лежащего где-то на диске.
Имеет значение как раз то, что вы называете "использование программистом" и соответствующие удобства для программиста, предоставляемые компилятором.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Указатель не исключает иерархичность.
Указатель как абстракция — исключает. Для того, чтоб иерархичность учитывать, такую абстракцию нужно либо "продырявить", чтоб учитывать то, от чего она нас абстрагирует или расширить.
EP>Я про quick sort Тони Хоара, а не про ту пародию которую с гордостью показывают хаскелисты.
Ну пошло-поехало. Что за хаскелисты это с гордостью показывают? (Это не какая-то "пародия на quick sort" кстати, а просто tree sort).
EP>Quick sort это как раз пример сache-oblivious алгоритма.
С каких пор? сache-oblivious сортировка это какие-нибудь разновидности merge-sort вроде funnel sort, например.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>То есть без ленивости трудно делать библиотеки хорошо взаимодействующие друг с другом?
Да, именно так. Это основное обоснование для поддержки ленивости.
Это легковесный способ организовать передачу от компонента B информации в компонент A о том, что именно от компонента A требуется. Т.е. компонент A не делает все что может, а только то, что требуется компоненту B про который A вообще говоря ничего не знает.
EP>Обычно синхронизация для мутабельных данных реально требуется только по периметру модуля, а не по всей площади.
Вообще не понимаю ничего. Какие-то площади и периметры модулей.
EP>Если же вы говорите что ленивость это пища для ФП — то видимо должна использоваться повсеместно, так?
Должна использоваться там, где она нужна. Но для этого придется платить в любом случае.
EP>И соответственно меж-поточная синхронизация разбрасывается по коду только ради самой дорогой абстракции, а не для решения прикладной задачи. Ничего хорошего в этом нет
Это типичный подход для высокоуровневого языка. К примеру, полноценные лямбды требуют нормальный ГЦ, а значит и write barrier при модификации ссылок. Полноценный параметрический полиморфизм и параметризуемые модули требуют боксинг всего (либо рантайм кодогенерацию), за которые тоже приходится платить во многих местах.
EP>"Ручное слияние" это по сути дубликация структуры кода, так? Хотелось бы увидеть пример.
Чем плох пример, с упоминания которого вами же вся эта линия разговора и пошла? Вы уже придумали "аналогичное решение", которое сопоставимо с ленивостью по удобству? Так не стесняйтесь — предъявляйте.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
EP>>Я про quick sort Тони Хоара, а не про ту пародию которую с гордостью показывают хаскелисты. K>Ну пошло-поехало. Что за хаскелисты это с гордостью показывают?
K>(Это не какая-то "пародия на quick sort" кстати, а просто tree sort).
Это никакой не Tree Sort, это именно пародия на quick sort.
EP>>Quick sort это как раз пример сache-oblivious алгоритма. K>С каких пор? сache-oblivious сортировка это какие-нибудь разновидности merge-sort вроде funnel sort, например.
Quick Sort делит массив на две части (вырезая середину), и продолжает рекурсивно в каждой из частей. Начиная с определённой глубины текущий Range полностью поместится в L3, ещё глубже — L2, потом в L1 и так далее. http://en.wikipedia.org/wiki/Cache-oblivious_algorithm
Most cache-oblivious algorithms rely on a divide-and-conquer approach. They reduce the problem, so that it eventually fits in cache no matter how small the cache is, and end the recursion at some small size determined by the function-call overhead and similar cache-unrelated optimizations, and then use some cache-efficient access pattern to merge the results of these small, solved problems.
А второй фазы ("merge the results") у quick sort нету.
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>В коде то, что я описал ранее — Lazy<T>, LazyList<T>, каррированные функции и named operator'ы.
Да это понятно.
EP>Код не показываю только потому, что я его не оптимизировал (нет ни времени, ни мотивации), а начинать сравнение скорости 100-строковой реализации vs optimized code мне бы не хотелось.
Так в этом и проблема. В низкоуровневом языке писать высокоуровневый код на практике невозможно. Нет ни времени, ни мотивации. Да и работать с приемлемой скоростью он все равно не будет.
EP>>>Вот только смысла так писать нет — итеративная версия будет и проще и быстрее.
Проще точно не будет. Да и с какой стати итеративная реализация бесконечного списка чисел Фибоначчи будет заметно быстрее?
EP>В том то и дело что нет. И даже нет волшебного рецепта переписывания "итеративного" кода в "подходящий"/"оптимальный".
Ну так о чем речь тогда? Вы отвергаете целый подход к написанию программ как ненужный, потому что какую-то одну программу можете переписать иначе, и получить от этого какой-то выигрыш. Это слабый аргумент. Да и неуместный потому, что (напоминаю в очередной раз) обсуждается не полезность подхода, а инструментальная поддержка подхода.
EP>Именно об этом я и говорю. Нужно знать алгоритмы, нужно знать машину, нужно знать mapping между ними — и только тогда можно получить эффективный код.
А еще можно всего этого не знать и получить код, работающий с приемлемой скоростью в 80% случаев. На что языки высокого уровня, в основном, и ориентированы.
EP>Так уж получилось, что на современные машины ФП код мэппится плохо.
И что? Значит, что отсутствие поддержки ФП засчитывается как хорошая поддержка? Нет? К чему вы опять про это вспомнили тогда?
EP>Да что там машины, многие полезные и практичные алгоритмы плохо мэппятся на чистый ФП (без всяких хаков типа STArray), на ровном месте добавляется логарифмическое penalty к complexity.
Ну конечно, сначала придумываете какой-то специально-ущербный чистый ФП, а потом с ним боретесь. Обосновать, что STArray является хаком сможете? О какой "логарифмическое penalty к complexity" речь идет вообще непонятно. Какой смысл сравнивать структуры данных с несопоставимой функциональностью? Вы без ФП сможете версионность поддерживать с меньшим penalty что ли?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[32]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Так есть ведь аналоги. Вместо создания списка, в котором косвенность на косвенности, аллокации и thunk'и — в ряде случаев достаточно обычного плоского массива.
Это на аналог не тянет. Ленивый список это, в первую очередь, не data, а control-structure. Я еще понимаю, какой-нибудь лисповый loop-комбайн или континуации рассматривать как аналоги, но плоский массив — это не смешно даже.
Напоминаю еще раз постановку вопроса:
Вот когда предоставите для сравнения control-structure для связывания комбинаторов с комбинаторами с аналогичной функциональностью (поддержка раннего завершения, циклов, автомемоизации, потокобезопасность и т.д.) тогда и сравним.
EP>Ленивые вычисления — реализуются, UFP — решена. И да, использовать эти средства везде — нет смысла. В тех местах где performance penalty допустима, и если эти средства действительно дают преимущества — то их нужно использовать.
Ну так performance penalty за вашу "поддержку" (тормозная ленивость, счетчики ссылок с утечками из-за циклических ссылок и т.д.) гораздо выше, чем в высокоуровневом языке. Т.е. performance penalty у вас получается неприемлема практически везде, использовать никто и нигде не будет (ну, кроме как для споров на форуме). Если это и понимается, когда декларируется, что поддержка есть — все понятно.
EP>Если же вся программа целиком будет состоять только из дорогих ФП элементов, то действительно лучше взять язык заточенный под это EP>Нужны где? По всему коду?
Не обязательно вся программа — достаточно заметных масштабов использования.
EP>Функции высшего порядка и first-class functions: мощная и полезная вещь.
В моем минимум списке, собственно, только этот пункт и есть, и даже тут у C++ все плохо из-за того что UFP не решено.
EP>Referential transparency: см. STL.
И где там Referential transparency? Или тут опять какой-то местечковый термин?
EP>Замыкания: удобны, особенно при захвате большого количества переменных.
Это подразумевается в пункте про первоклассные функции.
EP>И это всё бесплатно, или крайне дёшево (зависит от компилятора) — так как всё прекрасно inline'ится.
Нет, это все не бесплатно. Первоклассность функций требует ГЦ, поддержку карринга от рантайма, ленивость (опять таки с поддержкой от рантайма и компилятора) для того, чтоб можно было нормально комбинировать функции.
Если еще и поддержку рекурсии добавить, к ленивости, которая уже затребована, прибавится стек в куче, а для полиморфной рекурсии — боксинг всего.
Т.е. никаких чудес, за функции платим по полной программе, как приходится платить в ФЯ (за большую часть перечисленного).
Какое-то подобие нормальной поддержки первоклассных функций реализуется относительно дешево, чем бледнее подобие — тем дешевле — тут все достаточно интуитивно.
EP>Где-то наверху в calltree, можно использовать какие-то дорогие штуки, но не нужно разбрасывать их по всему коду без необходимости.
Это как раз подход низкоуровневых языков, который я рассматривал в сравнении с высокоуровневыми. Логика такая:
1) Дорогие штуки используем тогда, когда стоимость не имеет значение.
2) Раз стоимость значения не имеет — ничего для поддержки не делаем. Пусть работает медленно — какая разница?
3) Ставим галочку — все поддерживается, проблема решена!
4) Язык распадается на два подмножества "фортран" для написания кода, который имеет значение и "скрипт" для клеевого кода и споров на форумах.
5) На самом деле, мест где стоимость совсем не имеет значения довольно мало, такой код пишется редко, "Высокоуровневый" код либо с самого начала не пишется, либо пишется под переписывание в дальнейшем. Мотивация писать "высокоуровневый" код слабая, это напрасная трата времени — все равно же переписывать в идиоматическом для данного языка стиле придется.
6) "Высокоуровневый" код пишется только на форумах, чтоб доказывать полноценность языка. Но какая разница? Для галочки-то все есть.
Высокоуровневый язык должен поддерживать дорогие фичи настолько хорошо, чтоб ими действительно можно было пользоваться и делать настолько быстрыми, насколько это возможно. В этом и отличие.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[35]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>И откуда у вас эти контейнеры с функциями берутся, если вы их не из функций возвращаете?
Ну так это же не ФЯ с его ограничениями на иммутабельность — мы можем создавать что угодно, не только возвращая значения из функций. )
K>А причем тут уровни кода тогда? Если речь не о воплощении шаблонов проектирования с помощью каких-то инструментов метапрограммирования.
Шаблоны проектирования прекрасно реализуются и без всякого МП, так что оно собственно тут ни при чём. Так вот, возвращаясь к шаблонам проектирования... Это разве на ваш взгляд не абстракции достаточно высокого уровня?
K>Я тут писал по соседству, что высокоуровневый код — это такой код, о строительных блоках которого можно рассуждать как о математических объектах (о функциях как о функциях, например) и извлекать из этого какую-то пользу.
Интересное определение, но я не очень понял один нюанс. Правильно ли я понимаю, что мы таким определением очень сильно сужаем область даже теоретической возможности написания высокоуровневого кода?) Т.е. что этот термин (в таком определение) становится применим только к небольшой области ПО. Или же, если здесь не подразумевается подобного сужения (т.е. считаем что любую задачку можно решить высокоурвневым кодом), то хотелось бы увидеть примеры подобных математических объектов. Вот например возьмём такое общеизвестное простейшее приложение как "Блокнот". Из каких математических объектов он будет состоять, если мы его реализуем по высокоуровневому? )
K>Ну так покажите всем, как это ненормально. Слева все хорошо, справа "ужас-ужас-ужас". Но вы же упорно не хотите этого делать. И понятно почему, потому что рядом с императивным кодом на большинстве языков монадический код смотрится совсем не страшно.
Нуну)
Возьмём например такой простейший код, работающий через константные ссылки:
prepare :: Array Int Int -> Array Int Int
prepare а = а//[(1, а!1*а!1)]
test :: Array Int Int -> Int
test а = let r=prepare а
in sum $ elems r
main = print $ test $ listArray (0, length l -1) l
where l= [1, 2, 3]
Он конечно не оптимальный, но для массивов в 3 элемента без разницы. Его прямым аналогом на C++ будет что-то вроде:
auto prepare(const vector<int>& a)
{
vector<int> r=a;
r[1]=r[1]*r[1];
return r;
}
auto test(const vector<int>& a)
{
auto r=prepare(a);
return accumulate(r.cbegin(), r.cend(), 0);
}
int main(){cout<<test({1, 2, 3});}
Как видно, он является практически точной копией. Разве что копирования массива в C++ задаётся явно, а создание массива реализовано удобнее. Но это всё мелочи, а семантически код одинаков.
А теперь предположим, что нам захотелось переделать это под неконстантные ссылки. Кстати, вполне реальная задачка, если у нас массив не из 3-ёх элементов, а из 3*10^9. На C++ это станет выглядеть так:
void prepare(vector<int>& a){a[1]=a[1]*a[1];}
auto test(vector<int>&& a)
{
prepare(a);
return accumulate(a.cbegin(), a.cend(), 0);
}
int main(){cout<<test({1, 2, 3});}
Видно, что код практически не изменился по своей структуре, а стал только проще — просто стёрли лишнее.
Ну и теперь полюбуемся, как будет выглядеть что-то подобное на Хаскеле:
prepare :: STArray s Int Int -> ST s ()
prepare a = do
x <- readArray a 1
writeArray a 1 (x*x)
test :: STArray s Int Int -> ST s Int
test a = do
prepare a
l <- getElems a
return $ sum l
main = print $ runST $ do
let l=[1, 2, 3]
a <- newListArray (0, length l -1) l :: ST s (STArray s Int Int)
test a
И это ещё в лучше случае, если getElems в реальности создаёт ссылку, а не выделяет память (я просто не в курсе таких тонкостей). А если getElems выделяет память, то её использовать нельзя и придётся ещё самим писать новую версию sum, которая умеет работать с типом STArray s Int Int.
Но даже если забыть про этот момент, то в целом видно, что изначальный хаскельный код при переходе к монадному (который необходим для существования неконстантных ссылок) изменился до неузнаваемости. Причём код не просто полностью изменился, а стал заметно страшнее — смысловая часть в нём погребена под кучей монадного синтаксического мусора.
Re[36]: Есть ли вещи, которые вы прницпиально не понимаете...
K>>Я тут писал по соседству, что высокоуровневый код — это такой код, о строительных блоках которого можно рассуждать как о математических объектах (о функциях как о функциях, например) и извлекать из этого какую-то пользу. _>Интересное определение, но я не очень понял один нюанс. Правильно ли я понимаю, что мы таким определением очень сильно сужаем область даже теоретической возможности написания высокоуровневого кода?) Т.е. что этот термин (в таком определение) становится применим только к небольшой области ПО. Или же, если здесь не подразумевается подобного сужения (т.е. считаем что любую задачку можно решить высокоурвневым кодом), то хотелось бы увидеть примеры подобных математических объектов. Вот например возьмём такое общеизвестное простейшее приложение как "Блокнот". Из каких математических объектов он будет состоять, если мы его реализуем по высокоуровневому? )
Определение какое-то странное — о строительных блоках любого языка можно рассуждать как о математических объектах и извлекать из этого пользу.
Даже об инструкциях императивного языка можно рассуждать как о математических объектах. Например так, как делал Tony Hoare — Hoare Triple.
Или так как делает Александр Степанов. Например в STL — в ISO вполне математически описаны концепции с аксиомами. Или в его Elements of Programming — вводятся определения концепций, аксиомы, из которых выводятся леммы и теоремы, на основе которых строятся эффективные алгоритмы для современных машин.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
K>Я же объяснил, что это потому, что запрашиваемое вами конкретное поведение (с n-проходов) реально существующая библиотека обеспечивает при оптимизации "монадного" кода, а для остального другое поведение (хотя устранение промежуточных значений тоже происходит и такие преобразования я тоже продемонстрировал). Мы вроде начали с принципиальной возможности таких оптимизаций в реально существующем компиляторе, а теперь оказывается что пока я не напишу библиотеку с какими-то конкретными перламутровыми пуговицами это не засчитывается. Причем, когда я ее напишу, то окажется, что пуговицы опять недостаточно перламутровые и т.д.
Что-то я не понял, что вы тут хотели сказать. Что описываемую задачку можно решить без монадного кода? ) Если можно, то тогда с удовольствием посмотрю на это... Если же нельзя, то тогда в чём претензии к моим комментариям? )
K>Вообще-то это ручная пессимизация в чистом виде. Я вручную создаю лишние копирования, которые компилятор устраняет. K>Как раз для того, чтоб это (устранение их компилятором) продемонстрировать.
А что, без этих "лишних копирований" можно обойтись что ли? ) Как мы без них получим нормальные (не монадные) хаскельные функции? )
K>И в чем проблема? Почему бы первоначальному источнику не передавать результат обернутый в New?
Ну так мало ли откуда там идёт тот внешний буфер — далеко не факт, что он прямой результат new. А если делать дополнительную обёртку, то всё равно получим то самое копирование.
Кстати, в реальности (изначальная задачка то из вполне реальной области была) там это выглядит так: первичный буфер предоставляет ОС, вызывая наш код 30 раз в секунду и передавая нам при этом указатель. Так вот на C++ естественно без проблем делается такая обработка вообще без выделения памяти — и внутри обработки одного кадра (про что и был код выше) и между кадрами. А как тут у Хаскеля дела? )
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Klapaucius, Вы писали:
_>>На мой взгляд этого более чем достаточно для уверенности в корректности созданного ПО. K>Никогда не было недостатка программистов, которые считают, что проверка типов не нужна.
Утомил меня этот наш бестолковый спор о терминах. Вы пытаетесь цепляться за придуманные вами же определения и не обращаете внимания на смысл вообще.
Предлагаю простейшее разрешение вопроса. Раз вы считаете, что шаблоны C++ нетипизированные, то тогда просто приведите ровно один любой пример, в котором из-за этой нетипизированности будет создаваться некорректно работающее ПО. Ну и естественно Хаскель (как пример вроде как типизированного) для того же случая не должен позволять создать некорректное ПО.
Если покажете такой пример, то я признаю что ошибался и что в C++ шаблоны нетипизированные. Ну а если нет, то значит что вы всё время тут говорили ерунду.
P.S. Для динамических языков (того же питона например) я легко могу показать подобные примеры.
Re[39]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>В ноде очень простой и понятный апи, нормальная модульная система и функции. От джаваскрипта достается песочница. Все вместе это дает довольно простую и дешовую асинхронщину.
Ты вот всё время акцентируешь на этом внимание... В то время как в реальности действительная польза от асинхронного кода есть только на крайне узком спектре задач. Обычно что-то вроде сервера, обрабатывающего тысячи одновременных запросов. А в большинстве обычных задач, классический синхронный код является не менее эффективным (а в случае числа потоков около числа ядер процессора, скорее даже более эффективным). При этом являясь более удобным и лаконичным. Кстати, это видно даже по твоему любимому await из C# — вся его основная "крутизна" заключена в том, что он создаёт видимость синхронного кода, являясь при этом асинхронным. Т.е. уже даже из этого очевидно какой код удобнее в реальности.
Так что твой частый аргумент про "простую и дешовую асинхронщину" весьма сомнителен в большинстве случаев. Хотя если говорить именно про node.js, то на нём как раз частенько пытаются делать приложения из той узкой области, где асинхронный код может быть реально полезен... )
Re[44]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>В ноде очень простой и понятный апи, нормальная модульная система и функции. От джаваскрипта достается песочница. Все вместе это дает довольно простую и дешовую асинхронщину.
_>Ты вот всё время акцентируешь на этом внимание... В то время как в реальности действительная польза от асинхронного кода есть только на крайне узком спектре задач. Обычно что-то вроде сервера, обрабатывающего тысячи одновременных запросов.
Под это определение подойдут практически все серверные решения
>А в большинстве обычных задач, классический синхронный код является не менее эффективным (а в случае числа потоков около числа ядер процессора, скорее даже более эффективным).
Все гораздо проще — есть задачи, где больше вычислений. Есть задачи, где больше IO. Node.js нужен для второго случая. Это и ежу ясно — Джаваскрипт медленее С++ и даже шарпа с джавой. Асинхронщина в задачах где больше всего IO есть не потому что Node, а потому что IO.
_>Так что твой частый аргумент про "простую и дешовую асинхронщину" весьма сомнителен в большинстве случаев.
Я про все случаи и не говорил, это под твое определение подходят все случаи серверных решений.
Re[40]: Есть ли вещи, которые вы прницпиально не понимаете...
То есть, в кратце, тебя смущают не страхи в Хаскеле, которых ты не смог показать, а всего-то
1 если писать на XXX, как на YYY, то получается многословный код.
2 изменение состояния на функциональном языке дает многословный код
Хаскель не С++ — ужос !
Re[37]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Определение какое-то странное — о строительных блоках любого языка можно рассуждать как о математических объектах и извлекать из этого пользу.
Теоретически. Надо учитывать, что язык нужен человеку, а не компьютеру. Если учеть, что особенности человеческого внимания сильно ограничены, все резко меняется.
Отсюда ясно, что уровень языка нужно определять через количеством умозаключений, которые надо нагородить, что бы решать задачи абстрагируюясь от аппаратных и прочих особенностей.
Например, рассуждая скажем о строительных блоках в виде ассемблерных команд, до решения типичной задачи как правило мало кто доходит а для сложных задач решения вообще никогда не бывает.
Скажем, что бы написать быструю сортировку на ассемблере, надо очень, очень долго думать.
На С++ думать надо меньше, но все равно очень много относителя Хаскеля.
А вот Хаскель будет лидер из трех этих примеров, без шансов. (Тут кто нибудь из плюсовиков почти наверняка не согласится)
Т.е. высокоуровневый, это такой который легко позволяет оперировать абстракциями, а не конкретными особенностями аппаратной платформы. Очевидно, это никак не связано с быстродействием.
Если привязаться к железу и поменять условие, например управлять микроконтром обращаясь к нему через его порты, то, внезапно, всех порвёт ассемблер, а на других языках такая задача не решается, потому что в порты они писать не умеют, им понадобится помощь собтсвенно этого самого ассемблера.
А если смапить порты на память, то, внезапно, всех порвёт С++, который умеет легко менять состояние.
Очевидно, из этого не следует, что Ассемблер или С++ иногда становятся высокоуровневыми языками. Это значит, что они легко используются в конкретных случаях, а ассемблер будет самым быстродейственным, т.к. быстродействие там где ближе всего к железу.
Теоретически, компиляторы С++ создают код, который невозможно написать таким же быстрым но руками на ассемблере. Парадокс в том, что любую такую программу можно ускорить парочкой локальных финтов на ассемблере.
Это следует из того, что
1. компилятр пишут люди
2. компилятор всего лишь слепок текущих представлений, а не кладезь абсолютной истины
Пример — можно легко устранить лишние вызовы функций заменив их на переходы. Или инлайнить виртуальные вызовы, про которые ни у компилятора ни у линкера нет полноты сведений для принятия решения.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Предлагаю простейшее разрешение вопроса. Раз вы считаете, что шаблоны C++ нетипизированные, то тогда просто приведите ровно один любой пример, в котором из-за этой нетипизированности будет создаваться некорректно работающее ПО.
Это некорректное сравнение. Динамика означает, что всякие проверки переносятся на момент вызова или не выполняются вообще. Корректно ли будет ПО дело десятое. Где у нас вызов шаблонов С++ ? Правильно, при конкретном использовании.
Скажем, в джаваскрипте можно вообще написать мусор, но софт будет абсолютно корректно работать. Из этого, представь, не следует, что джаваскрипт вдруг стал статически типизированым.
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
EP>>Определение какое-то странное — о строительных блоках любого языка можно рассуждать как о математических объектах и извлекать из этого пользу. I>Теоретически.
Я привёл конкретные примеры.
I>Надо учитывать, что язык нужен человеку, а не компьютеру. Если учеть, что особенности человеческого внимания сильно ограничены, все резко меняется.
Вот выше был пример Fibonacci numbers через fix — ты сможешь объяснить его ребёнку? Зато обычная итеративная версия и проще и быстрее.
I>Отсюда ясно, что уровень языка нужно определять через количеством умозаключений, которые надо нагородить, что бы решать задачи абстрагируюясь от аппаратных и прочих особенностей. I>Например, рассуждая скажем о строительных блоках в виде ассемблерных команд, до решения типичной задачи как правило мало кто доходит а для сложных задач решения вообще никогда не бывает.
Неверно. Из ассемблерных команд делают блоки побольше, которые собирают ещё более в крупные блоки и т.п.
И это так везде, даже в ФП — из маленьких блоков собирают побольше и т.п.
And then in the beginning of 1976 I had my first revelation: the ideas of the Structured Programming had nothing to do with the language. One could write beautiful code even in assembly. And if I could, I must. (After all I reached the top of the technical ladder and had to either aspire to something unattainable or go into management.) I decided that I will use my new insight while doing my next project: implementing an assembler. Specifically I decided to use the following principles:
...
The result of my experiment was quite astonishing. The code did not contain serious bugs. There were typos: I had to change AND to OR, etc. But I did not need patches. And over 95% of the code was in general functions! I felt quite proud. There remained a problem that I could not yet precisely figure out what it meant that a function was general. As a matter of fact, it is possible to summarize my research over the next 30 years as an attempt to clarify this very point.
I>Скажем, что бы написать быструю сортировку на ассемблере, надо очень, очень долго думать. I>На С++ думать надо меньше, но все равно очень много относителя Хаскеля. I>А вот Хаскель будет лидер из трех этих примеров, без шансов. (Тут кто нибудь из плюсовиков почти наверняка не согласится)
Конечно не согласится — то убожество которое гордо демонстрируют Хаскелисты это не Quick Sort.
Адекватные Хаскилсты даже явно говорят, что это не Quick Sort Тони Хоара, например Erik Meijer (28:25).
Если же пытаться сделать нормальный Quick Sort на Haskell — то получается крайне убого и на порядок сложнее (alex_public выше приводил ссылку, и то — там до нормального quick sort с bidirectional partition ещё далеко).
Зато если делать на C++ как в Haskell (то есть медленно и не Quick Sort) — то код получится очень похожим, только смысла в этом нет.
I>Т.е. высокоуровневый, это такой который легко позволяет оперировать абстракциями, а не конкретными особенностями аппаратной платформы.
Конкретные модели абстракций на чём будешь реализовывать?
I>Очевидно, из этого не следует, что Ассемблер или С++ иногда становятся высокоуровневыми языками.
Очевидно, что из этого не следует и обратное. То есть не следует ни то, ни другое — к чему вообще тогда пример?
I>Пример — можно легко устранить лишние вызовы функций заменив их на переходы. Или инлайнить виртуальные вызовы, про которые ни у компилятора ни у линкера нет полноты сведений для принятия решения.
Если во время написания кода ты знаешь что есть возможность инлайнинга, то ты сможешь заинлайнить даже на C# — для этого ассемблер не нужен.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>То есть, в кратце, тебя смущают не страхи в Хаскеле, которых ты не смог показать, а всего-то I>1 если писать на XXX, как на YYY, то получается многословный код.
При такой логике и брейнфак легко становится идеальным языком... )
I>2 изменение состояния на функциональном языке дает многословный код
А вот и нет. Если мы глянем на тот же Ocaml и многие другие ФЯ, то там подобной ереси нет.
I>Хаскель не С++ — ужос !
Вообще то там было скорее показано, что "монадный хаскель" — это не хаскель. Хотя в сравнение "монадный хаскель" vs. C++ расклад оказался даже ещё хуже.
А вот против классического красивого Хаскеля никто ничего и не говорил. Ну за исключением того, что подобных Хаскель можно увидеть только в академических примерах, а во всех реальных приложениях почти весь код занимают гигантские монады.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
I>>Под это определение подойдут практически все серверные решения
_>Совсем нет. И тот факт, что Apache занимает большую часть рынка, как раз это и подтверждает.
Все. Любой сервер предполагает тысячи одновременно приходящих запросов. Ну разве кроме самопального, для hello world