Re[68]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: Somescout  
Дата: 07.11.19 03:08
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Не обязательно. Это "будущее" к моменту исполнения нашей функции, возможно, уже наступило. Классика жанра — фильтрация с необязательными условиями. Можно внести необязательность в сам предикат:

S>
S>where orderDate >= @startDate or  @startDate is null
S>

S>а можно вычислить её в процессе построения предиката:
S>
S>if (startDate.HasValue)
S>  q = q.Where(_ => _.orderDate >= startDate);
S>

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

S>Итого у нас не просто throughput падает вшестеро, но и response times вырастают в 10 раз.

S>Просто из-за неудачного выбора порядка операций.
Так себе пример: вы приводите откровенно неоптимальный вариант, и сравниваете его с идеальным, причём не только по исполнению, но и по условиям, когда запрос может быть выполнен целиком на БД, без участия клиента. А такое возможно только с полностью "чистой" функцией.

ЗЫ. Оффтоп — интересно, а есть ли какие-нибудь эксперименты по трансляции C# кода в SQL? В смысле за пределами linq-выражений, трансляция метода целиком.
ARI ARI ARI... Arrivederci!
Re[76]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.11.19 03:50
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, samius, Вы писали:


S>>Уверен лишь в том, что нет смысла искать, т.к. ты захочешь трактовать по-своему. Как с цитатой с хабра.


ARK>Если определение размытое, то захочу, конечно. Ты считаешь это некорректным?

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

S>>>>И еще в этом можно убедиться с помощью отладчика.

ARK>>>Отладчик — это сторонняя программа, она не может определять семантику языка.
S>>Хорошо, прикрути вывод в файл.

ARK>Тут не понял.

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

S>>И в чем же это будет аналог printf, если выполнение printf приводит к выводу на консоль?


ARK>Это написано в описании стандартной библиотеки С? А у хаскеля в документации написано, что IO-функция не приводит к выводу на консоль, а просто создает Action? А если бы было написано все наоборот — ну, просто предположим такое, абстрагируемся от текущего положения дел — то ты бы считал хаскельную функцию грязной, а сишную чистой?

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

ARK>>>Если определение позволяет трактовать себя разными способами — значит, оно не является формальным. Каким образом, по твоему мнению, необходимо дополнить определение, чтобы исключить "такую трактовку"?

S>>Я ее исключаю без дополнений.

ARK>Почему? Чем она плоха?

отсутствием смысла. Ты вводишь свойства объектов для того, что бы рассуждать об объектах, чем объекты с этим свойством отличаются от объектов без этого свойства. Но не можешь назвать ни один без этого свойства. Зачем мы теряем время?

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


ARK>Я понимаю. Но не понимаю, как ты не можешь понять, что определение, допускающее различные трактовки — бесполезное?

Определение функции трактуется однозначно или бесполезно?

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

Это зависит от того, что хочешь объяснить.

ARK>- Что такое яблоко?

ARK>- Это зеленый шарик.
ARK>- Но дальтоники видят розовый вместо зеленого, получается, что для них розовый пластиковый шарик и яблоко — это одно и то же?
ARK>- Нет.
ARK>- Почему нет? Твое определение яблока полностью подходит для розового пластикового шара, если человек дальтоник.
ARK>- Яблоко — не пластиковый шарик, это твоя трактовка.
ARK>- Тогда дополни свое определение, чтобы дальтоник смог отличить зеленое яблоко от розового пластикового шарика.
ARK>- Я отвергаю твою трактовку без каких-либо дополнений.
ARK>- А если посветить на яблоко светом другого спектра, то оно тоже зеленым выглядеть не будет, даже для обычного человека.
ARK>- Другие спектры я обсуждать не готов, даже пытаться не буду.

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

ARK>>>А почему любая функция С не чиста? Это "общеизвестно"?

S>>Почему вдруг любая функция С не чиста? Разве я делал такое утверждение или это следует из моих утверждений?

ARK>Уже спрашивал, спрошу еще раз: как отличить чистую функцию С от нечистой? Как ты поймешь, делает она ввод-вывод или нет? Отладчик, на всякий случай, не задает семантику языка. Семантику языка и стандартных функций задает спецификация языка и описание стандартной библиотеки (документация).

Кстати, я тоже умею не отвечать на прямые вопросы.
Но здесь ты пытаешься нарушить семантику самой функции, утверждая, что она возвращает action, в то время, как она возвращает void. Что бы понять это не нужна семантика языка.
Может быть имеет смысл начать от определения функции?
Re[69]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.11.19 04:53
Оценка:
Здравствуйте, Somescout, Вы писали:

S>Здравствуйте, Sinclair, Вы писали:


S>>Не обязательно. Это "будущее" к моменту исполнения нашей функции, возможно, уже наступило. Классика жанра — фильтрация с необязательными условиями. Можно внести необязательность в сам предикат:

S>>
S>>where orderDate >= @startDate or  @startDate is null
S>>

S>>а можно вычислить её в процессе построения предиката:
S>>
S>>if (startDate.HasValue)
S>>  q = q.Where(_ => _.orderDate >= startDate);
S>>

S>Не понял пример: в первом случае ничего заранее отброшено не будет, а во втором нужны внешние данные — грязная функция.
Нет. У нас разная трактовка термина "чистая функция". Факториалу-то вроде бы тоже нужны "внешние данные". Тем не менее, чистота факториала сомнений не вызывает. "Грязной" функция становится тогда, когда меняет разделяемое состояние.
Так и тут — функция IQueryable<X> BuildReportStatement<X>(...., ...., ...., startDate, .....) является чистой. Она зависит от своих параметров и всё — её результат можно безопасно кэшировать; можно её исполнять без подключения к реальной базе и т.п.

