Здравствуйте, reductor, Вы писали:
V>>Но если в языке нет break, continue, return, то без goto порой получается тот самый синтаксический оверхед и лишняя "искусственная" запутанность кода.
R>А по-моему все наоборот становится понятнее R>Вот в ML и Haskell нет ни break ни return ни continue ни goto — ну по крайней мере в прямом смысле
Опять ты про функциональный стиль? Нафига вообще козе баян? А замечание про отсекающие условия я уже делал.
R>И никакого синтаксического оверхеда
Ясен пень. Вся императивщина скрыта в недрах компилятора/интерпретатора. Но согласись, пока что еще слишком много императивных задач, хотя бы из соображений эффективности. Вон даже длину списка подсчитать в Лисп или Пролог нетривиально (с т.з. ресурсов), подозреваю, что такая же хрень в Haskell.
Вставлю свои 5 копеек. В С++ допустима перезагрузка оператора new. Мне неоднократно приходилось писат свои менеджеры памяти на С++. Т.е. все предельно разумно — на каждый конкретный случай, требующий эффективности можно написать идеально подходящий для данного случая менеджер памяти.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, reductor, Вы писали:
V>>>Но если в языке нет break, continue, return, то без goto порой получается тот самый синтаксический оверхед и лишняя "искусственная" запутанность кода.
R>>А по-моему все наоборот становится понятнее R>>Вот в ML и Haskell нет ни break ни return ни continue ни goto — ну по крайней мере в прямом смысле
V>Опять ты про функциональный стиль? Нафига вообще козе баян? А замечание про отсекающие условия я уже делал.
Я когда-нибудь того человека, который придумал термин "функциональное программирование" отловлю и скормлю крокодилам.
Ненавижу, когда начинают разделять тут — одно дело, когда модель языка — чистая лямбда, как в случае с хаскелем, а другое, когда некоторые конструкции просто удобны везде.
просто удобно, когда if и switch возвращают значения, дико удобен pattern matching, очень полезно, когда раскручивается хвостовая рекурсия и тп.
и самое главное — все эти goto теряют смысл, когда есть замыкания и ты можешь просто передать куда-то функцию для дальнейшей обработки.
Можно подумать, Nemerle или C# 3.0 — это "функциональные" языки. Или там ruby...
"Функциональных" языка толком два — это Haskell и Clean, в остальных случаях — это просто языки без комплексов
V>Ясен пень. Вся императивщина скрыта в недрах компилятора/интерпретатора.
Ну скрыта или не скрыта — это как считать. Си вот тоже некоторым образом "функциональный" язык. все функция, всегда есть возвращаемый тип, функции передавать можно. ну и тп. большая абстракция.
v>Но согласись, пока что еще слишком много императивных задач, хотя бы из соображений эффективности. Вон даже длину списка подсчитать в Лисп или Пролог нетривиально (с т.з. ресурсов), подозреваю, что такая же хрень в Haskell.
Длину связного списка посчитать везде стоит одинаково.
а описывается задача очень просто:
length [] = 0
length (x:xs) = 1 + length xs
Попроще, чем в си.
другое дело, что длину знать их — это очень редко, когда нужно. по индексу их никто не итерирует и т.п
мощная штука, жаль, пока что без аппаратной поддержки медленнее, чем массивы (те в кеш разом зафигачить проще)
резюме:
Императивных задач же конечно много, но это не повод лишать себя удобства в виде матчинга, замыканий и хвостовой рекурсии.
Причина существования окамла, между прочим (который не менее императивный, чем функциональный)
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, reductor, Вы писали:
V>Вставлю свои 5 копеек. В С++ допустима перезагрузка оператора new. Мне неоднократно приходилось писат свои менеджеры памяти на С++. Т.е. все предельно разумно — на каждый конкретный случай, требующий эффективности можно написать идеально подходящий для данного случая ...
...менеджер памяти. и операционную систему
Написать свой аллокатор где угодно не проблема, просто за пределами С++ это требуется несколько реже
Опять же — учитывая сколько в современном С++ своих объектов, а сколько всякого boost'a и прочего, сия возможность как-то не сильно обнадеживает.
Здравствуйте, reductor, Вы писали:
R>Я когда-нибудь того человека, который придумал термин "функциональное программирование" отловлю и скормлю крокодилам.
Тогда остановимся на термине "функциональный стиль". Мы же должны оперировать какими-нибудь краткими терминами.
R>и самое главное — все эти goto теряют смысл, когда есть замыкания и ты можешь просто передать куда-то функцию для дальнейшей обработки.
Синтаксически это присутствует уже в C# 2.0, никто не спорит. В С++ та же идиома обыгрывается функторами и там тоже goto не нужен. Это не те случаи и мы отклонились.
R>Можно подумать, Nemerle или C# 3.0 — это "функциональные" языки. Или там ruby... R>"Функциональных" языка толком два — это Haskell и Clean, в остальных случаях — это просто языки без комплексов
V>>Ясен пень. Вся императивщина скрыта в недрах компилятора/интерпретатора.
R>Ну скрыта или не скрыта — это как считать. Си вот тоже некоторым образом "функциональный" язык. все функция, всегда есть возвращаемый тип, функции передавать можно. ну и тп. большая абстракция.
В С++, повторю, есть еще и функторы. Весь STL писан в расчете на них (ф-ии и функторы).
v>>Но согласись, пока что еще слишком много императивных задач, хотя бы из соображений эффективности. Вон даже длину списка подсчитать в Лисп или Пролог нетривиально (с т.з. ресурсов), подозреваю, что такая же хрень в Haskell. R>Длину связного списка посчитать везде стоит одинаково.
Самое время задуматься, почему связанные списки редко где используются в императвных участках кода.К тому же — побочный эффект насчет попаданий в кеш тоже играет свою роль. Далее, "сплошные" массивы более компактны, value-типы в .Net будет гораздо эффективней хранить в массивах и т.д.
В STL есть итераторы, причем работа с ними в основных алгоритмах не зависит от способа организации списка. Разница м/у итераторами — суть длина списка. Неплохая абстракция.
R>а описывается задача очень просто: R>
R>другое дело, что длину знать их — это очень редко, когда нужно. по индексу их никто не итерирует и т.п
Если у меня свой собственный распределитель памяти, или я вызываю ф-ии АПИ ОС, или я пишу свой загрузчик и т.д.?
R>мощная штука, жаль, пока что без аппаратной поддержки медленнее, чем массивы
Есть инциденты аппаратной поддержки кеширования списочных структур?
R>резюме: R>Императивных задач же конечно много, но это не повод лишать себя удобства в виде матчинга, замыканий и хвостовой рекурсии.
STL/boost
с замыканиями сложнее, их приходтся эмулировать руками, в виде... объектов.
R>Причина существования окамла, между прочим (который не менее императивный, чем функциональный)
а что серьезного уже написано на окамле? (не стеб, если есть навскидку инфа — поделись)
Пролог — тоже весьма мощная штука, но блин чего-то не пошел в массы, даже удивительно... Даже с ОО- и императивными расширениями.
E>А чего здесь вообще должно делаться? Матрица на матрицу перемножаться?
E>Ну и сколько Scheme-программисту нужно будет изучать C++ и boost::mpl для того, чтобы сделать то же самое через C++ные expression templates?
blitz++, готовая, легко расширяемая либа для матричных и прочих вычислений. Очень элегентна и проста в использовании.
Здравствуйте, vdimas, Вы писали:
V>а что серьезного уже написано на окамле? (не стеб, если есть навскидку инфа — поделись)
Unison File Synchronizer, насколько я знаю. В отличии от rsync он был оптимизирован для синхронизации файлов, которые дописываются в конец (логи, к примеру).
Только rsync есть на гораздо большем количестве платформ, чем unison.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
V>В STL есть итераторы, причем работа с ними в основных алгоритмах не зависит от способа организации списка. Разница м/у итераторами — суть длина списка. Неплохая абстракция.
Мимо. operator- поддерживается только random access итераторами. Для произвольных итераторов есть std::distance.
R>>другое дело, что длину знать их — это очень редко, когда нужно. по индексу их никто не итерирует и т.п
А еще все стандратные контейнеры свой размер кэшируют. И сделать то же самое на любом ФЯ можно (только не нужно).
E>Нужно только понимать, что для каждой задачи нужен свой язык. Где-то функциональные языки рулят неимоверно. Когда таких задач станет большинство, тогда и эти языки будут мейнстримом. Хотя, скорее, в существующие императивные языки будут добавлены лучшие качества функциональных.
Именно так и будет скорее всего. Идиоматически "чистые" языки весьма узконаправленные by design, отсюда их низкая популярность. Не знаю как это будет выражаться синтаксически и какова будет сложность компиляторов, но 100%-но будут совмещать разные идиомы в программном коде.
Здравствуйте, Глеб Алексеев, Вы писали:
V>>В STL есть итераторы, причем работа с ними в основных алгоритмах не зависит от способа организации списка. Разница м/у итераторами — суть длина списка. Неплохая абстракция. ГА>Мимо. operator- поддерживается только random access итераторами. Для произвольных итераторов есть std::distance.
речь шла о фичах, а не о внешнем их выражении.
R>>>другое дело, что длину знать их — это очень редко, когда нужно. по индексу их никто не итерирует и т.п ГА>А еще все стандратные контейнеры свой размер кэшируют. И сделать то же самое на любом ФЯ можно (только не нужно).
Нет, не можно. Голова списка (cons) — это может быть середина другого списка.
Здравствуйте, reductor, Вы писали:
R>Здравствуйте, vdimas, Вы писали:
V>>Здравствуйте, reductor, Вы писали:
V>>Вставлю свои 5 копеек. В С++ допустима перезагрузка оператора new. Мне неоднократно приходилось писат свои менеджеры памяти на С++. Т.е. все предельно разумно — на каждый конкретный случай, требующий эффективности можно написать идеально подходящий для данного случая ...
R>...менеджер памяти. и операционную систему
Согласись, что написание своего менеджера памяти — это тот самый "особый случай", который не возникает сам по себе.
R>Написать свой аллокатор где угодно не проблема, просто за пределами С++ это требуется несколько реже
В Лисп — проблема, в Пролог — проблема. Не знаю как в других новомодных.
R>Опять же — учитывая сколько в современном С++ своих объектов, а сколько всякого boost'a и прочего, сия возможность как-то не сильно обнадеживает.
В любой программе содержится счетное кол-во типов. Гораздо более счетно кол-во типов действительно требующих своего аллокатора. Обычно в командах С++ давно есть несколько разновидностей аллокаторов, которые просто прикручиваются к требуемым типам.
V>Тогда остановимся на термине "функциональный стиль". Мы же должны оперировать какими-нибудь краткими терминами.
зачем? :)
R>>и самое главное — все эти goto теряют смысл, когда есть замыкания и ты можешь просто передать куда-то функцию для дальнейшей обработки.
V>Синтаксически это присутствует уже в C# 2.0, никто не спорит. В С++ та же идиома обыгрывается функторами и там тоже goto не нужен. Это не те случаи и мы отклонились.
Почему не те, по-моему, очень даже.
R>>Можно подумать, Nemerle или C# 3.0 — это "функциональные" языки. Или там ruby... R>>"Функциональных" языка толком два — это Haskell и Clean, в остальных случаях — это просто языки без комплексов ;)
V>>>Ясен пень. Вся императивщина скрыта в недрах компилятора/интерпретатора.
R>>Ну скрыта или не скрыта — это как считать. Си вот тоже некоторым образом "функциональный" язык. все функция, всегда есть возвращаемый тип, функции передавать можно. ну и тп. большая абстракция.
V>В С++, повторю, есть еще и функторы. Весь STL писан в расчете на них (ф-ии и функторы).
Я видел :)
Я опять к тому, что делить функциональное и императивное программирование почти невозможно в том смысле, что пусть тот, кто сможет провести грань, первым бросит в меня камень.
v>>>Но согласись, пока что еще слишком много императивных задач, хотя бы из соображений эффективности. Вон даже длину списка подсчитать в Лисп или Пролог нетривиально (с т.з. ресурсов), подозреваю, что такая же хрень в Haskell. R>>Длину связного списка посчитать везде стоит одинаково.
V>Самое время задуматься, почему связанные списки редко где используются в императвных участках кода.К тому же — побочный эффект насчет попаданий в кеш тоже играет свою роль. Далее, "сплошные" массивы более компактны, value-типы в .Net будет гораздо эффективней хранить в массивах и т.д.
Потому что их не так удобно там использовать.
Если не обращать вниания на эффективность, то списки вообще вещь гораздо удобнее, чем массивы для 90% задач.
Не просто же так все эти итераторы и прочее появились в "императивных" языках — своего рода эмуляция списков.
V>В STL есть итераторы, причем работа с ними в основных алгоритмах не зависит от способа организации списка. Разница м/у итераторами — суть длина списка. Неплохая абстракция.
Да не проблема. Только list interface в функциональных языках — это не от их бедности и скупости, он сам по себе очень экспрессивное средство.
Это самый низкий уровень работы со списками. Никто своей функции length конечно не пишет, она уже есть :)
А определить класс со стандартным интерфейсом ничего не стоит, но оно не особо нужно — в большинстве случаев все равно списки. А когда массивы, это уже слишком другая семантика, чтобы вводить такую абстракцию.
R>>Попроще, чем в си.
V>
V>it2-it1
V>
V>С++ V>:)
ну тогда
length xs
ну или
bounds ar
для массивов
R>>другое дело, что длину знать их — это очень редко, когда нужно. по индексу их никто не итерирует и т.п
V>Если у меня свой собственный распределитель памяти, или я вызываю ф-ии АПИ ОС, или я пишу свой загрузчик и т.д.?
Это к чему?
R>>мощная штука, жаль, пока что без аппаратной поддержки медленнее, чем массивы
V>Есть инциденты аппаратной поддержки кеширования списочных структур?
Ну, смотря что считать... http://citeseer.ist.psu.edu/187280.html
Вообще это большая тема с затрагиванием фон ноймана против гарварда и тп
ну ее...
подальше :)
R>>резюме: R>>Императивных задач же конечно много, но это не повод лишать себя удобства в виде матчинга, замыканий и хвостовой рекурсии.
R>>Причина существования окамла, между прочим (который не менее императивный, чем функциональный) :)
V>а что серьезного уже написано на окамле? (не стеб, если есть навскидку инфа — поделись)
А так, кое в каких очень немаленьких компаниях используется в очень немаленьких внутренних системах.
Но те же молчат и другим велят :)
V>Пролог — тоже весьма мощная штука, но блин чего-то не пошел в массы, даже удивительно... Даже с ОО- и императивными расширениями.
У пролога трагическая судьба :)
Его загубили PC и слишком большие ожидания. Как и лисп
Пролог-машины, лисп-машины, Красота. а тут персоналки, мать их.
И все, всем считать байты :)
Здравствуйте, vdimas, Вы писали:
R>>...менеджер памяти. и операционную систему :)
V>Согласись, что написание своего менеджера памяти — это тот самый "особый случай", который не возникает сам по себе.
Не уверен, что понял.
Просто у меня это очень достаточно задача и на такие вещи я как правило не оглядываюсь.
R>>Написать свой аллокатор где угодно не проблема, просто за пределами С++ это требуется несколько реже :)
V>В Лисп — проблема, в Пролог — проблема. Не знаю как в других новомодных.
R>>Опять же — учитывая сколько в современном С++ своих объектов, а сколько всякого boost'a и прочего, сия возможность как-то не сильно обнадеживает.
V>В любой программе содержится счетное кол-во типов. Гораздо более счетно кол-во типов действительно требующих своего аллокатора. Обычно в командах С++ давно есть несколько разновидностей аллокаторов, которые просто прикручиваются к требуемым типам.
не просто :)
впрочем, это, опять же, зависит от специфики.
reductor,
> ПК> Пожалуй, правильнее говорить об управлении временем жизни объектов, с чем C++, действительно, справляется лучше ряда других языков благодаря детерминированному разрушению объектов. GC этой задачи не решает. > > Я все же не понимаю кое-чего. Для каких задач нужно такое управление?
Для любых, включающих необходимость своевременного освобождения внешних по отношению к программе ресурсов: файлы, сокеты, соединения с базами данных, хэндлы операционной системы и т.п. Основная проблема не столько в том, чтобы не забывать освобождать внешние ресурсы, а в том, чтобы надежно делать это в реальных условиях, когда, фактически, любая функция может выбросить исключение.
> Но даже если так, почему С++ здесь справляется лучше тех языков, у которых нет проблем с алиасингом?
Не вижу связи с aliasing, но в C++ этому помогает возможность использования RAII.
В том же Окамле, насколько я понимаю, лучшее, что получится сделать для автоматизированного освобождения ресурсов в присутствии исключений -- некоторый аналог using из C# (взято отсюда):
let using resource thunk =
try
let
result = thunk resource
in
dispose resource;
result
with
any_exception ->
dispose resource;
raise any_exception
конечно, это лучше, чем ничего, но очень далеко до RAII, т.к. не позволяет управлять временем жизни ресурсов, хранящихся в членах классов.
Posted via RSDN NNTP Server 2.0
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>reductor,
>> ПК> Пожалуй, правильнее говорить об управлении временем жизни объектов, с чем C++, действительно, справляется лучше ряда других языков благодаря детерминированному разрушению объектов. GC этой задачи не решает. >> >> Я все же не понимаю кое-чего. Для каких задач нужно такое управление?
ПК>Для любых, включающих необходимость своевременного освобождения внешних по отношению к программе ресурсов: файлы, сокеты, соединения с базами данных, хэндлы операционной системы и т.п. Основная проблема не столько в том, чтобы не забывать освобождать внешние ресурсы, а в том, чтобы надежно делать это в реальных условиях, когда, фактически, любая функция может выбросить исключение.
reductor,
> ПК>Для любых, включающих необходимость своевременного освобождения внешних по отношению к программе ресурсов: файлы, сокеты, соединения с базами данных, хэндлы операционной системы и т.п. Основная проблема не столько в том, чтобы не забывать освобождать внешние ресурсы, а в том, чтобы надежно делать это в реальных условиях, когда, фактически, любая функция может выбросить исключение. > > http://www.rsdn.ru/Forum/Message.aspx?mid=1522461&only=1
Вы, вероятно, недочитали, или же я Вас недопонял. На мой взгляд, в конце сообщения и было нечто в таком же духе, но как сказано далее, такой подход не позволяет управлять временем жизни ресурсов, хранящихся в членах классов. Не могли бы Вы привести пример, аналогичный следующему (C++):
В случае исключения в любой точке, как в этой функции, так и далее, где будет приниматься и использоваться MyObj, все занятые ресурсы будут автоматически освобождены вовремя. В общем случае время жизни MyObj вовсе необязательно ограничено лексической областью видимости или временем исполнения некоторой функции.
Posted via RSDN NNTP Server 2.0
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, vdimas, Вы писали:
V>речь шла о фичах, а не о внешнем их выражении.
Ну извините, я, видимо, не понял, о каких именно. ГА>>А еще все стандратные контейнеры свой размер кэшируют. И сделать то же самое на любом ФЯ можно (только не нужно). V>Нет, не можно.
Что я не так делаю ?
type 'a cached_size_list = CSList of 'a list * int
let make_cs_list list = CSList (list, List.length list)
let add_cs_list (CSList (lst, n)) item = CSList (item::lst, n+1)
let cs_list_length (CSList (_, n)) = n
let cs_list_head (CSList (lst, _)) = List.hd lst
let cs_list_tail (CSList (lst, n)) = CSList (List.tl lst, n-1)
# let ls = make_cs_list [1;2;3;4];;
val ls : int cached_size_list = CSList ([1; 2; 3; 4], 4)
# let ls1 = add_cs_list ls 0;;
val ls1 : int cached_size_list = CSList ([0; 1; 2; 3; 4], 5)
# let ls2 = cs_list_tail ls1;;
val ls2 : int cached_size_list = CSList ([1; 2; 3; 4], 4)
V>Голова списка (cons) — это может быть середина другого списка.
Список — не объект, это значение, у него нет identity. Пока мы играем по функциональным правилам и 1) не интересуемся физическим равенством объектов (в ОКамл такое можно) и 2) не модифицируем mutable объекты внутри списков, нас совершенно не интересует, что несколько логически различных списков имеют физически общий хвост.
Здравствуйте, Глеб Алексеев, Вы писали:
ГА>Список — не объект, это значение, у него нет identity. Пока мы играем по функциональным правилам и 1) не интересуемся физическим равенством объектов (в ОКамл такое можно) и 2) не модифицируем mutable объекты внутри списков, нас совершенно не интересует, что несколько логически различных списков имеют физически общий хвост.
Глеб, извини за оффтопик, а тебе, когда ты учился, функциональное программирования или Пролог читали или нет?
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Глеб, извини за оффтопик, а тебе, когда ты учился, функциональное программирования или Пролог читали или нет?
Да ничего. Я надеюсь, остальные участники нас простят.
Нет, я, к сожалению, учился не там, где это могли преподавать (эх, если бы я заканчивал MIT, я бы прошел SICP на первом курсе, а сейчас по ночам приходится ). На 90% все свои обрывочные знания о программировании добыл самостоятельно. Разве что мой будущий научный руководитель посоветовал обратить внимание на Пролог и подкинул пару тестовых задачек.