Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.9.173] |
|
Страницы: (11) « Первая ... 6 7 [8] 9 10 ... Последняя » все ( Перейти к последнему сообщению ) |
Сообщ.
#106
,
|
|
|
Цитата sergioK @ хватит тут теории разводить,с умным видом, JVM тут ыообще не причем, он и в STL есть, И вот это поизучай: ❯❯❯ g++ -O2 -std=c++17 -o lists main.cpp ❯❯❯ time ./lists 100000000 stdlist Result: 3749999975000000 ./lists 100000000 stdlist 14.97s user 0.91s system 99% cpu 15.892 total ❯❯❯ time ./lists 100000000 stdvector Result: 3749999975000000 ./lists 100000000 stdvector 0.61s user 0.42s system 99% cpu 1.040 total src #include <iostream> #include <list> #include <string> #include <vector> void usage(std::string, std::string); int64_t std_list(int64_t); int64_t std_vector(int64_t); int main(int argc, char** argv) { if (argc != 3) { usage(std::string(argv[0]), "invalid arguments"); return 1; } const int64_t n = std::stoi(std::string(argv[1])); if (n < 1) { usage(std::string(argv[0]), "invalid nitems"); return 2; } std::string type(argv[2]); int64_t result; if (type == "stdlist") { result = std_list(n); } else if (type == "stdvector") { result = std_vector(n); } else { usage(std::string(argv[0]), "unsupported type"); return 3; } std::cout << "Result: " << result << std::endl; } void usage(std::string app, std::string err) { std::cerr << err << std::endl; std::cerr << "Usage: " << app << " <nitems> <type>" << std::endl; std::cerr << "nitems: positive integer" << std::endl; std::cerr << "type:" << std::endl; std::cerr << "\tstdlist" << std::endl; std::cerr << "\tstdvector" << std::endl; } int64_t std_list(int64_t n) { std::list<int64_t> xs; for (auto i = 0; i < n; ++i) { xs.push_back(i); } xs.remove_if([n](int x) { return x < n/2; }); int64_t sum = 0; for (auto x : xs) { sum += x; } return sum; } int64_t std_vector(int64_t n) { std::vector<int64_t> xs; for (auto i = 0; i < n; ++i) { xs.push_back(i); } auto filter = std::remove_if(xs.begin(), xs.end(), [n](int x) { return x < n/2; }); xs.erase(filter, xs.end()); int64_t sum = 0; for (auto x : xs) { sum += x; } return sum; } Так что там с загрузкой неизвестного большого количества данных в linked list? |
Сообщ.
#107
,
|
|
|
Цитата korvin @ Цитата sergioK @ хватит тут теории разводить,с умным видом, JVM тут ыообще не причем, он и в STL есть, И вот это поизучай: ❯❯❯ g++ -O2 -std=c++17 -o lists main.cpp ❯❯❯ time ./lists 100000000 stdlist Result: 3749999975000000 ./lists 100000000 stdlist 14.97s user 0.91s system 99% cpu 15.892 total ❯❯❯ time ./lists 100000000 stdvector Result: 3749999975000000 ./lists 100000000 stdvector 0.61s user 0.42s system 99% cpu 1.040 total src #include <iostream> #include <list> #include <string> #include <vector> void usage(std::string, std::string); int64_t std_list(int64_t); int64_t std_vector(int64_t); int main(int argc, char** argv) { if (argc != 3) { usage(std::string(argv[0]), "invalid arguments"); return 1; } const int64_t n = std::stoi(std::string(argv[1])); if (n < 1) { usage(std::string(argv[0]), "invalid nitems"); return 2; } std::string type(argv[2]); int64_t result; if (type == "stdlist") { result = std_list(n); } else if (type == "stdvector") { result = std_vector(n); } else { usage(std::string(argv[0]), "unsupported type"); return 3; } std::cout << "Result: " << result << std::endl; } void usage(std::string app, std::string err) { std::cerr << err << std::endl; std::cerr << "Usage: " << app << " <nitems> <type>" << std::endl; std::cerr << "nitems: positive integer" << std::endl; std::cerr << "type:" << std::endl; std::cerr << "\tstdlist" << std::endl; std::cerr << "\tstdvector" << std::endl; } int64_t std_list(int64_t n) { std::list<int64_t> xs; for (auto i = 0; i < n; ++i) { xs.push_back(i); } xs.remove_if([n](int x) { return x < n/2; }); int64_t sum = 0; for (auto x : xs) { sum += x; } return sum; } int64_t std_vector(int64_t n) { std::vector<int64_t> xs; for (auto i = 0; i < n; ++i) { xs.push_back(i); } auto filter = std::remove_if(xs.begin(), xs.end(), [n](int x) { return x < n/2; }); xs.erase(filter, xs.end()); int64_t sum = 0; for (auto x : xs) { sum += x; } return sum; } Так что там с загрузкой неизвестного большого количества данных в linked list? Ты применяешь std_list не по месту, https://www.geeksforgeeks.org/advantages-an...of-linked-list/ больше я бесплатно обьяснять не буду , |
Сообщ.
#108
,
|
|
|
Цитата sergioK @ Ты применяешь std_list не по месту Цитата sergioK @ А LinkedList нужен когда ды ты считываешь данные неопередельной длины, особенно большие обьемы, а свои джуновские статейки лучше забудь. |
Сообщ.
#109
,
|
|
|
Ну какой был вопрос такой и ответ. Я не знаю чего ты ожидал.
Цитата D_KEY @ Скажем так. Спор сводится фактически к одному моему утверждению: Можно ли писать императивно не используя мутабельных переменных?.Аргументации чего? Ты выкинул из конвенционально принятого определения ИП половину, а аргументы какие-то должен приводить я? Причем не синтетические примеры, а реальный полезный код. Можно, конечно скатываться в терминологическую демагогию, как это делаешь ты: ну типа раз в определении ИП написано "мутабельный", значит ответ очевиден: низзя. А на остальное насрать. В таком случае можешь просто не участвовать в данном споре, потому что мне интересна оправданность необходимости мутабельности в ИП. Действительно ли иммутабельность кардинально меняет парадигму и код, внезапно, превращается в функциональный? Рассуждения о пользе этого спора вообще смехотворны, мы тут не поиском истины занимаемся, а делимся мыслями и точками зрения. Ведь вне зависимости от того согласитесь ли вы со мной или нет, ничего не поменяется вообще Беседа, по-сути, философская. Хотя некоторые аспекты диалога с korvin, уже ближе к реальности. Цитата D_KEY @ Я рассуждаю так. Вот код, в нем есть последовательность инструкций, но нет мутабельности. Получается, что код не подходит под "конвенционально принятое" определение ФП (не должно быть последовательности инструкций). И не подходит под "конвенционально принятое" определение ИП (должна быть мутабельность).Смотри, это зависит от определения императивности. Ты же пытаешься наоборот , из примера вывести определение. Или я тебя не понимаю. Подумав я решил, что иммутабельность в ФП - это не какая-то самоцель, а следствие из самой сущности ФП. Нет необходимости где-то держать промежуточные результаты, потому что их попросту не существует, а что тогда мутировать? Получается, что иммутабельность не должна входить в определение ФП вообще, она автоматически следует из отсутствия промежуточных результатов. Далее, рассматривая ИП, я пришел к выводу, что промежуточные результаты совсем не обязательно должны быть мутабельными. Что мешает на очередном шаге создавать новую иммутабельную переменную, вместо мутации старой? Ничего не мешает, более того, я постоянно так делаю, и при этом код не превращается в функциональный, так как последовательность иструкций никуда не девается. Получается, что обязательность мутабельности как бы "искусственно" прицеплена к определению, без каких либо логических причин. А как же эта мутабельность вообще попала в определение ИП? Ведь вряд ли кто-то действительно беспричинно ее туда запихал. Но это можно объяснить просто историей императивного программирования. Отсюда делаю. вывод: "конвенционально принятое" определение ИП устарело. Ключевое - это последовательность инструкций. А, если подняться еще выше по уровню абстракции, то ИП тесно связано с течением времени. Время - это не просто очередная координата пространства, а фундаментальная особая составляющая ИП. В отличие от ФП. Ну так не выводи в консоль, а просто возвращай результат и получится чистое ФП. Не понимаю, что ты хотел сказать этим примером. Цитата korvin @ Ты ошибаешься, возможно путаешь иммутабельность и возможность объявлять константы. const в том же Си появилась, внезапно, в C89, благодаря тому самому Страуструпу, который добавил его сначала в свой Си с классами. Я помню времена, когда строковые литералы в сяшке имели тип char*. В школьном бейсике вообще не было никаких константных переменных. В php нормальной иммутабельности не было ни в 4-ой, ни в 5-ой версии, сейчсас не знаю. В JS const появился в ES6. Интересно, что даже сейчас const ни в C, ни в C++, ни в JS не является полноценной поддержкой иммутабельности, так как const не гарантирует иммутабельность (в отличие от immutable в D). Короче, о иммутабельности в прикладном программировании серъезно начали задумываться сравнительно недавно. ФП, конечно, возникло давно, но оно едва-едва начало выползать из академических кругов.Так как бы языки перестают быть "монопарадигмальными". А популярные языки никогда такими и не были. Иммутабельность была в Си, Паскале и практически любом другом языке с самого начала, не понимаю, что эта твоя фраза должна означать. Вообще-то нет. Этож одна из фишек этого вашего ФП, типа смотрите, компилятор может все нафиг распараллелить. Представь, что операция сравнения очень тяжелая. В ФП можно раздербанить список на элементы и запустить кучу потоков, которые будут параллельно выполнять сравнение. При этом твой код никак не изменится. Нет не присутствует. Сравни императивную версию: a = foo(x) bar(a) с функциональной bar(foo(x)) На первый взгляд кажется, что разницы нет, но на самом деле есть. В императивном варианте функция foo будет выполнена до начала выполнения функции bar. В функциональной же версии foo может быть выполнена уже после начала выполнения bar (например в середине или даже паралелльно), да и вообще пофиг когда она выполнится. Мысли абстрактней, в ФП композиция функций - это просто новая функция, а не последовательность вызовов функций. В реальности, конечно, последовательность будет, потому что исполнитель любой ФП-программы императивен и любая задача все равно так или иначе будет разбитна на шаги компилятором/интерпретатором. Этот эффект используется в Haskell, там, где нужна императивность, например в некоторых монадах. Но это не относится к самой парадигме ФП, это несовершенство реализации. |
Сообщ.
#110
,
|
|
|
Цитата applegame @ Отсюда делаю. вывод: "конвенционально принятое" определение ИП устарело. Я бы сделал другой вывод. Применение термина ИП к практике современного программирования потеряло актуальность. Ну и подходов-то не два Да и в чистом виде мало кто применяет только какой-то один. |
Сообщ.
#111
,
|
|
|
Цитата korvin @ Да не, там отличные, на мой взгляд, статейки. Там прекрасно описаны достоинства и недостатки связных списков в том числе по сравнению с массивам. И вообще, рассмотрена туева хуча всяких видов списков, включая xor и unrolled варианты, на доступном английском языке с картинками. Даже дебил осилит. Инфа представленная там никак не противоречит твоим бенчам, скорее наоборот, объясняет почему так может происходить. а свои джуновские статейки лучше забудь. |
Сообщ.
#112
,
|
|
|
Цитата applegame @ Ты ошибаешься, возможно путаешь иммутабельность и возможность объявлять константы. const в том же Си появилась, внезапно, в C89, благодаря тому самому Страуструпу, который добавил его сначала в свой Си с классами. Я помню времена, когда строковые литералы в сяшке имели тип char*. В школьном бейсике вообще не было никаких константных переменных. Нет, не ошибаюсь. Но раз ты не понял, о чём я, то подскажу: opaque struct + функции чтения. Цитата applegame @ Вообще-то нет. Вообще-то да. Цитата applegame @ Этож одна из фишек этого вашего ФП, типа смотрите, компилятор может все нафиг распараллелить. Параллельность к этому примеру вообще не в тему. Цитата applegame @ В ФП можно раздербанить список на элементы и запустить кучу потоков, которые будут параллельно выполнять сравнение. При этом твой код никак не изменится. В моём примере нет списка. Цитата applegame @ a = foo(x) bar(a) bar(foo(x)) На первый взгляд кажется, что разницы нет, но на самом деле есть. В императивном варианте функция foo будет выполнена до начала выполнения функции bar. В функциональной же версии foo может быть выполнена уже после начала выполнения bar (например в середине или даже паралелльно), да и вообще пофиг когда она выполнится. Мысли абстрактней, в ФП композиция функций - это просто новая функция, а не последовательность вызовов функций. И вот ты снова путаешь синтаксис и семантику. Чисто функциональный код на Хаскелле: do a <- foo x bar a do-нотация является ни чем иным, как синтаксическим сахаром для монадной функции bind (оператор '>>=' и '>>' ): foo x >>= \a -> bar a который в свою очередь является просто композицией функций, определённой в используемой монаде: (\a -> bar a) (unwrap (foo x)) При этом bar(foo(x)) foo вычислится гарантировано до вызова bar при аппликативном порядке вычислений (а это все неленивые ФП языки, F#, Ocaml, Clojure и т.д.) а a = foo(x) bar(a) может вычислиться в другом порядке при нормальном порядке вычислений или просто отложенных вычислениях, например, в Си/Паскале foo может вернуть какой-то объект Promise. Цитата applegame @ Да не, там отличные, на мой взгляд, статейки. Там прекрасно описаны достоинства и недостатки связных списков в том числе по сравнению с массивам. И вообще, рассмотрена туева хуча всяких видов списков, включая xor и unrolled варианты, на доступном английском языке с картинками. Даже дебил осилит. Инфа представленная там никак не противоречит твоим бенчам, скорее наоборот, объясняет почему так может происходить. Значит, sergioK и вправду джун, раз не понимает даже статей, на которые сам ссылается. ) |
Сообщ.
#113
,
|
|
|
Цитата korvin @ Это ты называешь поддержкой иммутабельности в языке? Я вообще никогда не встречал, чтобы кто-то использовал opaque типы ради иммутабельности. Это же трешовый костыль вроде immutable.js. Ты бы еще просто запрет программисту менять объект назвал поддержкой иммутабельности в языке.Нет, не ошибаюсь. Но раз ты не понял, о чём я, то подскажу: opaque struct + функции чтения. Цитата korvin @ Тут нет списка?В моём примере нет списка. Что касается оператора ||, то хотя в конкретной реализации (например GHC) сначала действительно будет вычислено значение левого операнда, надо понимать, что это просто деталь реализации. || - это ведь просто функция двух аргументов и ты сам совершенно правильно говорил, что порядок вычисления этих аргументов не имеет значения в ФП: Цитата korvin @ Судя по тому, что я нашел в интернетах, Haskell не запрещает реализации вычисляющие операнды в любом порядке.Странный вопрос. Для чистого ФП разницы нет (разве что одна из функций bar, baz значительно дольше вычисляется, чем другая). Цитата korvin @ То что do-нотация является сахаром к монаде - это не семантика, это детали реализации. Семантика же заключается в последовательном выполнении. И do-нотация, кмк, отходит от ФП в сторону ИП.И вот ты снова путаешь синтаксис и семантику. Цитата korvin @ Это опять же деталь реализации. Мы же не о конкретном языке говорим. ФП подразумевает нестрогую модель вычислений: порядок выполнения функций неважен.foo вычислится гарантировано до вызова bar при аппликативном порядке вычислений (а это все неленивые ФП языки, F#, Ocaml, Clojure и т.д.) Цитата korvin @ Пример с Promise неудачен, функция foo-то все равно выполнена до начала выполнения функции bar. Что касается нормального порядка вычислений, то это опять же деталь реализации. Компилятор может сделать редукцию, свертку констант и так далее, а может и не сделать. Результат гарантированно будет таким же как и при реально последовательном выполнении, иначе это неправильный компилятор.может вычислиться в другом порядке при нормальном порядке вычислений или просто отложенных вычислениях, например, в Си/Паскале foo может вернуть какой-то объект Promise. В общем, ты везде ссылаешься на конкретные реализации, причем разные в разных ФП-языках. |
Сообщ.
#114
,
|
|
|
Цитата korvin @ Значит, sergioK и вправду джун, раз не понимает даже статей, на которые сам ссылается. ) Не не понимаю, я ничего кроме hello world никогда не писал |
Сообщ.
#115
,
|
|
|
Цитата applegame @ Я вообще никогда не встречал, чтобы кто-то использовал opaque типы ради иммутабельности. Мало ли что ты не встречал. Цитата applegame @ Это же трешовый костыль В чём тут трешевость и костыльность? Цитата applegame @ Ты бы еще просто запрет программисту менять объект назвал поддержкой иммутабельности в языке. WUT? Цитата applegame @ надо понимать, что это просто деталь реализации И что, что это деталь реализации? Порядок задан? Задан. Цитата applegame @ Судя по тому, что я нашел в интернетах, Haskell не запрещает реализации вычисляющие операнды в любом порядке. И что? Calling conventions тоже разные бывают. Цитата applegame @ То что do-нотация является сахаром к монаде - это не семантика, это детали реализации Нет, это то, чем она является. Цитата applegame @ Семантика же заключается в последовательном выполнении Нет, не заключается. Цитата applegame @ И do-нотация, кмк, отходит от ФП в сторону ИП. Не отходит. Что, по-твоему, означает эта запись: do a <- foo x b <- bar y return $ gee a b ? Цитата applegame @ Пример с Promise неудачен, функция foo-то все равно выполнена до начала выполнения функции bar. И что, что она выполнена до? Что будет, если поменять их местами? Чем по-твоему это отличается от Хаскелла, например? Чем это отличается от ФП, если реальное вычисление может быть выполнено в любом порядке? Цитата applegame @ Результат гарантированно будет таким же как и при реально последовательном выполнении, иначе это неправильный компилятор. В общем, ты везде ссылаешься на конкретные реализации, причем разные в разных ФП-языках. Что ты вообще несёшь? Ответь лучше на вопрос: почему в ИП порядок имеет значение? Что будет, если в a = foo(x) b = bar(y) gee(a, b) поменять местами вызовы foo и bar: b = bar(y) a = foo(x) gee(a, b) ? Добавлено И ещё вопрос: для ФПшной композиции порядок важен? foo x = x + x bar x = (x, x) foo . bar и bar . foo — одно и то же или нет? А тут: foo x = x + 1 bar x = x * 2 foo . bar bar . foo ? |
Сообщ.
#116
,
|
|
|
И кроме всего прочего, как компилятор, так и процессор могут переставлять инструкции при необходимости, если это не нарушает связи между данными и не изменяет наблюдаемый результат, поэтому порядок инструкций языка может не везде совпадать с реальным порядком выполнения.
Например http://csg.csail.mit.edu/pubs/memos/Memo-493/memo-493.pdf |
Сообщ.
#117
,
|
|
|
Цитата Qraizer @ Использовались ли математические методы доказательства правильности разработанных алгоритмов? На закуску: приходилось ли проектировать системы с учётом возможных неизвестных аппаратных багов в процессорах? Математически доказано, что невозможно проверить зависнет программа или нет. На этом можно остановиться. Программа должна работать на компьютере, который не умеет считать? |
Сообщ.
#118
,
|
|
|
Цитата korvin @ А ты встречал чтобы кто-нибудь в C/С++ задействовал opaque типы ради иммутабельности? Пруфы пожалуйста.Мало ли что ты не встречал. Цитата korvin @ В том, что гарантиии иммутабельности дает не язык, а код, то бишь программист. Например те же функции чтения могут из-за ошибки программиста изменить opaque данные, и компилятор возражать не будет.В чём тут трешевость и костыльность? Цитата korvin @ В GHC задан, в другом компиляторе может быть не задан. Ты же надеюсь понимаешь, что мы обсуждаем не конкретные реализации, а ФП в целом? Ты же сам признал, что порядок вычисления аргументов функции в ФП не имеет значения.И что, что это деталь реализации? Порядок задан? Задан. Цитата korvin @ Ну тогда она является императивными машинными кодами, а реального ФП не существует.Нет, это то, чем она является. Цитата korvin @ Как минимум она означает, что foo будет выполнена раньше чем bar. Вся эта ваша монада IO для этого и предназначена: дать возможность в Haskell выполнять код последовательно, потому что IO - это связь с внешним миром, который императивен.Что, по-твоему, означает эта запись: Цитата korvin @ Если поменять местами строчки, оно просто не скомпилируется. Тем что во всякой императивщине отложенность прописывается явно, то есть программист сам решает в каком порядке делать вычисления, а в Хаскелле програмисту пофиг (до тех пор пока не столкнется с императивной реальностью) в каком порядке оно будет считаться. От ФП отличается тем, что в ИП программист точно знает, что конечный результат будет как при последовательном выполнении. А в ФП наплевать на порядок выполнения вообще, компилятор может выполнять функции в любом нужном ему порядке.И что, что она выполнена до? Что будет, если поменять их местами? Чем по-твоему это отличается от Хаскелла, например? Чем это отличается от ФП, если реальное вычисление может быть выполнено в любом порядке? Цитата korvin @ Результат может измениться. А вот в чистом ФП (например Хаскеле) ничего измениться не может.Ответь лучше на вопрос: почему в ИП порядок имеет значение? Что будет, если в a = foo(x) b = bar(y) gee(a, b) b = bar(y) a = foo(x) gee(a, b) Цитата korvin @ Порядок чего? Порядок записи конечно важен, могут же получиться в итоге разные функции. Примерно как спросить, поменяется ли что-нибудь если в числе 42 поменять местами 2 и 4.И ещё вопрос: для ФПшной композиции порядок важен? Цитата korvin @ Ключевое тут "не изменяет наблюдаемый результат". Более того, наблюдаемый результат обязан быть таким же как при последовательном выполнении инструкций. То есть компилятор может делать все что угодно (детали реализации), но выглядеть все должно так, как будто инструкции выполняются одна за другой. И кроме всего прочего, как компилятор, так и процессор могут переставлять инструкции при необходимости, если это не нарушает связи между данными и не изменяет наблюдаемый результат, поэтому порядок инструкций языка может не везде совпадать с реальным порядком выполнения. |
Сообщ.
#119
,
|
|
|
Цитата applegame @ А ты встречал чтобы кто-нибудь в C/С++ задействовал opaque типы ради иммутабельности? Пруфы пожалуйста. А если не встречал, то что это доказывает? Я так-то на Си не пишу. Цитата applegame @ В GHC задан, в другом компиляторе может быть не задан. Ты же надеюсь понимаешь, что мы обсуждаем не конкретные реализации, а ФП в целом? Ты же сам признал, что порядок вычисления аргументов функции в ФП не имеет значения. "Не имеет значения" и "отсутствует" --- не одно и то же Цитата applegame @ Как минимум она означает, что foo будет выполнена раньше чем bar. Вся эта ваша монада IO для этого и предназначена: дать возможность в Haskell выполнять код последовательно, потому что IO - это связь с внешним миром, который императивен. Не обязательно. И do-нотация не завязана на монаду IO, она работает с любой монадой, например монадой списков: import Data.Char foo = map chr . map (+ ord 'a') bar = filter even gee x y = (x, y) main = let x = [1,2,3] y = [4,5,6] in print $ do a <- foo x b <- bar y return $ gee a b https://ideone.com/0wW9IY [('b',4),('b',6),('c',4),('c',6),('d',4),('d',6)] Порядок определяется реализацией монады для конкретного типа, а не do-выражением. Цитата applegame @ Результат может измениться. А вот в чистом ФП (например Хаскеле) ничего измениться не может. За счёт чего же результат может измениться? ) Цитата applegame @ Ключевое тут "не изменяет наблюдаемый результат" А за счёт чего наблюдаемый результат может измениться? Цитата applegame @ Если поменять местами строчки, оно просто не скомпилируется. Это в первом случае, где у функций разные типы. А во втором? Там всё прекрасно скомпилируется. А результат поменяется? |
Сообщ.
#120
,
|
|
|
Цитата korvin @ Я писал много и на Си и на C++. Никто на парится иммутабельностью вообще. Раньше даже const-ом не заморачивались, сейчас юзают const, который тоже не является полноценной заменой иммутабельности. В общем никакой поддержки иммутабельности в самих языках C/С++/JS/PHP и многих других нет. Есть только попытки эмулировать ее теми или иными способами, и эти эмуляции мало кого интересуют. В Rust есть полноценная иммутабельность, в D тоже есть.А если не встречал, то что это доказывает? Я так-то на Си не пишу. Цитата korvin @ А ты не противопоставляй эти тезисы. Последовательность отсутствует в ФП-коде, потому что не она не имеет значения. То бишь сам ФП-код не задает никакой последовательности действий. Это уже реализация имеет какую-то последовательность, которая тоже может быть любой."Не имеет значения" и "отсутствует" --- не одно и то же Цитата korvin @ Честно говоря лень уже дальше разбираться. Мое знание Хаскеля достаточно базовое и довольно тяжело копаться даже в несложных кусках.Не обязательно. И do-нотация не завязана на монаду IO, она работает с любой монадой, например монадой списков: Погуглив по словам "haskell do imperative" обнаружил кучу упоминаний о том, что на хаскеле можно (но не нужно) писать имеративно, применяя монады, что do-нотация является псевдоимперативной или imperative style и так далее. Цитата korvin @ За счёт чего же результат может измениться? ) Цитата korvin @ За счет побочных эффектов, очевидно. Причем побочных эффектов в реальности может и не быть, но если компилятор об этом не знает, то он не будет переставлять местами инструкции.А за счёт чего наблюдаемый результат может измениться? Цитата korvin @ Ты похоже потерял нить, проследи эту ветку немного назад. Речь вроде шла об этом куске:Это в первом случае, где у функций разные типы. А во втором? Там всё прекрасно скомпилируется. А результат поменяется? a = foo(x) bar(a) |