S>>Итого у нас не просто throughput падает вшестеро, но и response times вырастают в 10 раз.

S>>Просто из-за неудачного выбора порядка операций.
S>Так себе пример: вы приводите откровенно неоптимальный вариант, и сравниваете его с идеальным, причём не только по исполнению, но и по условиям, когда запрос может быть выполнен целиком на БД, без участия клиента. А такое возможно только с полностью "чистой" функцией.
Ну нет конечно. Всё как раз наоборот — эта функция максимально нечиста; она лезет "в базу" в течение всего цикла исполнения. То-то и оно, что на входе в функцию мы имеем, скажем, пару параметров — типа номер заказа и флаг "можно ли дробить по нескольким складам".
На выходе из функции — функция с одним параметром, "номер заказа". Флаг превратился в тело функции — набор SQL стейтментов, которые надо будет исполнить.
Теперь мы делаем db.ExecuteNonQuery(stmt, orderNumber), и получаем весь процессинг в один приём.

S>ЗЫ. Оффтоп — интересно, а есть ли какие-нибудь эксперименты по трансляции C# кода в SQL? В смысле за пределами linq-выражений, трансляция метода целиком.

Не в курсе. В прошлый раз, когда я смотрел, всё упиралось в неполноценность лямбд. C#-код удобно транслировать тогда, когда он представлен в виде Expression<>, а для statements в шарпе была ограниченная поддержка. Вроде были планы её починить, но я не знаю, чем там дело кончилось.
А заниматься трансляцией CLR-кода в SQL — это на порядок более трудная задача.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[70]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: Somescout  
Дата: 07.11.19 05:49
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>>Не понял пример: в первом случае ничего заранее отброшено не будет, а во втором нужны внешние данные — грязная функция.

S>Нет. У нас разная трактовка термина "чистая функция". Факториалу-то вроде бы тоже нужны "внешние данные". Тем не менее, чистота факториала сомнений не вызывает. "Грязной" функция становится тогда, когда меняет разделяемое состояние.
S>Так и тут — функция IQueryable<X> BuildReportStatement<X>(...., ...., ...., startDate, .....) является чистой. Она зависит от своих параметров и всё — её результат можно безопасно кэшировать; можно её исполнять без подключения к реальной базе и т.п.

Я всё ещё рассуждаю в контексте:
S> Во-первых, у нас могут быть "тупиковые" ветки, которые будут выброшены в процессе построения батча на основе условий, которые обнаружатся "в будущем".

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

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

S>На выходе из функции — функция с одним параметром, "номер заказа". Флаг превратился в тело функции — набор SQL стейтментов, которые надо будет исполнить.
S>Теперь мы делаем db.ExecuteNonQuery(stmt, orderNumber), и получаем весь процессинг в один приём.

Ну конечно да: если функция исполняется базой и зависит только от данных базы, и не запрашивает никакие внешние данные — это вполне аналог чистой функции (по крайней мере если она сама ничего не меняет). А если нужно какую-то часть данных обработать на клиенте? Или сджоинить с данными из другой базы или сервиса?
ARI ARI ARI... Arrivederci!
Re[77]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: AlexRK  
Дата: 07.11.19 06:33
Оценка:
Здравствуйте, samius, Вы писали:

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


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

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


А в хаскеле это будет не так? Если вывести в файл tickCount перед, после и в самом putStr, то нельзя будет убедиться в том, что именно во время вызова putStr остается грязь на консоли?

S>Если бы было написано наоборот, но при этом printf был бы void, а putStr IO(), то я бы подумал, какая чушь написана в документации. Но если бы printf был типа IO или аналога, а putStr был бы void, то да, пришлось бы считать хаскельную функцию грязной, а сишную чистой. Еще я бы для контроля заглянул в исходники, разумеется. И понаблюдал бы, выводится ли вообще хоть что-нибудь.


Мы возвращаемся к утверждению, что чистой функцию делает некоторый синтаксис. Типа — если написано "IO printf", то функция чистая, а если написано "void printf" — то однозначно грязная. А если написано "QWERTY printf", то ты это не готов обсуждать, насколько я помню.

Но вот другой пример. В одной из ранних версий языка Rust все функции считались чистыми, кроме тех, которые были помечены специальным словом "io": https://mail.mozilla.org/pipermail/rust-dev/2013-April/003926.html

