Что означает "Данные - это просто тупой код, а код - просто умные данные"?
Я только что натолкнулся на идею в "Структуре и интерпретации компьютерных программ":
Данные - это просто тупой код, а код - просто умные данные
Я не понимаю, что это значит. Может ли кто-нибудь помочь мне лучше понять это?
5 ответов
Это один из фундаментальных уроков SICP и одна из самых мощных идей информатики. Это работает так:
То, что мы называем "кодом", на самом деле не способно что-либо сделать само по себе. Код определяет программу только в контексте интерпретации - вне этого контекста это просто поток символов. (На самом деле это поток битов, который на самом деле представляет собой поток электрических импульсов. Но давайте сделаем это простым.) Значение кода определяется системой, в которой вы его выполняете, - и эта система просто обрабатывает ваш код как данные, которые сообщают это то, что ты хотел сделать. Исходный код C интерпретируется компилятором C как данные, описывающие объектный файл, который вы хотите создать. Объектный файл обрабатывается загрузчиком как данные, описывающие некоторые машинные инструкции, которые вы хотите поставить в очередь для выполнения. Машинные инструкции интерпретируются ЦП как данные, определяющие последовательность переходов состояний, которым он должен подвергаться.
Интерпретируемые языки часто содержат механизмы для обработки данных как кода, что означает, что вы можете передать код в функцию в некоторой форме и затем выполнить ее - или даже сгенерировать код во время выполнения:
#!/usr/bin/perl
# Note that the above line explicitly defines the interpretive context for the
# rest of this file. Without the context of a Perl interpreter, this script
# doesn't do anything.
sub foo {
my ($expression) = @_;
# $expression is just a string that happens to be valid Perl
print "$expression = " . eval("$expression") . "\n";
}
foo("1 + 1 + 2 + 3 + 5 + 8"); # sum of first six Fibonacci numbers
foo(join(' + ', map { $_ * $_ } (1..10))); # sum of first ten squares
В некоторых языках, таких как схема, есть понятие "первоклассные функции", что означает, что вы можете рассматривать функцию как данные и передавать ее, не оценивая ее, пока не захотите.
В результате разделение между "кодом" и "данными" в значительной степени произвольно, является функцией только перспективы. Чем ниже уровень абстракции, тем "умнее" должен быть код: он должен содержать больше информации о том, как он должен выполняться. С другой стороны, чем больше информации предоставляет интерпретатор, тем более глупым может быть код, пока он не начнет выглядеть как данные без всяких умов.
Один из самых мощных способов написания кода - это простое описание того, что вам нужно: данные, которые будут превращены в код, описывающий, как получить то, что вам нужно, в контексте интерпретации. Мы называем это "декларативным программированием".
Для конкретного примера рассмотрим HTML. HTML не описывает полный по Тьюрингу язык программирования. Это просто структурированные данные. Его структура содержит некоторые смарты, которые позволяют ему контролировать поведение своего интерпретирующего контекста - но не так много смартов. С другой стороны, он содержит больше умных текстов, чем текстовые абзацы, которые появляются на средней веб-странице: это довольно глупые данные.
В контексте безопасности: из-за переполнения буфера то, что вы рассматриваете как данные и, таким образом, безвредно (например, изображение), может быть выполнено как код и загрузить вашу машину.
В контексте разработки программного обеспечения: Многие разработчики очень боятся "жестко кодировать" вещи и очень заинтересованы в извлечении параметров, которые, возможно, придется изменить в конфигурационные файлы. Часто это основано на идее, что файлы конфигурации являются просто "данными" и, следовательно, могут быть легко изменены (разразившимися клиентами), не затрагивая проблем (компиляция, развертывание, тестирование), которые могли бы изменить что-либо в коде.
Эти разработчики не понимают, что, поскольку эти "данные" влияют на поведение программы, это действительно код; это может сломать программу, и единственная причина, по которой не требуется полное тестирование после такого изменения, заключается в том, что, если все сделано правильно, настраиваемые значения имеют очень специфический, хорошо задокументированный эффект, и любое недопустимое значение или поврежденная файловая структура будут обнаружены программа.
Однако часто случается так, что структура файла конфигурации становится самостоятельным языком программирования, включающим поток управления и все остальное - плохо документированное, с причудливым синтаксисом и синтаксическим анализатором, которое используют только самые опытные разработчики в команде. можно потрогать, не нарушая приложение полностью.
Это то, что вы должны понять, написав в компиляторе.
Одним из распространенных шагов в компиляторах является преобразование программы в абстрактное синтаксическое дерево. Представление часто будет похоже на деревья, такие как [+, 2, 3], где + - корень, а 2, 3 - дочерние.
Языки Лисп просто воспринимают это как свои данные. Таким образом, нет разделения между данными и кодом, которые представляют собой списки, похожие на деревья AST.
Таким образом, в языке, подобном Scheme, даже код обрабатывается как данные первого класса. Вы можете относиться к функциям и лямбда-выражениям так же, как к другому коду, например, передавая их в другие функции и лямбда-выражения. Я рекомендую продолжить с текстом, так как все это станет совершенно ясно.
Код определенно является данными, но данные определенно не всегда являются кодом. Давайте рассмотрим базовый пример - имя клиента. Это не имеет ничего общего с кодом, это функциональный (существенный), а не технический (случайный) аспект приложения.
Вы могли бы, вероятно, сказать, что любые технические / случайные данные являются кодом, а функциональные / важные данные - нет.