Category: it

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

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

Я ещё помню те времена, когда мощным современным языком считался чистый 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 )

Сделай сам себе язык

Для тех немногих сильных духом, кто заинтересовался «псевдо-макросами» в приложении к матмоделям, запилил статью с гораздо более подробными разъяснениями и всевозможной философией по этой теме.



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

Аналогичное заодно является основой символьных вычислений, в том числе — построения систем, которые могут, например, решать уравнения или выводить производные в символьной форме.

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


Читать на сайте «XX2 век»