A long time ago we had an effect system and we made pure the default (since we didn't want people accidentally leaving it out due to sloth) and we made the impure specifier a very small and reasonable keyword: "io".


Потом все стали делать все функции "io" и это слово убрали:

Eventually people just took to making everything io, at which point it was a noise word and we decided to remove it (along with 'pred', which just meant pure, bool, and tracked by the typestate layer).


Можно ли сказать что-то чистоте такой функции на Rust, просто по одному синтаксису?
fn main() {
    my_func("test");
}


Ранняя спецификация языка трактует эту функцию как чистую, нынешняя — как грязную.

Получается, по одному только голому синтаксису, без знания семантики, ничего нельзя сказать, не так ли? Синтаксис — это условность, главное, какая семантика из него следует. А семантика берется ровно из одного места — из документации по языку. Если в спецификации написано, что "QWERTY printf" — чистая функция, значит, она чистая. И если написано, что "void printf" — чистая функция, то она тоже будет считаться чистой. Такие дела.

ARK>>Почему? Чем она плоха?

S>отсутствием смысла. Ты вводишь свойства объектов для того, что бы рассуждать об объектах, чем объекты с этим свойством отличаются от объектов без этого свойства. Но не можешь назвать ни один без этого свойства. Зачем мы теряем время?

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

ARK>>>>А почему любая функция С не чиста? Это "общеизвестно"?

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

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

ARK>>Уже спрашивал, спрошу еще раз: как отличить чистую функцию С от нечистой? Как ты поймешь, делает она ввод-вывод или нет? Отладчик, на всякий случай, не задает семантику языка. Семантику языка и стандартных функций задает спецификация языка и описание стандартной библиотеки (документация).

S>Но здесь ты пытаешься нарушить семантику самой функции, утверждая, что она возвращает action, в то время, как она возвращает void. Что бы понять это не нужна семантика языка.

Именно что семантика нужна. Надо знать, что такое "void", что такое "action", что такое "IO". Без семантики это просто пустые слова. В общем, см. выше пример про Rust.
Re[71]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.11.19 07:05
Оценка:
Здравствуйте, Somescout, Вы писали:

S>Я всё ещё рассуждаю в контексте:

S>> Во-первых, у нас могут быть "тупиковые" ветки, которые будут выброшены в процессе построения батча на основе условий, которые обнаружатся "в будущем".
S>Никаких тупиковых ветвей здесь выброшено не будет, потому что будущее не известно и существует зависимость от внешнего состояния.
Я плохо объяснил термин "будущее". Вот я пишу функцию сейчас — я не знаю, потребуется ли отбор по startDate, или нет, до момента получения запроса от клиента. Оба варианта закодированы в функции. Но в исполняющий конвеер попадёт только один — тот, который будет нужен по факту. Потенциально в функции факториал спрятана бесконечная рекурсия; на практике для конечного значения параметра она всегда ограничена.
Вот если бы функция построения запроса "лезла" во "внешний мир" — вот тогда она была бы грязной. Ну, как во времена десктопных приложений девяностых не было ничего стрёмного в функции Print(), которая при печати "в файл" внезапно выкидывала диалог выбора имени файла. Она грязная "в обе стороны" — её результат зависит не от параметров, а от того, что ввёл пользователь во внешнем мире, и что там лежит на диске по неизвестному заранее адресу.

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

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

Вот вы сейчас про какую функцию говорите — про ту, которая строит запрос, или про ту, которая является результатом построения?
И что значит "обработать на клиенте"?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[78]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.11.19 08:27
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, samius, Вы писали:


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


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

Именно. Для меня все однозначно. Но на протяжении десятка лет на rsdn находятся другие трактовки.

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


ARK>А в хаскеле это будет не так? Если вывести в файл tickCount перед, после и в самом putStr, то нельзя будет убедиться в том, что именно во время вызова putStr остается грязь на консоли?

В том-то и дело, что не так. вызов putStr не приведет к выводу на консоль. Я уже устал это повторять.

S>>Если бы было написано наоборот, но при этом printf был бы void, а putStr IO(), то я бы подумал, какая чушь написана в документации. Но если бы printf был типа IO или аналога, а putStr был бы void, то да, пришлось бы считать хаскельную функцию грязной, а сишную чистой. Еще я бы для контроля заглянул в исходники, разумеется. И понаблюдал бы, выводится ли вообще хоть что-нибудь.


ARK>Мы возвращаемся к утверждению, что чистой функцию делает некоторый синтаксис. Типа — если написано "IO printf", то функция чистая, а если написано "void printf" — то однозначно грязная. А если написано "QWERTY printf", то ты это не готов обсуждать, насколько я помню.


Не было такого утверждения, что чистой функцию делает синтаксис. По-крайней мере от меня. И если уж на то пошло, то "void printf" вообще затруднительно рассматривать в виде математического понятия функции. Разве что, будем считать void пустым множеством.
Хорошо, рассмотрим "QUERTY printf". Но если она испачкает консоль (или файл, ...) между моментом передачи ей управления и моментом возврата управления, то, боюсь, чистоты мы не получим.

ARK>Но вот другой пример. В одной из ранних версий языка Rust все функции считались чистыми, кроме тех, которые были помечены специальным словом "io": https://mail.mozilla.org/pipermail/rust-dev/2013-April/003926.html

ARK>

ARK>A long time ago we had an effect system and we made pure the default (since we didn't want people accidentally leaving it out due to sloth) and we made the impure specifier a very small and reasonable keyword: "io".


ARK>Потом все стали делать все функции "io" и это слово убрали:

ARK>

ARK>Eventually people just took to making everything io, at which point it was a noise word and we decided to remove it (along with 'pred', which just meant pure, bool, and tracked by the typestate layer).


Я не знаю Rust и не готов рассуждать о чистоте его функций, о том, насколько адекватно то, что пишут в его документации.

ARK>Можно ли сказать что-то чистоте такой функции на Rust, просто по одному синтаксису?

ARK>
ARK>fn main() {
ARK>    my_func("test");
ARK>}
ARK>

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

ARK>Ранняя спецификация языка трактует эту функцию как чистую, нынешняя — как грязную.

И определяется это не спецификацией. Если бы было так — в определении чистоты бы стояло "смотри спецификацию".

ARK>Получается, по одному только голому синтаксису, без знания семантики, ничего нельзя сказать, не так ли? Синтаксис — это условность, главное, какая семантика из него следует. А семантика берется ровно из одного места — из документации по языку. Если в спецификации написано, что "QWERTY printf" — чистая функция, значит, она чистая. И если написано, что "void printf" — чистая функция, то она тоже будет считаться чистой. Такие дела.


Не семантика определяет чистоту, а поведение функции.

ARK>>>Почему? Чем она плоха?

S>>отсутствием смысла. Ты вводишь свойства объектов для того, что бы рассуждать об объектах, чем объекты с этим свойством отличаются от объектов без этого свойства. Но не можешь назвать ни один без этого свойства. Зачем мы теряем время?

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

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

ARK>>>>>А почему любая функция С не чиста? Это "общеизвестно"?

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

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

Конечно, не разделяю такое мнение. А согласно каким данным такое мнение считается общепринятым?

S>>Но здесь ты пытаешься нарушить семантику самой функции, утверждая, что она возвращает action, в то время, как она возвращает void. Что бы понять это не нужна семантика языка.


ARK>Именно что семантика нужна. Надо знать, что такое "void", что такое "action", что такое "IO". Без семантики это просто пустые слова. В общем, см. выше пример про Rust.


Хорошо, семантика нужна. Но не одна лишь она. Если ты скажешь что void ведет себя как IO, то одного лишь этого утверждения мне не будет достаточно что бы поверить в чистоту printf.
Re[79]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: AlexRK  
Дата: 07.11.19 09:06
Оценка:
Здравствуйте, samius, Вы писали:

S>В том-то и дело, что не так. вызов putStr не приведет к выводу на консоль. Я уже устал это повторять.

S>Хорошо, рассмотрим "QUERTY printf". Но если она испачкает консоль (или файл, ...) между моментом передачи ей управления и моментом возврата управления, то, боюсь, чистоты мы не получим.
S>Не семантика определяет чистоту, а поведение функции.

Хорошо, копнем здесь, если ты не против. Поведение функции. Ты утверждаешь, что в функцию putStr управление передается и возвращается назад ДО фактического выполнения описанных внутри этой функции действий, а вот выполнение описанных в printf действий происходит МЕЖДУ получением и возвратом управления.

Вопрос: почему ты так считаешь? Как ты определяешь, в какой момент испачкана консоль?

Предполагаю такие варианты ответа (которые уже были):

1) Я вижу в исходном коде слово IO в одном месте (это значит, что функция возвращает action) и void в другом (это значит, что функция выполняется напрямую).
Возражение: трактовка синтаксиса исходного кода, в частности символов IO, void или QWERTY, определяется спецификацией языка. Нет никаких "абсолютных" понятий, означающих, что некоторый текст однозначно трактуем. Ключом к расшифровке текста является спецификация языка. Если она говорит, что слово QWERTY означает 100% чистую функцию (означает возврат action), то она чистая, а иначе она грязная.

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

Так что же такое "момент передачи управления" в функцию, чем он определяется? Семантикой языка? Если в спецификации С будет указано (предположим такой вариант, абстрагируясь от реальности), что все функции возвращают action ("void" идеологически превращается в "action<void>"), то все функции С станут чисты?

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

S>Конечно, не разделяю такое мнение. А согласно каким данным такое мнение считается общепринятым?

Мы можем в любой функции вызвать любую другую, никаких преград для этого нет. Это означает, что потенциально любая С-функция является грязной. Ты, вероятно, говоришь о "фактической" чистоте — сигнатура грязная, но функция по факту не дергает IO, значит, она чистая. Честно говоря, не очень понимаю, чем твой вариант полезен с практической точки зрения, ведь с таким подходом мы не можем ничего определенного сказать о функции, исходного кода которой у нас нет.
Re[80]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.11.19 10:21
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, samius, Вы писали:


S>>В том-то и дело, что не так. вызов putStr не приведет к выводу на консоль. Я уже устал это повторять.

S>>Хорошо, рассмотрим "QUERTY printf". Но если она испачкает консоль (или файл, ...) между моментом передачи ей управления и моментом возврата управления, то, боюсь, чистоты мы не получим.
S>>Не семантика определяет чистоту, а поведение функции.

ARK>Хорошо, копнем здесь, если ты не против. Поведение функции. Ты утверждаешь, что в функцию putStr управление передается и возвращается назад ДО фактического выполнения описанных внутри этой функции действий, а вот выполнение описанных в printf действий происходит МЕЖДУ получением и возвратом управления.


ARK>Вопрос: почему ты так считаешь? Как ты определяешь, в какой момент испачкана консоль?

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


ARK>Предполагаю такие варианты ответа (которые уже были):


ARK>1) Я вижу в исходном коде слово IO в одном месте (это значит, что функция возвращает action) и void в другом (это значит, что функция выполняется напрямую).

