Парадокс Рассела для операций, автогенерация кода
sergey shishkinМодели информации и данных. Атом и универсум информации
Обсуждение автогенерации кода начнем с описания парадокса Рассела, хорошо известного в теории множеств: пусть К – множество всех множеств, которые не содержат себя в качестве своего элемента. Содержит ли К само себя в качестве элемента? Обычно этот парадокс иллюстрируется несколькими, насколько занимательными, настолько и абсурдными задачами:
Парадокс брадобрея: деревенскому брадобрею приказали брить всякого, кто не бреется сам и не брить того, кто бреется сам. Может ли брадобрей брить самого себя?
Парадокс мэра: в стране вышел указ о том, что мэры городов должны жить не в своем городе, а в специальном городе мэров. Может ли мэр города мэров жить в городе мэров?
Парадокс Рассела сам по себе неразрешим из-за самой постановки задачи, поскольку он ссылается на множество всех не включающих себя множеств, то есть в задачах противоречие задаётся аксиоматически, в самом определении. Чтобы свести математический взгляд на вещи к естественному, и если хотите, к бытовому понимаю, сравним этот парадокс с парадоксом всемогущества: попросите всемогущего сделать камень, который он не сможет поднять. Если получится, значит его всемогущество утратило силу, а если нет – то он и не был всемогущ.
Аналогичный парадокс, связанный с модификацией программного кода, возникает в задачах искусственного интеллекта. А именно, может ли программный код модифицировать и выстраивать сам себя? Или в другой интерпретации: может ли программный код строить другой программный код, не содержащий сам себя?
Как же соотносятся множества из парадокса Рассела и генерируемый программный код? На элементарном уровне код состоит из команд и операций. Их стройная последовательность и является кодом, который требуется получить. Но на уровне постановки задачи генерации никакого программного кода еще нет, это обобщенная информация или мета-информация о том, каким должен быть генерируемый код. Это и есть множество (задач), не содержащее другое множество (команд). Задача – это поручение процессору выполнить определенную команду. Получается, что, создавая программу, и записывая её в память мы даем поручение процессору выполнить определенный набор команд. Когда же процессор идет по этой последовательности команд, он рассматривает каждую из них в текущем контексте выполнения (регистры, состояние памяти и пр.). Понятие множества, не содержащего само себя – это фактически мета-информация (задачи) о мета-информации (командах), в которой не содержатся задачи более низкого уровня, то есть представления задач с более детализированным видом, хотя формально этот более абстрактный вид мета-информации остается мета-информацией. Подробнее представление мета-информации будет рассмотрено ниже.
Разумеется, парадокс Рассела не является краеугольным камнем для возможности генерации кода. В нашем случае, наоборот, мы понимаем, что одна программа может сформировать программный код (об этом ниже), и сама программа – это код. Так может ли идти речь о воспроизведении кода как об аналоге всемогущества?
Среди идей искусственного интеллекта существует идея самомодифицирующихся программ. На практике обычно программы не модифицируют себя сами. Есть ограниченный класс программ, которые изменяют свой код, такие как системы безопасности и их антагонисты – вирусы. С помощью механизма самомодификации программы обычно пытаются защититься от их распознавания. Идея самомодификации искусственного интеллекта состоит в самовоспроизведении кода, подобно рельсоукладчику на железной дороге, который кладет рельсы, а затем и едет по ним же.
В связи с тем, что самомодифицирующиеся программы, за исключением специфических, указанных выше программ, сейчас фактически не встречаются, поднятый мной вопрос на основе парадокса Рассела не так уж наивен для сегодняшнего уровня развития информационных систем.
Существует вид программирования, основной задачей которого является генерация программного кода путем самомодификации либо путем создания новой программы. Такой вид программирования называется мета-программированием.
Мета-программирование, собственно, предлагает два варианта – это шаблоны и внеязыковые средства, такие как синтаксические и лексические анализаторы. Полиморфизм объекто-ориентированного подхода программирования также предлагается как один из инструментов мета-программирования. Частным случаем мета-программы является «квайн» (quine): программа, которая выдает на выходе точную копию своего исходного текста. Тем не менее, какие бы технологии программирования мы не перечисляли, созданием программ в мета-программировании занимаются люди, а подходы призваны лишь упрощать написание кода.
Что же формирует код или, говоря простым языком, заставляет программы исполняться? Крупным классом программ, порождающим программный код, являются компиляторы. Противоположностью генерации низкоуровневого исполняемого кода является исполнение кода высокого уровня при помощи программ-интерпретаторов, которые на ходу анализируют исходный код и исполняют инструкции программ. Существует и компромиссный вариант между компиляцией и интерпретацией программ. Это технологии, осуществляющие трансляцию исходного программного кода в байт-код или в p-код (пи-код). Байт-код является более низкоуровневым, p-код – в большей степени высокоуровневым. Внутри исполнимого модуля эти виды кода исполняются интерпретатором.
Существенным отличием интерпретаторов и p-кода от компилированного кода состоит в том, что, используя механизмы интерпретации, система «на ходу» может выполнять скрипты на том же языке программирования.
В качестве альтернативы внешние программные коды также могут встраиваться в систему. Например, Microsoft предлагает собственный SDK, основанный на Visual Basic for Applications (VBA), подобно тому, как VBA существует в офисных продуктах Microsoft – MS Word, MS Excel и пр.
Подводя итог, подчеркнем, что, учитывая разнообразие существующих методов исполнения кода, выбор той или иной программной архитектуры системы важен, поскольку интеллектуальная система должна уметь формировать и модифицировать порядок и правила выполнения задач.
Однако при автоматическом создании кода мы неизменно столкнемся с типичными проблемами, связанными с корректностью кода. Согласно статистики, в среднем 60% времени по разработке программного обеспечения тратится не на программирование, а на отладку и тестирование кода. Если человек сталкивается с подобными проблемами, то с ними столкнется и автоматическая система динамической генерации кода. То есть либо код должен быть лишен ошибок (что, очевидно, невозможно), либо ошибки при исполнении кода должны порождать исключения, которые в свою очередь должны возвращать исполнимый код на уровень регенерации кода. Коррекцию или регенерацию можно сравнить с проведением эксперимента, а последовательную отладку программы – с методом проб и ошибок.
Также как программист пишет код с точки зрения собственных представлений или теории, при отладке и тестировании этого кода и при возникновении логической ошибки или некорректных результатов программа с отладочной средой указывают, что теория программиста была не идеальной. Последовательными итерациями программист корректирует код, доводя его до совершенства.