Каковы практические ограничения полного языка, отличного от Тьюринга, такого как Coq?

Поскольку существуют не полные по Тьюрингу языки, и, учитывая, что я не изучал Comp Sci в университете, может ли кто-нибудь объяснить что-то, что является неполным по Тьюрингу языком (например, Coq) не может?

Или полнота / неполнота не представляет реального практического интереса (т.е. не имеет большого значения на практике)?

ИЗМЕНИТЬ - я ищу ответ типа вы не можете построить хеш-таблицу на языке, отличном от Тьюринга, из-за X или чего-то в этом роде!


person oxbow_lakes    schedule 16.08.2010    source источник
comment
Кстати, на более ранний аналогичный вопрос было несколько интересных ответов, которые дополняют приведенные здесь: stackoverflow.com/questions/315340/   -  person Gilles 'SO- stop being evil'    schedule 16.08.2010
comment
@ulidtko Способность интерпретировать полный по Тьюрингу язык требует полноты по Тьюрингу основного языка интерпретатора ... это правда. Упомянутый там код Agda позволяет избежать имитации кода BF. Он назначает семантику любой программе BF и, в принципе, может использоваться в структуре, позволяющей доказывать завершение определенных программ BF в Agda.   -  person Atsby    schedule 07.04.2015


Ответы (4)


Во-первых, я полагаю, вы уже слышали о тезисе Черча-Тьюринга, в котором говорится, что все, что мы называем «вычислением», можно сделать с помощью машины Тьюринга (или любой из многих других эквивалентных моделей). Таким образом, полный по Тьюрингу язык - это язык, на котором могут быть выражены любые вычисления. И наоборот, неполный по Тьюрингу язык - это язык, в котором есть некоторые вычисления, которые не могут быть выражены.

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

Хорошо, это все еще не очень информативно. реальный вопрос в том, какая полезная программа не может быть написана на языке, неполном по Тьюрингу? Что ж, никто не придумал определение «полезная программа», которое включает в себя все программы, которые кто-то где-то написал для полезных целей, и не включает все вычисления на машине Тьюринга. Так что создание неполного по Тьюрингу языка, на котором можно было бы писать все полезные программы, по-прежнему остается очень долгосрочной целью исследования.