ARK>Возражение: трактовка синтаксиса исходного кода, в частности символов IO, void или QWERTY, определяется спецификацией языка. Нет никаких "абсолютных" понятий, означающих, что некоторый текст однозначно трактуем. Ключом к расшифровке текста является спецификация языка. Если она говорит, что слово QWERTY означает 100% чистую функцию (означает возврат action), то она чистая, а иначе она грязная.

Вопреки тому, что написано в документации (Write a string to the standard output device), ожидаемые мной действия от вызова putStr — создать экшн. И я не ожидаю от нее что она будет пачкать консоль в момент вызова. Т.е. судя по документации она грязная как раз. Но я продолжаю утверждать что она чиста.

ARK>2) Я могу запустить отладчик и посмотреть, что происходит.

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

ARK>Так что же такое "момент передачи управления" в функцию, чем он определяется? Семантикой языка? Если в спецификации С будет указано (предположим такой вариант, абстрагируясь от реальности), что все функции возвращают action ("void" идеологически превращается в "action<void>"), то все функции С станут чисты?

Конечно, нет. Не тип результата и не спецификация определяет наличие сайд эффекта, следовательно чистоты. Спецификации putStr написано что она грязная. И что?

S>>Конечно, не разделяю такое мнение. А согласно каким данным такое мнение считается общепринятым?


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

