Category: it

Category was added automatically. Read all entries about "it".

Информация о списке внутри списка

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

Что-де «а как же можно в множество сложить что-то там, что приобретает определённость только после построения этого множества?».

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

Однако мне, как программисту со стажем, сама постановка вопроса «как можно?» в те времена, когда этим постоянно пользуются для написания программ, кажется абсурдной. Это всё равно, как если бы кто-то в 2021-м начал риторически вопрошать: «да осмысленна ли вообще идея летательных аппаратов тяжелее воздуха?!». Эй, алё, уже немножечко поздно сомневаться в возможности такового.

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

Collapse )

Тенденция к локальным контекстам

Я ещё помню те времена, когда мощным современным языком считался чистый C, где, в частности, существовали заголовочные файлы.

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

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

Но особенно наглядной кривота этого способа стала тогда, когда допилился современный объектный мэйнстрим, к которому потом присовокупилось ещё и функциональное программирование в версии «для психически здорового человека».

Да, реализацию гораздо проще подменить виртуальным наследованием или ссылкой на функции: не надо завязываться на файлы и, что немаловажно, в рамках одной системы можно иметь сразу несколько реализаций одновременно. Причём использовать их не только в одном файле, а даже и в одной функции или в одном контейнере.

Collapse )

Проверка диапазона во время компиляции

В Scala 3, с одной стороны, можно завести тип, имя которого — просто некоторое число, с другой стороны, можно делать вычисления с типами, а с третьей стороны можно объединять типы через логическое «или».

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

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

Такая переменная будет прекрасно подходить к соответствующей функции.

type LessBuilder = [T <: Int, Acc] =>> T match
 case 1 => 1 | Acc
 case _ => LessBuilder[T - 1, T | Acc]

type UpTo[T <: Int] = LessBuilder[T - 1, T]

def f(x: UpTo[5]) = x + 1

println(f(3))
println(f(9)) // Ошибка компиляции

val x: UpTo[5] = 4
println(f(x))


Правда, расшифровка типа UpTo[5] получается прямо вообще офигенная.

(1 : Int) | ((5 : Int) - (1 : Int) - (1 : Int) - (1 : Int) | ((5 : Int) - (1 : Int) - (1 : Int) | ((5 : Int) - (1 : Int) | (5 : Int))))

Но, блин, работает.

Не знаю, зачем это нужно, но вдруг.



doc-файл

О разработке магических языков

Смысл программ на Scala состоит в том, чтобы придумать и описать где-то так семь слов, при помощи которых вы сможете сказать всё по выбранной вами теме. После этого начинается скучная, но, благо, короткая часть, когда вы говорите всё по этой теме в десяти строках.

Минус этого подхода в том, что единственным в мире знатоком этого семисловного языка являетесь исключительно вы сами, поэтому никто не понимает, что вы там по этой теме сказали.

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

Нововведения Scala 3 позволяют сократить локальный магический язык с где-то так семи слов до где-то так четырёх, поэтому колдовать на тайных языках для посвящённых гипотетически смогут даже высшие обезьяны. Если, конечно, их удастся какому-то из них научить.




doc-файл

Как привнеси в Scala немножко Wolfram

В приложении к предыдущей статье я задумался, а сколько вообще надо дописать к Scala, чтобы разобранная в статье конструкция работала и там тоже. То есть, чтобы код вида

x \\ f \\ g


превращался в код

g(f(x))


Причём желательно без создания промежуточных объектов, то есть чтобы в плане производительности это бы ничего не стоило.

Знаете сколько для этого надо написать?

Collapse )




А потом…

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

Суть проблемы вот в чём. Есть у вас, предположим, набор функций, которые — для простоты — принимают число и возвращают число. В результате, вы можете взять число и последовательно применить эти функции «по цепочке» — то есть каждую следующую к результату выполнения предыдущей, составляя, таким образом, самые разные последовательности вычислений и преобразований.

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

Причём для длинной цепочки оба «стандартных» варианта выглядят очень так себе.

В варианте…

Collapse )

Чистое лицемерие

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

Однако, стоит вам произнести «функциональная парадигма», как тут же обнаружится какой-то теоретик программирования, слышавший это словосочетание, который обязательно добавит что-то типа: «так несчитово — в настоящем функциональном программировании ещё и все значения неизменяемые». Эти ваши Си-шарпы и Скалы, таким образом, для быдла. В крайнем случае, если вы уж не засели за честный Хаскель, то хотя бы пишите «честно»: никогда не используйте изменяемые значения.

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

В сферическом вакууме кто-то наверно уже написал, например, движок GUI, который одновременно невырвиглазный, удобный в использовании и «чисто функциональный», однако в физической реальности таких нет. И скорее всего не будет — по крайней мере, до тех пор, пока не будут придуманы такие же удачные абстракции, какие придуманы для ссылок на функции.

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

Collapse )

О точности математиков

Есть такое распространённое мнение, что «математики запредельно точны в своих рассуждениях — не то, что физики, инженеры или биологи».

При этом я, как программист-математик, не устаю поражаться тому, сколь математики-непрограммисты не точны и сколь расплывчаты многие их рассуждения.

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

Не менее круто развиты и двойные стандарты, применяемые почти на автомате. Например, весьма нередко встречаются рассуждения вроде:

  1. Возьмём в качестве текущего результата число 1.


  2. Применим к текущему результату функцию f.


  3. Применим к текущему результату функцию g.


  4. Будем повторять 2 и 3 бесконечно много раз.


  5. Финальным результатом будет что-то, что выдала функция f в этот момент.


Collapse )

Икс не равен самому себе

Что-то давно не было про диалектику. И про программирование. Сейчас я экстренно наверстаю.

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

«Я равен самому себе — а иначе как же меня друзья-то опознают? Однако я не равен самому себе, поскольку не влезаю в те штанишки, которые носил в десять лет. Шах и мат, формальнологисты!».

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

Тем не менее, я готов поделиться с общественностью ещё более крышесносящим примером — прямо сразу на формальнологическом языке программирования Java.

Collapse )

Понятно, почему почти никому не понятно

Теоремы Гёделя очень любят всевозможные эзотерики, мистики, верующие, диалектики и т.п. Причём большинство из них трактует оные в стиле «Гёдель доказал, что в мире всё очень сложно и непознаваемо», к чему добавляется что-то, приятное данному гражданину, но никак не следующее ни из теорем Гёделя, ни из непознаваемости чего-то там.

Как-то раз я собрался с силами и прочитал четыре книги/длинные статьи о теореме Гёделя, а также посмотрел три отечественные лекции по ней и одну зарубежную.

С тех пор я понимаю, почему её почти никто не понимает: вместо современных знаний и современной же терминологии, опирающейся на нехило так отработанный за три четверти века опыт реального программирования, во всех изложениях — косплей начала двадцатого века.

Всё подаётся так, будто бы компьютеры, как и тогда, всё ещё только в мечтах, способы записи — сплошняком о чём-то гипотетическом, а реализация всем сейчас очевидного, коя у самого Гёделя составляет примерно 90% текста, — самое главное, о чём надо поведать современным студентам, хотя с тех пор уже было наверно за полсотни итераций гораздо более удачных вариантов записи того же самого.

В общем, всё так, как если бы кто-то сейчас попытался преподавать механику в терминологии Ньютона, причём с обильными цитатами на латыни из «первоисточников», без которых «весь смысл ускользнёт».

Collapse )