sab123: (face)
SB ([personal profile] sab123) wrote2016-03-04 01:35 am

про систему записи

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

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

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

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

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

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

[identity profile] amarao-san.livejournal.com 2016-03-08 08:13 am (UTC)(link)
> Строгая типизация существует уже давно, как и алгольно-паскльное различение процедур и функций, с обязательным требованием что-то сделать со значением, возвращаемым функцией.

Нет. Если функция может вернуть три состояния: None, value и Error, то если мы пишем

foo = function(), то компилятор никак не может проверить, что мы действительно сказали, что делать, если foo будет None или Error. Эксепшены чуть лучше, чем -1 из функции, т.к. хотя бы роняют программу, а не кормят этот -1 дальше по коду, но это runtime checking. Добротный язык должен проверить, что у меня в языке написано что делать с None, что делать с Error и что делать с value. А если value - перечисляемый тип, то ещё и проверить, что все значения value покрыты.

Монадки - как раз и есть такие "конвееры", позволяющие завернуть значение в "коробочку" с доп.обработкой. Так, чтобы функция, обрабатывающая реальное значение, не парилась (и никогда в жизни не столкнулась) с прилагающимися к обработке None и Error.

А вот про break/continue не надо, пожалуйста. Я не видел ни одного компилятора сишнопаскального вида, который бы мог сказать "чувак, твои break/continue не покрывают все случаи возвращаемых значений". Есть миллиард статических чекеров, которые это дело расширяют, но сам язык не подразумевает достаточно выразительной семантики, чтобы объяснить, какие там могут быть значения.

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

[identity profile] sab123.livejournal.com 2016-03-08 09:23 pm (UTC)(link)
Так ить нормальные функции не кормят ошибку дальше по коду, а сразу возвращают ее наружу. Потребность в кормлении - от функционального программирования, которое не может сразу вернуть.

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

> А вот про break/continue не надо, пожалуйста. Я не видел ни одного компилятора сишнопаскального вида, который бы мог сказать "чувак, твои break/continue не покрывают все случаи возвращаемых значений".

Мне несколько непонятно, что имеется в виду под "покрывать". У break/continue нет потребности возвращать какие-то значения, которые будут обрабатываться ("покрываться") где-то далеко. Они обрабатывают особые ситуации сразу на месте. Поэтому "не покрыть" с ними что-то - невозможно.

> Чистый код - нужен и важен. Если у тебя функция считает sha512 от блока, зачем ей внешний мир?

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

[identity profile] amarao-san.livejournal.com 2016-03-09 10:44 am (UTC)(link)
Наружу - это куда? Вот у нас есть функция чтения данных из БД. И есть функция, которая вычисляет что-то по данным из БД.

Из БД может быть прочитано value|none|error. Функция умеет делать сложную математику, но мы хотим, чтобы она возвращала что-то осмысленное даже если там error или none. Мы можем написать пачку if'ов, чтобы на всех уровнях стека каждый раз писать if status==error ... if value == none..., а можем завернуть разумные функции (которые работают только с данными) в монадки, которые добавят адекватную обработку error/none случаев, и если мы в финале (на верхнем уровне) не обработаем все варианты (допустим, в стеке в какой-то момент у нас получилось уже error|invalid|outdatated|none|value), то программа просто не скомпилируется.

А вот сишный код, который if'ами утыкан, просто молча "сделает не то", обнаружив на месте value invalid|outdated, о котором в одном месте программы подумали, а во втором забыли.

[identity profile] sab123.livejournal.com 2016-03-09 08:43 pm (UTC)(link)
Сишный код получит ошибку от функции чтения данных и просто НЕ ВЫЗОВЕТ функцию обработки данных. Поэтому функции обработки данных не надо вообще ничего знать об ошибках чтения. Ну, естественно, кроме случая, когда чтение идет по мере обработке.

[identity profile] amarao-san.livejournal.com 2016-03-09 09:51 pm (UTC)(link)
Таким образом, если нам всё-таки НУЖНО вызвать функцию обработки данных (например, поскольку запрос в базу минорный и не особо влияет на результат), то мы вернём ошибку и расслабимся.

Либо, напишем (псевдокодом):

compound_reply = compose (important_data, SPECIAL_CODE_TO_SAY_NO_DATA_HERE, important_data).
return compound_reply

И в compose мы эту обработку сделаем. И в ответе по стеку выше (куды compound_reply уйдёт) тоже напишем наш if'ик, так?

[identity profile] sab123.livejournal.com 2016-03-10 08:40 pm (UTC)(link)
Если данные сначала целиком читаются, а потом целиком обрабатываются, то нет, функцию обработки данных вызывать не нужно.

Нужно только если одна и та же функция занимается и чтением и обработкой: прочитали один кусочек, обработали, прочитали еще кусочек, обработали. И вот тут break/continue/return позволяют при ошибке легко плюнуть на все оставшиеся кусочки.