Потенциально любая функция Haskell является грязной, ведь она может залезть в бэкдор или FFI.
ARK>Ты, вероятно, говоришь о "фактической" чистоте — сигнатура грязная, но функция по факту не дергает IO, значит, она чистая.
Я так не говорю. Могут быть грязные функции, которые не дергают IO.
ARK>Честно говоря, не очень понимаю, чем твой вариант полезен с практической точки зрения, ведь с таким подходом мы не можем ничего определенного сказать о функции, исходного кода которой у нас нет.
А что полезного дает твой вариант, когда "фсе функции C чисты, см. мою спецификацию и мою трактовку"? Он полезнее по отношению к функциям, исходного кода которых у нас нет?

Что бы знать, можно ли что-то делать с функцией такого, что можно делать с чистыми, нужно знать, является ли она чистой. Хаскель не делает все функции чистыми по умолчанию. Но результат вызова putStr "11" можно (например) кэшировать и использовать многократно, как и результат другой чистой функции. Результат FFI обертки над GetTickCount кэшировать не получится. И дело тут не в спецификации хаскеля.
Re[81]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: AlexRK  
Дата: 07.11.19 11:14
Оценка:
Здравствуйте, samius, Вы писали:

ARK>>Вопрос: почему ты так считаешь? Как ты определяешь, в какой момент испачкана консоль?

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

Насколько мне известно, этого сделать ты не можешь. Возможно, я ошибаюсь или неправильно тебя понял. Можешь показать код? Вот здесь можно проверить: https://repl.it/@essic/Haskell-playground

S>Вопреки тому, что написано в документации (Write a string to the standard output device), ожидаемые мной действия от вызова putStr — создать экшн. И я не ожидаю от нее что она будет пачкать консоль в момент вызова. Т.е. судя по документации она грязная как раз. Но я продолжаю утверждать что она чиста.

S>Конечно, нет. Не тип результата и не спецификация определяет наличие сайд эффекта, следовательно чистоты. Спецификации putStr написано что она грязная. И что?

Хорошо. Значит, ни спецификация, ни сигнатура функции не определяют ее чистоту.

Тогда ЧТО определяет чистоту? У тебя есть функция X на хаскеле. Как понять, она чиста или нет?

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

Если ты лезешь в отладчик (предположим, он есть), то ЧТО ты ожидаешь увидеть? Ты запустил, ничего не происходит. Ждешь минуту, час, месяц, год, ничего не происходит (внутри функции в начале стоит таймаут на миллион лет). Или ты запустил, функция завершилась, визуально в консоли ты ничего не увидел. ЧТО ты ожидаешь получить, чтобы понять, чиста ли функция?

А если нет ни исходного кода, ни отладчика? Тогда уж точно никак не понять, чиста функция или нет?

S>Потенциально любая функция Haskell является грязной, ведь она может залезть в бэкдор или FFI.


ОК.

ARK>>Ты, вероятно, говоришь о "фактической" чистоте — сигнатура грязная, но функция по факту не дергает IO, значит, она чистая.

S>Я так не говорю. Могут быть грязные функции, которые не дергают IO.

Под "IO" я понимаю здесь не хаскелевые функции с IO, а ввод-вывод в широком смысле.

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

S>А что полезного дает твой вариант, когда "фсе функции C чисты, см. мою спецификацию и мою трактовку"? Он полезнее по отношению к функциям, исходного кода которых у нас нет?

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

S>Что бы знать, можно ли что-то делать с функцией такого, что можно делать с чистыми, нужно знать, является ли она чистой.


Вопрос только, как это узнать.

S>Но результат вызова putStr "11" можно (например) кэшировать и использовать многократно, как и результат другой чистой функции.


Можно сделать то же самое с printf — просто возьми указатель на эту функцию и получишь абсолютно то же самое. Получишь "действие", которое надо выполнить.
Re[82]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.11.19 12:29
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, samius, Вы писали:


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


ARK>Насколько мне известно, этого сделать ты не можешь. Возможно, я ошибаюсь или неправильно тебя понял. Можешь показать код? Вот здесь можно проверить: https://repl.it/@essic/Haskell-playground


main = do
    last [putStrLn "a", putStrLn "b"]


ARK>Хорошо. Значит, ни спецификация, ни сигнатура функции не определяют ее чистоту.

верно.

ARK>Тогда ЧТО определяет чистоту? У тебя есть функция X на хаскеле. Как понять, она чиста или нет?

Определение чистоты определяет чистоту.

ARK>Если ты лезешь в исходный код (предположим, он есть), то ЧТО ты там ищешь? Ты видишь внутри массу других функций, какой признак ты ищешь, чтобы понять, чиста функция или нет?

Нужно смотреть, есть ли вызов грязных функций. Причем, вызов, а не возврат "указателя" на них.

