Во-первых, я полагаю, вы уже слышали о тезисе Черча-Тьюринга, в котором говорится, что все, что мы называем «вычислением», можно сделать с помощью машины Тьюринга (или любой из многих других эквивалентных моделей). Таким образом, полный по Тьюрингу язык - это язык, на котором могут быть выражены любые вычисления. И наоборот, неполный по Тьюрингу язык - это язык, в котором есть некоторые вычисления, которые не могут быть выражены.
Хорошо, это было не очень информативно. Приведу пример. Есть одна вещь, которую вы не можете сделать ни на одном языке, неполном по Тьюрингу: вы не можете написать симулятор машины Тьюринга (иначе вы могли бы кодировать любые вычисления на симулированной машине Тьюринга).
Хорошо, это все еще не очень информативно. реальный вопрос в том, какая полезная программа не может быть написана на языке, неполном по Тьюрингу? Что ж, никто не придумал определение «полезная программа», которое включает в себя все программы, которые кто-то где-то написал для полезных целей, и не включает все вычисления на машине Тьюринга. Так что создание неполного по Тьюрингу языка, на котором можно было бы писать все полезные программы, по-прежнему остается очень долгосрочной целью исследования.
Сейчас существует несколько очень разных типов неполных по Тьюрингу языков, и они различаются тем, что не могут делать. Однако есть общая тема. Если вы разрабатываете язык, есть два основных способа гарантировать, что язык будет полным по Тьюрингу:
требовать, чтобы в языке были произвольные циклы (while
) и динамическое распределение памяти (malloc
)
требовать, чтобы язык поддерживал произвольные рекурсивные функции
Давайте рассмотрим несколько примеров полных по Тьюрингу языков, которые некоторые люди, тем не менее, могут называть языками программирования.
В ранних версиях FORTRAN не было динамического распределения памяти. Вам нужно было заранее выяснить, сколько памяти потребуется вашим вычислениям, и выделить это. Несмотря на это, FORTRAN когда-то был наиболее широко используемым языком программирования.
Очевидное практическое ограничение состоит в том, что вы должны предсказать потребности вашей программы в памяти перед ее запуском. Это может быть сложно и может быть невозможно, если размер входных данных не ограничен заранее. В то время человеком, который вводил входные данные, часто был человек, который написал программу, так что это не было такой большой проблемой. Но это не так для большинства программ, написанных сегодня.
Coq - это язык, разработанный для теорем доказательства. Теперь теоремы доказательства и запуск программ очень тесно связаны, поэтому вы можете писать программы на Coq, просто как вы доказываете теорему. Интуитивно, доказательство теоремы «A влечет B» - это функция, которая принимает доказательство теоремы A в качестве аргумента и возвращает доказательство теоремы B.
Поскольку целью системы является доказательство теорем, вы не можете позволить программисту писать произвольные функции. Представьте, что язык позволил вам написать глупую рекурсивную функцию, которая просто вызывала себя (выберите строку, в которой используется ваш любимый язык):
theorem_B boom (theorem_A a) { return boom(a); }
let rec boom (a : theorem_A) : theorem_B = boom (a)
def boom(a): boom(a)
(define (boom a) (boom a))
Вы не можете позволить существованию такой функции убедить вас в том, что A влечет B, иначе вы сможете доказать что угодно, а не только истинные теоремы! Таким образом, Coq (и подобные средства доказательства теорем) запрещают произвольную рекурсию. Когда вы пишете рекурсивную функцию, вы должны доказать, что она всегда завершается, чтобы всякий раз, когда вы запускали ее для доказательства теоремы A, вы знали, что она построит доказательство теоремы B.
Непосредственным практическим ограничением Coq является то, что вы не можете писать произвольные рекурсивные функции. Поскольку система должна иметь возможность отклонять все незавершенные функции, неразрешимость проблемы остановки ( или, в более общем смысле, теорема Райса) гарантирует, что есть завершающие функции, которые также отклоняются. Дополнительная практическая трудность заключается в том, что вы должны помочь системе доказать, что ваша функция действительно завершается.
В настоящее время ведется много исследований по тому, чтобы сделать системы доказательства более похожими на язык программирования без ущерба для их гарантии того, что если у вас есть функция от A до B, это так же хорошо, как математическое доказательство того, что A подразумевает B. Расширение системы для принятия большего количества завершающие функции - одна из тем исследования. Другие направления расширения включают решение таких «реальных» проблем, как ввод / вывод и параллелизм. Другая задача - сделать эти системы доступными для простых смертных (или, возможно, убедить простых смертных в том, что они действительно доступны).
Языки синхронного программирования - это языки, разработанные для программирования систем реального времени, то есть систем, в которых программа должна ответ менее чем за n тактов. Они в основном используются для критически важных систем, таких как средства управления транспортными средствами или сигнализация. Эти языки предлагают надежные гарантии того, сколько времени потребуется для запуска программы и сколько памяти она может выделить.
Конечно, аналогом таких сильных гарантий является то, что вы не можете писать программы, потребление памяти и время работы которых вы не можете предсказать заранее. В частности, вы не можете написать программу, потребление памяти или время работы которой зависит от входных данных.
Есть много специализированных языков, которые даже не пытаются быть языками программирования и поэтому могут оставаться комфортно далекими от полноты Тьюринга: регулярные выражения, языки данных, большинство языков разметки, ...
Кстати, Дуглас Хофштадтер написал несколько очень интересных научно-популярных книг о вычислениях, в частности Гёдель, Эшер, Бах: вечная золотая коса. Я не помню, обсуждает ли он явно ограничения неполноты по Тьюрингу, но чтение его книг определенно поможет вам понять больше технического материала.
person
Gilles 'SO- stop being evil'
schedule
16.08.2010