Сейчас существует несколько очень разных типов неполных по Тьюрингу языков, и они различаются тем, что не могут делать. Однако есть общая тема. Если вы разрабатываете язык, есть два основных способа гарантировать, что язык будет полным по Тьюрингу:

  • требовать, чтобы в языке были произвольные циклы (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
comment
Хороший ответ. Примечание: я думаю, вы можете иметь в виду «популяризация», а не «вульгаризация». (Я не думаю, что второе слово имеет предполагаемое вами значение на английском языке.) - person Nathan Shively-Sanders; 17.08.2010
comment
Я не согласен с требованием динамического распределения памяти. Учитывая, что все физические компьютеры имеют ограниченную память, разве не у всех актуальных языков есть эта проблема? Конечно, моя программа C может выполнять динамическое распределение, но это не сработает на моей 32-битной машине, как только она выделит 4 ГБ, так чем это отличается от того, что я заранее предсказывал, что моей программе потребуется 4 ГБ? - person Gabe; 27.10.2010
comment
@Gabe: Вы путаете язык и его реализацию. Любая реальная реализация на компьютере будет ограничена конечным объемом памяти. Но это просто означает, что реализация обрабатывает только конечное (но полезное) подмножество языка. Обратите внимание, что языки стоит изучать, даже если они технически нереализуемы, потому что гораздо легче рассуждать о бесконечной системе, чем о чрезвычайно большой конечной системе. - person Gilles 'SO- stop being evil'; 27.10.2010
comment
Жиль: Я просто не понимаю, насколько динамическое распределение памяти является требованием для полноты по Тьюрингу. Даже если FORTRAN 77 не имеет malloc, вы все равно можете написать свой собственный malloc, используя большие заранее выделенные массивы. - person Gabe; 27.10.2010
comment
@Gabe: Нет, вы не можете написать malloc (ну, идеализированный malloc, который позволяет реализовать полный по Тьюрингу язык) с заранее выделенными массивами. Вы все равно позволите своей программе обращаться только к ограниченному количеству памяти; поэтому с теоретической точки зрения все, что у вас есть, - это конечный автомат. - person Gilles 'SO- stop being evil'; 28.10.2010
comment
@Gabe: Между прочим, полнота C по Тьюрингу не так очевидна. Поскольку указатели должны полностью определяться их битовым шаблоном, любая данная реализация C (даже концептуальная) может предоставить программе только конечный объем памяти (при условии, что вы не используете ввод-вывод для обеспечения дополнительного хранилища). Однако вы можете создать «мета-реализацию», которая запускает программу C в реализации, но начинает с нуля с большими ограничениями реализации, если malloc заканчивается память. Эта мета-реализация C является полной по Тьюрингу средой программирования. - person Gilles 'SO- stop being evil'; 28.10.2010
comment
Жиль: Что в C делает его способным к этой мета-реализации, но не FORTRAN? - person Gabe; 28.10.2010
comment
@Gabe: Насколько я знаю, в ранних версиях FORTRAN нет ничего похожего на malloc: размер структуры данных должен быть указан в тексте программы. В C вы можете сделать что-то вроде while (...) {n *= 2; realloc(p, n); ...}, чтобы увеличить размер доступной памяти (в конечном итоге вы столкнетесь с ограничением реализации, отсюда и необходимость в мета-реализации). Я думаю (поправьте меня, если я ошибаюсь), что FORTRAN до 95 не имеет подобной функции и, следовательно, более ограничен (я подозреваю, что вы можете писать только примитивные рекурсивные функции или что-то в этом роде). - person Gilles 'SO- stop being evil'; 28.10.2010
comment
Жиль: Предположим, у нас есть программа FORTRAN, которая создает программы FORTRAN, имитирующие машины Тьюринга. Когда внешняя программа обнаруживает, что массив внутренней программы слишком мал, она генерирует новый эмулятор машины Тьюринга с большим массивом и перезапускает программу. Таким образом, ФОРТРАН является полным по Тьюрингу. - person Gabe; 28.10.2010
comment
@Gabe: Нет, извините, вы не доказали, что ФОРТРАН является полным по Тьюрингу; вы доказали, что ФОРТРАН (или, скорее, мета-ФОРТРАН, который не имеет ограничений на длину массива, а значит, и на целочисленный размер) плюс запоминающее устройство неограниченного размера является полным по Тьюрингу. Но если вы хотите использовать это устройство хранения, существует гораздо более простая реализация машины Тьюринга: напишите универсальный автомат машины Тьюринга как программу FORTRAN (это конечный автомат, поэтому очевидно выразимый) и используйте хранилище для ленты. - person Gilles 'SO- stop being evil'; 28.10.2010
comment
В пункте Coq вы говорите: Расширение системы для принятия большего количества функций без прерывания - одна из тем исследования. Я думаю, вы имеете в виду больше (непримитивно-рекурсивных) завершающих функций? - person Chris Conway; 28.10.2010
comment
Жиль: Разве не все языки требуют, чтобы устройство хранения неограниченного размера было полным по Тьюрингу? Учитывая, что никакая реализация любого языка не является неограниченной, как может любой язык быть полным по Тьюрингу? - person Gabe; 29.10.2010
comment
@Gabe: Никакая конкретная реализация не является полной по Тьюрингу, поскольку не существует неограниченного запоминающего устройства. (Если у вас есть только миллиард терабайт, это не безгранично.) Но некоторые языки программирования неограниченны. Например, языки, в которых основным целочисленным типом является bignum (такие как Lisp, Haskell, Python), являются полностью полными по Тьюрингу. Языки, которые не имеют встроенных ограничений (например, тот, который налагается в C тем фактом, что указатели имеют заданное количество битов), также легко завершаются по Тьюрингу (например, я думаю, что Java, C # попадают в эту категорию). - person Gilles 'SO- stop being evil'; 29.10.2010
comment
Я думаю, что ссылка в доказательстве теорем должна быть связана не с автоматическим доказательством теорем, а с интерактивным доказательством теорем или помощниками по доказательству, поскольку это то, что делает Coq .. - person Kristopher Micinski; 03.10.2012
comment
@KristopherMicinski Противоречие: Народный язык - это интерактивное доказательство теорем, но тактический язык - это автоматическое доказательство теорем, а язык доказательств на основе CoC (о котором идет речь в этой части моего ответа) - это проверка доказательства. Я думаю, что Автоматическое доказательство теорем лучше отражает суть таких языков, Proof Assistant - это не более чем сравнительная таблица. - person Gilles 'SO- stop being evil'; 03.10.2012
comment
@Gilles неправда, язык тактики только доказывает теорему, если он действительно завершается, что на практике должно, но не по необходимости. В результате, хотя тактика реализует номинально разрешимые фрагменты логики более высокого порядка, утверждение, что это автоматическое доказательство теорем, неискренне по отношению к тому, что происходит на самом деле. - person Kristopher Micinski; 03.10.2012
comment
@Gilles, однако, я согласен с тем, что страница помощника по доказательству - отстой, нужна страница, которая охватывает интерактивное доказательство теорем, но отмечает, что тактика должна охватывать разрешимый фрагмент .. - person Kristopher Micinski; 03.10.2012
comment
Отличный ответ! Но вот комментарий. [...] вы не можете писать программы, потребление памяти и время работы которых вы не можете предсказать заранее. - это утверждение сомнительно для меня, особенно с учетом результатов текущих разработок шрифтов теория, включая такие концепции, как зависимые типы и codata. Трудно избежать попадания в эту ловушку, но при техническом написании следует проявлять крайнюю осторожность: со временем недостаточно строгие утверждения могут внезапно оказаться неправильными. - person ulidtko; 20.01.2015
comment
@ulidtko Вам не нужно знать точное время работы (потребление памяти ограничено временем работы). Но в системе с разрешимым статическим доказательством завершения доказательство завершения по построению дает ограничение на время выполнения. Это может быть чрезвычайно высокая граница, но неразрешимость проблемы остановки подразумевает, что в любой такой системе есть вычисления, завершение которых не может быть доказано и, следовательно, не может быть выражено, даже если они завершаются. - person Gilles 'SO- stop being evil'; 20.01.2015
comment
@ Жиль, верно, но ты же не читал пост о codata? можно написать ОС на полном языке. Некоторым программистам даже не нужно постоянно писать программы завершения; однако им нужны программы с хорошим поведением. Обобщите прекращение до четко определенного поведения в своем аргументе - тогда он внезапно исчезнет в привлекательности. А как насчет коиндукции, метода доказательства (тактика в машинном доказательстве), который можно использовать для утверждения равенства бесконечных структур данных в строгом и четко определенный путь? Можно написать цикл событий графического интерфейса пользователя на общем языке с кодировками. - person ulidtko; 21.01.2015
comment
@Gilles Я думаю, что разница для меня очень очевидна. ... это было бы невозможно - правильно, но вывод, который я делаю из этого, заключается не в том, что это не интерпретатор, а в следующем: практически возможно вычислить полные следы выполнения полного по Тьюрингу машины на общем языке с кодами, четко определенным образом. Называть это переводчиком или нет - вопрос другой и неинтересный. Главный вопрос, на который это дает ключ к разгадке: как далеко мы можем зайти в написании полезных программ без необходимости полной полноты по Тьюрингу? Какие вычисления существуют ниже этого класса? - person ulidtko; 21.01.2015
comment
Я упоминаю все это с единственной целью: предотвратить дальнейшее распространение мифа о том, что языки, соответствующие Тьюрингу, бесполезны. Они есть. Да, и для программ программирования тоже! (Не только для декларативных данных и т. Д.). Мы даже не знаем (пока) насколько они могут быть полезны. - person ulidtko; 21.01.2015
comment
@Giles нет, вы не всегда получаете ограничения на время работы из статических доказательств завершения (я не уверен, что вы имеете в виду под решаемым): если ваше доказательство завершения использует принцип Маркова (примерно эквивалентно предположению исключенного среднего в вашей мета-теории) , тогда у вас не будет никаких облигаций. Есть также некоторые завершающие программы, для которых, я думаю, довольно сложно вычислить границы: кажущиеся невозможными функциональные программы могут иметь время выполнения, зависящее от модуля равномерной непрерывности входных функций. - person Jason Gross; 23.05.2019

Самый прямой ответ: машина / язык, который не является полным по Тьюрингу, не может использоваться для реализации / моделирования машин Тьюринга. Это происходит из основного определения полноты Тьюринга: машина / язык является завершенным по Тьюрингу, если он может реализовывать / моделировать машины Тьюринга.

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

Например, если язык не поддерживает циклы или рекурсию или неявно циклы не могут быть завершены по Тьюрингу, потому что машины Тьюринга можно запрограммировать на вечную работу. Следовательно, этот язык не может решать проблемы, требующие циклов.

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

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

person slebetman    schedule 16.08.2010
comment
+1 Вы не можете написать интерпретатор для полного по Тьюрингу языка на неполном по Тьюрингу языке. Вы также не можете сделать ничего эквивалентного (где эквивалент означает, что написание интерпретатора для полного по Тьюрингу языка может быть сведено к этой проблеме). Для всего остального (вычислимого) существует не полный по Тьюрингу язык, на котором вы можете это делать. - person sepp2k; 16.08.2010
comment
Как мне доказать, что некоторая заданная проблема требует петель для решения. Например, может ли случиться так, что все, что можно решить с помощью циклов, также можно решить с помощью рекурсии? - person oxbow_lakes; 16.08.2010
comment
@oxbow_lakes: Доказано, что рекурсия и цикл взаимозаменяемы. Поэтому под циклом мы понимаем и рекурсию. Отсутствие цикла означает невозможность выполнения рекурсии. - person slebetman; 16.08.2010
comment
@oxbow_lakes: Подход 1: чтобы доказать, что проблема P требует решения циклов на языке L, вы определяете язык K, который является L без циклов, и показываете, что проблема P не может быть решена на языке K. Обычно последняя часть выполняется путем доказательства что каждая программа на языке K имеет определенное свойство (например, ограничение на время выполнения), а проблема P не имеет этого свойства. - person Gilles 'SO- stop being evil'; 16.08.2010
comment
@oxbow_lakes: Подход 2: чтобы доказать, что проблема P требует решения циклов или некоторой эквивалентной функции, вы пытаетесь закодировать циклы в проблему P. Например, чтобы доказать, что наличие циклов требует рекурсии (т. е. что циклы столь же мощны, как и рекурсия), вы показываете, что любая рекурсивная программа может быть написана с использованием циклов. - person Gilles 'SO- stop being evil'; 16.08.2010

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

function collatz(n)
  while n > 1
    if n is odd then
      set n = 3n + 1
    else
      set n = n / 2
    endif
 endwhile

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

person ejgallego    schedule 25.05.2016
comment
Я не согласен: вы можете прекрасно выразить гипотезу Коллатца в Coq: forall n, exists k, (iterate collatz k) n = 1. (где iterate f k применяет функцию k раз). - person Olivier Verdier; 07.12.2016

Вы не можете написать функцию, имитирующую машину Тьюринга. Вы можете написать функцию, которая имитирует машину Тьюринга для 2^128 (или 2^2^2^2^128 шагов) и сообщает, приняла ли машина Тьюринга, отклонила или работала дольше разрешенного количества шагов.

Поскольку «на практике» вас уже давно не будет, прежде чем ваш компьютер сможет смоделировать машину Тьюринга для 2^128 шагов, справедливо будет сказать, что неполнота Тьюринга не имеет большого значения «на практике».

person Atsby    schedule 07.04.2015