ARK>Если ты лезешь в отладчик (предположим, он есть), то ЧТО ты ожидаешь увидеть? Ты запустил, ничего не происходит. Ждешь минуту, час, месяц, год, ничего не происходит (внутри функции в начале стоит таймаут на миллион лет). Или ты запустил, функция завершилась, визуально в консоли ты ничего не увидел. ЧТО ты ожидаешь получить, чтобы понять, чиста ли функция?

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

ARK>А если нет ни исходного кода, ни отладчика? Тогда уж точно никак не понять, чиста функция или нет?

Можно поковыряться в двоичном коде. Но в общем случае — нет, не понять.

ARK>>>Ты, вероятно, говоришь о "фактической" чистоте — сигнатура грязная, но функция по факту не дергает IO, значит, она чистая.

S>>Я так не говорю. Могут быть грязные функции, которые не дергают IO.

ARK>Под "IO" я понимаю здесь не хаскелевые функции с IO, а ввод-вывод в широком смысле.

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

S>>А что полезного дает твой вариант, когда "фсе функции C чисты, см. мою спецификацию и мою трактовку"? Он полезнее по отношению к функциям, исходного кода которых у нас нет?


ARK>Он совершенно бесполезен. Приведен для иллюстрации абсурдности утверждения, что "в хаскеле все функции чистые". Но я понял, что ты так не считаешь.

Нет, не считаю.

S>>Что бы знать, можно ли что-то делать с функцией такого, что можно делать с чистыми, нужно знать, является ли она чистой.


ARK>Вопрос только, как это узнать.

Убедиться в выполнении определения.

S>>Но результат вызова putStr "11" можно (например) кэшировать и использовать многократно, как и результат другой чистой функции.


ARK>Можно сделать то же самое с printf — просто возьми указатель на эту функцию и получишь абсолютно то же самое. Получишь "действие", которое надо выполнить.

Да, функция C, возвращающая указатель на функцию printf будет чиста, если она кроме этого не делает ничего грязного сама, разумеется.
Re[83]: Мнение: объектно-ориентированное программирование —
От: AlexRK  
Дата: 07.11.19 12:49
Оценка:
Здравствуйте, samius, Вы писали:

ARK>>Если ты лезешь в исходный код (предположим, он есть), то ЧТО ты там ищешь? Ты видишь внутри массу других функций, какой признак ты ищешь, чтобы понять, чиста функция или нет?

S>Нужно смотреть, есть ли вызов грязных функций. Причем, вызов, а не возврат "указателя" на них.

А как ты поймешь, какие функции грязные?

S>Можно поковыряться в двоичном коде. Но в общем случае — нет, не понять.


ОК. Значит, в общем случае мы не можем понять, чиста функция или нет.

Полагаю, можно говорить о двух уровнях понимания чистоты: "реальная" (что происходит на самом деле) и "декларируемая" (через сигнатуру или спецификацию). Ясное дело, по факту они могут отличаться — задекларировав функцию чистой, мы можем дернуть изнутри unsafe функцию, и наоборот — задекларировав функцию грязной, мы можем внутри просто сложить 2+2.

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

В чем польза и смысл "реальной" чистоты, можешь пояснить? Ты же вроде ратуешь за смысл.

S>>>Но результат вызова putStr "11" можно (например) кэшировать и использовать многократно, как и результат другой чистой функции.

ARK>>Можно сделать то же самое с printf — просто возьми указатель на эту функцию и получишь абсолютно то же самое. Получишь "действие", которое надо выполнить.
S>Да, функция C, возвращающая указатель на функцию printf будет чиста, если она кроме этого не делает ничего грязного сама, разумеется.

Абстрагируйся и представь, что функция printf сама возвращает action. "Вызов" этой функции будет "printf" (без скобок), а вызов action, который она возвращает — "printf()". Все как в хаскеле.


UPD. Убрал неправильный вопрос, некорректно код прочитал.
Отредактировано 07.11.2019 12:51 AlexRK . Предыдущая версия .
Re[84]: Мнение: объектно-ориентированное программирование —
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.11.19 13:12
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, samius, Вы писали:


S>>Нужно смотреть, есть ли вызов грязных функций. Причем, вызов, а не возврат "указателя" на них.


ARK>А как ты поймешь, какие функции грязные?

Так же, как и с текущей.

S>>Можно поковыряться в двоичном коде. Но в общем случае — нет, не понять.


ARK>ОК. Значит, в общем случае мы не можем понять, чиста функция или нет.

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

ARK>Полагаю, можно говорить о двух уровнях понимания чистоты: "реальная" (что происходит на самом деле) и "декларируемая" (через сигнатуру или спецификацию). Ясное дело, по факту они могут отличаться — задекларировав функцию чистой, мы можем дернуть изнутри unsafe функцию, и наоборот — задекларировав функцию грязной, мы можем внутри просто сложить 2+2.

Декларация не значит ничего, как показала практика.

ARK>В чем польза декларируемой чистоты, я могу понять — мы можем рассуждать о свойствах программы, просто глядя на сигнатуры функций или в документацию, и строя код относительно предполагаемых инвариантов. При чтении кода мы можем обоснованно предполагать, что происходит. Компилятор также работает именно с декларируемой чистотой — оптимизирует код вокруг нее (реальной он в общем случае не знает).

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

ARK>В чем польза и смысл "реальной" чистоты, можешь пояснить? Ты же вроде ратуешь за смысл.

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

S>>Да, функция C, возвращающая указатель на функцию printf будет чиста, если она кроме этого не делает ничего грязного сама, разумеется.


