Как мне управлять побочными эффектами в новом дизайне языка? - PullRequest
6 голосов
/ 29 апреля 2009

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

Однако то, что является побочным эффектом, не совсем ясно. Я ищу любые мысли или предложения по этому вопросу, которые я мог бы рассмотреть на моем языке. Вот мои нынешние мысли.

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

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

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

  • Чтобы помочь в разделении проблем. (Ни один модуль не может сделать все).
  • Для песочницы каждого модуля в приложении. (Любой модуль может быть использован в качестве плагина)

Имея это в виду, как мне обращаться с "псевдо" побочными эффектами, такими как случайные числа и сон, как я упоминал выше? Что еще я мог пропустить? Каким образом я могу управлять использованием памяти и временем как ресурсами?

Ответы [ 4 ]

4 голосов
/ 30 апреля 2009

Проблема описания и управления эффектами в настоящее время занимает одну из лучших научных областей в языках программирования, включая таких людей, как Грег Моррисетт из Гарвардского университета. Насколько мне известно, наиболее амбициозная новаторская работа в этой области была проделана Дэвидом Гиффордом и Пьером Жувело на языке программирования FX, начатом в 1987 году. Определение языка доступно в Интернете, но вы можете лучше понять идеи прочитав их 1991 POPL бумагу .

2 голосов
/ 05 мая 2009

Это действительно интересный вопрос, и он представляет собой один из этапов, которые я прошел и, честно говоря, вышел за рамки.

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

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

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

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

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

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

Так что удачи, и я надеюсь, что это открывает новые перспективы для вас.

1 голос
/ 29 апреля 2009

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

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

Если у вас есть функция, которая изменяет переданную переменную, эта модификация является побочным эффектом, потому что она является видимым выводом функции, отличной от возвращаемого значения. Функция void, которая не запрещена, должна иметь побочные эффекты, потому что у нее нет другого способа воздействовать на мир.

Функция может иметь закрытую переменную, видимую только той функции, которую она читает и изменяет, и ее вызов все равно будет иметь побочный эффект изменения поведения функции в будущем. Быть чистым означает иметь ровно один канал для вывода любого вида: возвращаемое значение.

Можно генерировать случайные числа чисто, но вы должны вручную обойти случайное начальное число. Большинство случайных функций сохраняют частное начальное значение, которое обновляется каждый раз при его вызове, так что вы каждый раз получаете разные случайные значения. Вот фрагмент кода Haskell, использующий System.Random :

randomColor              :: StdGen -> (Color, Int, StdGen)
randomColor gen1         = (color, intensity, gen2)
 where (color, gen2)     = random gen1
       (intensity, gen3) = randomR (1, 100) gen2

Каждая из случайных функций возвращает рандомизированное значение и новый генератор с новым начальным числом (на основе предыдущего). Чтобы получить новое значение каждый раз, необходимо передать цепочку новых генераторов (gen1, gen2, gen3). Неявные генераторы просто используют внутреннюю переменную для хранения значений gen1 .. в фоновом режиме.

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

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

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

Распределение памяти на чистых языках должно происходить неявно, потому что явное выделение и освобождение памяти являются побочными эффектами, если вы можете выполнять любые виды сравнения указателей. В противном случае создание двух новых объектов с одинаковыми параметрами будет по-прежнему иметь разные значения, поскольку они будут иметь разные идентификаторы (например, не будут равны оператору Java ==).

Я знаю, что немного поболтал, но, надеюсь, это объясняет, что такое побочные эффекты.

0 голосов
/ 29 апреля 2009

Серьезный взгляд на Clojure и их использование программной транзакционной памяти, агентов и атомов для контроля побочных эффектов.

...