ARK>Абстрагируйся и представь, что функция printf сама возвращает action. "Вызов" этой функции будет "printf" (без скобок), а вызов action, который она возвращает — "printf()". Все как в хаскеле.

Допустим. Но если main вызывает printf со скобками, то она и выполняет этот action.


ARK>UPD. Убрал неправильный вопрос, некорректно код прочитал.

С формальной чистотой putStr(Ln) вопрос закрыт?
Re[85]: Мнение: объектно-ориентированное программирование —
От: AlexRK  
Дата: 07.11.19 13:41
Оценка:
Здравствуйте, samius, Вы писали:

S>>>Нужно смотреть, есть ли вызов грязных функций. Причем, вызов, а не возврат "указателя" на них.

ARK>>А как ты поймешь, какие функции грязные?
S>Так же, как и с текущей.

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

ARK>>Полагаю, можно говорить о двух уровнях понимания чистоты: "реальная" (что происходит на самом деле) и "декларируемая" (через сигнатуру или спецификацию). Ясное дело, по факту они могут отличаться — задекларировав функцию чистой, мы можем дернуть изнутри unsafe функцию, и наоборот — задекларировав функцию грязной, мы можем внутри просто сложить 2+2.

S>Декларация не значит ничего, как показала практика.

Почему, значит. То, что ее можно нарушить — не значит, что она бесполезна. Чем полезна, я уже писал: "мы можем рассуждать о свойствах программы, просто глядя на сигнатуры функций или в документацию, и строя код относительно предполагаемых инвариантов. При чтении кода мы можем обоснованно предполагать, что происходит". Это гораздо лучше, чем ничего, когда у тебя нет исходников.

ARK>>В чем польза декларируемой чистоты, я могу понять — мы можем рассуждать о свойствах программы, просто глядя на сигнатуры функций или в документацию, и строя код относительно предполагаемых инвариантов. При чтении кода мы можем обоснованно предполагать, что происходит. Компилятор также работает именно с декларируемой чистотой — оптимизирует код вокруг нее (реальной он в общем случае не знает).

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

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

ARK>>В чем польза и смысл "реальной" чистоты, можешь пояснить? Ты же вроде ратуешь за смысл.

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

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

ARK>>Абстрагируйся и представь, что функция printf сама возвращает action. "Вызов" этой функции будет "printf" (без скобок), а вызов action, который она возвращает — "printf()". Все как в хаскеле.

S>Допустим. Но если main вызывает printf со скобками, то она и выполняет этот action.

Да, main будет грязная. А printf чистая. Верно?

ARK>>UPD. Убрал неправильный вопрос, некорректно код прочитал.

S>С формальной чистотой putStr(Ln) вопрос закрыт?

Нет, не закрыт. Я точно такой же код могу написать и для printf. Присвою указатель на printf в переменную и не буду вызывать его. Функция printf "чиста".
Re[83]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: Mamut Швеция http://dmitriid.com
Дата: 07.11.19 14:05
Оценка:
S>>>Например, я могу создать экшн с помощью вызова putStr, но не встроить результат вызова в main цепочку. Вызов будет, а консоль останется нетронутой этим экшном.

ARK>>Насколько мне известно, этого сделать ты не можешь. Возможно, я ошибаюсь или неправильно тебя понял. Можешь показать код? Вот здесь можно проверить: https://repl.it/@essic/Haskell-playground


S>
S>main = do
S>    last ( [putStrLn "a", putStrLn "b"]
S>


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


dmitriid.comGitHubLinkedIn
Re[84]: Мнение: объектно-ориентированное программирование — катастрофа на трилли
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.11.19 17:42
Оценка:
Здравствуйте, Mamut, Вы писали:

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


ARK>>>Насколько мне известно, этого сделать ты не можешь. Возможно, я ошибаюсь или неправильно тебя понял. Можешь показать код? Вот здесь можно проверить: https://repl.it/@essic/Haskell-playground


S>>
S>>main = do
S>>    last ( [putStrLn "a", putStrLn "b"]
S>>


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

Верно, он ленивый.

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

import System.IO
import System.IO.Unsafe

test :: [Char]
test = unsafePerformIO $! do
    putStrLn "<test>"
    return "test result"

a1 = putStrLn $! test

main = do
    last $! [a1, putStrLn "b"]


В любом случае, никакой грязи от выполнения putStr до подачи в его результирующий action RealWorld значения, литься не должно.
Re[86]: Мнение: объектно-ориентированное программирование —
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.11.19 17:48
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, samius, Вы писали:


S>>Так же, как и с текущей.


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

Включу чуйку.

S>>Декларация не значит ничего, как показала практика.


ARK>Почему, значит. То, что ее можно нарушить — не значит, что она бесполезна. Чем полезна, я уже писал: "мы можем рассуждать о свойствах программы, просто глядя на сигнатуры функций или в документацию, и строя код относительно предполагаемых инвариантов. При чтении кода мы можем обоснованно предполагать, что происходит". Это гораздо лучше, чем ничего, когда у тебя нет исходников.

Лучше, чем ничего. Но не истина в последней инстанции.

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


ARK>Компилятор располагает только компилируемыми в данный момент исходниками. Если надо скомпилировать код, ссылающийся на функцию, определенную в бинарном файле, то компилятор в пролете.

Если в бинарном файле нет разметки о чистоте — то в пролете.

ARK>Мы можем все то же самое сделать и с декларируемой чистотой. При этом мы не ограничены наличием исходников. И нам никак не помешает случай, когда декларированно-грязная является по факту чистой. Единственный потенциально неприятный случай — когда грязная функция объявляет себя чистой, но здесь те же проблемы, что и в случае с unsafe — если делаешь так, то на свой страх и риск.

Действительно.

S>>Допустим. Но если main вызывает printf со скобками, то она и выполняет этот action.


ARK>Да, main будет грязная. А printf чистая. Верно?

Верно.

S>>С формальной чистотой putStr(Ln) вопрос закрыт?


ARK>Нет, не закрыт. Я точно такой же код могу написать и для printf. Присвою указатель на printf в переменную и не буду вызывать его. Функция printf "чиста".

Допустим, что мы определили функцию-константу, всегда возвращающую указатель на грязный printf. Новая функция чиста. Но старый printf не стал чище от этого.
Re[87]: Мнение: объектно-ориентированное программирование —
От: AlexRK  
Дата: 07.11.19 18:03
Оценка:
Здравствуйте, samius, Вы писали:

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

S>Включу чуйку.

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

ARK>>Нет, не закрыт. Я точно такой же код могу написать и для printf. Присвою указатель на printf в переменную и не буду вызывать его. Функция printf "чиста".

S>Допустим, что мы определили функцию-константу, всегда возвращающую указатель на грязный printf. Новая функция чиста. Но старый printf не стал чище от этого.

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

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

Не уверен, что есть большой смысл в таком подходе, но ведь это то, что делает хаскель — зачем он это делает, я до сих пор понять не могу.
Re[88]: Мнение: объектно-ориентированное программирование —
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.11.19 18:17
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, samius, Вы писали:


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

S>>Включу чуйку.

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

ARK>По запуску — тоже.
ARK>То есть ее вообще никак определить нельзя. Тогда какой с нее толк? Компилятор как-то поймет? Ну ОК, иногда поймет. А программисту с такого понятия чистоты толку ноль.
Либо на доверии. Вот для того и придумали отделять грязь от чистоты на уровне типов, что бы разметка чистоты торчала из каждой функции. Конечно, возможность сунуть грязь в любую чистую (по разметке) функцию, ломает всю прелесть разметки. Но при определенном доверии к источнику можно даже документацию не смотреть.

ARK>>>Нет, не закрыт. Я точно такой же код могу написать и для printf. Присвою указатель на printf в переменную и не буду вызывать его. Функция printf "чиста".

S>>Допустим, что мы определили функцию-константу, всегда возвращающую указатель на грязный printf. Новая функция чиста. Но старый printf не стал чище от этого.

ARK>Мы можем смотреть на сам старый printf как на функцию, которая возвращает action. Ситуация совершенно аналогична с IO-функциями хаскеля с точностью до небольших различий в синтаксисе.

смотреть можем. Но printf со скобками приведет к появлению мгновенной грязи, как и до этого. А использовать указатель, не называя его функцией, и так никто не запрещал. Чего добились — непонятно.

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

main из кода никто не зовет. Ну и потом, кто-то же должен "вызывать" скобки у указателя на printf. Вот тот метод сразу станет грязным.

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

Немного не то, но похоже. А делает он это ровно для того, что бы затаскивать ввод-вывод в любую функцию было бы неудобно, что бы весь ввод-вывод байндился бы в одном месте. Иначе lazy с неконтролируемым вводом-выводам выбесит любого программиста. Как я понимаю, именно ленивость плохосовместима с IO в неожиданных местах.
Re[89]: Мнение: объектно-ориентированное программирование —
От: AlexRK  
Дата: 07.11.19 19:17
Оценка:
Здравствуйте, samius, Вы писали:

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

ARK>>По запуску — тоже.
ARK>>То есть ее вообще никак определить нельзя. Тогда какой с нее толк? Компилятор как-то поймет? Ну ОК, иногда поймет. А программисту с такого понятия чистоты толку ноль.
S>Либо на доверии. Вот для того и придумали отделять грязь от чистоты на уровне типов, что бы разметка чистоты торчала из каждой функции. Конечно, возможность сунуть грязь в любую чистую (по разметке) функцию, ломает всю прелесть разметки. Но при определенном доверии к источнику можно даже документацию не смотреть.

То есть мы таки плавно возвращаемся назад к "декларируемой" чистоте, а не "реальной". А декларируемая чистота от чего зависит — от сигнатуры функции и, как следствие, от спецификации языка, верно?

ARK>>Мы можем смотреть на сам старый printf как на функцию, которая возвращает action. Ситуация совершенно аналогична с IO-функциями хаскеля с точностью до небольших различий в синтаксисе.

S>смотреть можем. Но printf со скобками приведет к появлению мгновенной грязи, как и до этого. А использовать указатель, не называя его функцией, и так никто не запрещал. Чего добились — непонятно.
S>main из кода никто не зовет. Ну и потом, кто-то же должен "вызывать" скобки у указателя на printf. Вот тот метод сразу станет грязным.

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

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

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

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

Ну... Я бы сказал, не просто похоже, а вообще то же самое. А чтобы запретить затаскивать ИО куда попало, есть и более простые способы — скажем, явное деление на чистые и грязные функции. Впрочем, если я правильно понял, ты вроде бы сейчас согласен с тем, что в хаскеле есть грязные функции? Помеченные как IO — это "декларируемо грязные", а еще есть "реально грязные", но их мы никак опознать не можем. Но мы знаем, что они есть. Правда для нас толку с этого знания нет. Так?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.