Это может быть философский вопрос, но я считаю, что на него есть объективный ответ.
Если вы читаете статью в Википедии о Haskell, вы можете найти следующее:
Этот язык основан на наблюдениях Хаскелла Карри и его интеллектуальных потомков, что «доказательство - это программа; формула, которую он доказывает, - это тип для программы»
Теперь я спрашиваю: разве это не применимо практически ко всем языкам программирования? Какая особенность (или набор функций) Haskell делает его совместимым с этим утверждением? Другими словами, каковы заметные способы, которыми это утверждение повлияло на структуру языка?
Ответы:
Да, основная концепция применяется повсеместно, да, но редко полезным способом.
Начнем с того, что с точки зрения теории типов это предполагает, что «динамические» языки лучше всего рассматривать как имеющие один тип, который содержит (среди прочего) метаданные о природе значения, которое видит программист, включая то, что эти динамические языки будут называть сами по себе "тип" (что не является концептуально одним и тем же). Любые такие доказательства, вероятно, будут неинтересны, поэтому эта концепция в основном относится к языкам со статическими системами типов.
Кроме того, многие языки, которые предположительно имеют «статическую систему типов», должны рассматриваться как динамические на практике, в этом контексте, поскольку они допускают проверку и преобразование типов во время выполнения. В частности, это означает любой язык со встроенной, по умолчанию поддержкой «отражения» или тому подобное. C #, например.
Haskell необычен в том, сколько информации он ожидает от типа - в частности, функции не могут зависеть ни от каких значений, кроме тех, которые указаны в качестве аргументов. С другой стороны, в языке с изменяемыми глобальными переменными любая функция может (потенциально) проверять эти значения и соответственно изменять поведение. Таким образом, функцию Haskell с типом
A -> B
можно рассматривать как миниатюрную программу, доказывающую, что этоA
подразумеваетB
; эквивалентная функция во многих других языках только скажет нам, чтоA
и какое бы глобальное состояние ни находилось в области видимости, подразумеваетсяB
.Обратите внимание, что хотя Haskell поддерживает такие вещи, как отражение и динамические типы, использование таких функций должно указываться в сигнатуре типа функции; аналогично для использования глобального государства. Ни один не доступен по умолчанию.
В Haskell также есть способы сломать вещи, например, разрешить исключения во время выполнения или использовать нестандартные примитивные операции, предоставляемые компилятором, но те ожидают, что они будут использоваться с полным пониманием только теми способами, которые победили. повредить смысл внешнего кода. Теоретически то же самое можно сказать и о других языках, но на практике с большинством других языков труднее выполнять задачи без «мошенничества» и менее навязчиво «обманывать». И, конечно, в настоящих «динамических» языках все это не имеет значения.
Концепция может быть взята гораздо дальше, чем в Хаскеле.
источник
Вы правы, что переписка Карри-Ховарда - вещь очень общая. Стоит немного ознакомиться с его историей: http://en.wikipedia.org/wiki/Curry-Howard_correspondence
Вы заметите, что в первоначальной формулировке это соответствие применимо, в частности, к интуиционистской логике с одной стороны и к простейшему типу лямбда-исчисления (STLC) с другой.
Классический Haskell - либо '98, либо даже более ранние версии, очень тесно связан с STLC, и по большей части был очень простой прямой перевод между любым данным выражением в Haskell и соответствующим термином в STLC (расширен с рекурсией и несколько примитивных типов). Так что это сделало Карри-Говарда очень явным. Сегодня, благодаря расширениям, такой перевод является несколько более сложным делом.
Таким образом, в некотором смысле, вопрос заключается в том, почему Хаскелл так легко «впадает» в STLC. На ум приходят две вещи:
Есть также важный способ, которым Haskell, как и большинство языков, терпит неудачу в отношении прямого применения корреспонденции Карри-Ховарда. Haskell, как полный по Тьюрингу язык, содержит возможность неограниченной рекурсии и, следовательно, не прекращения. STLC не имеет оператора с фиксированной точкой, не является завершающим по Тьюрингу и сильно нормализуется - то есть, ни одно сокращение термина в STLC не завершится. Возможность рекурсии означает, что можно «обмануть» Карри-Говарда. Например,
let x = x in x
имеет типforall a. a
То есть, поскольку он никогда не возвращается, я могу притворяться, что он дает мне все, что угодно! Поскольку мы всегда можем сделать это в Haskell, это означает, что мы не можем полностью «поверить» в любое доказательство, соответствующее программе на Haskell, если у нас нет отдельного доказательства того, что сама программа завершает работу.Происхождение функционального программирования до Хаскелла (особенно семейства ML) было результатом исследований CS, сфокусированных на создании языков, о которых вы могли легко доказать (среди прочего), исследованиях, которые очень хорошо знакомы и вытекают из CH с самого начала. И наоборот, Haskell служил как языком-носителем, так и источником вдохновения для ряда разрабатываемых помощников по доказательствам, таких как Agda и Epigram, которые основаны на разработках в теории типов, в значительной степени связанных с происхождением CH.
источник
A -> B
, заданная какA
, будет либо производить,B
либо ничего вообще. Он никогда не выдастC
, и какое значение типаB
он предоставляет или, если он расходится, все равно будет зависеть исключительно отA
предоставленного.Void
, нет? Лень усложняет и то и другое. Я бы сказал, что функцияA -> B
всегда производит значение типаB
, но это значение может содержать меньше информации, чем можно было бы ожидать.В приближении первого порядка большинство других (слабо и / или однотипированных) языков не поддерживают строгое разграничение на уровне языка между
и строгие отношения между ними. Во всяком случае, лучшими гарантиями, которые предоставляют другие такие языки, являются:
Обратите внимание, что по типу мы ссылаемся на предложение и, следовательно, на нечто, описывающее гораздо больше информации, чем просто int или bool . В Haskell существует проникающая культура функции, на которую влияют только ее аргументы - без исключений *.
Чтобы быть немного более строгим, общая идея состоит в том, что, применяя жесткий интуиционистский подход (почти) ко всем программным конструкциям (т.е. мы можем доказать только то, что мы можем построить), и ограничивая набор примитивных конструкций в таком так, что мы имеем
Конструкции на Haskell очень хорошо поддаются рассуждениям об их поведении. Если мы можем построить доказательство (читай: функция), доказывающее, что это
A
подразумеваетB
, это имеет очень полезные свойства:A
, мы можем построитьB
)A
, и ничего другого.что позволяет нам эффективно рассуждать о локальных / глобальных инвариантах. Вернемся к исходному вопросу; Языковые особенности Haskell, которые лучше всего способствуют этому мышлению:
Ничто из этого не является уникальным для Хаскелла (многие из этих идей невероятно стары). Тем не менее, в сочетании с богатым набором абстракций в стандартных библиотеках (обычно в классах типов), различным разделением на уровне синтаксиса и строгим стремлением к чистоте при разработке программ, мы получаем язык, который каким-то образом может быть одновременно достаточно практичен для реальных приложений , но в то же время оказывается проще рассуждать о большинстве традиционных языков.
Этот вопрос заслуживает достаточно глубокого ответа, и я не мог бы сделать это справедливо в этом контексте. Я бы посоветовал прочитать больше в Википедии / в литературе:
* Примечание: я игнорирую / игнорирую некоторые хитрые аспекты примесей Хаскелла (исключения, недопущения и т. Д.), Которые только усложняют аргумент.
источник
Какая особенность? Система типов (будучи статичной, чистой, полиморфной). Хорошей отправной точкой являются «Теоремы Вадлера бесплатно». Заметное влияние на дизайн языка? Тип IO, классы типа.
источник
Иерархия Клини показывает нам , что доказательства не являются программами.
Первое рекурсивное отношение:
Первыми рекурсивно перечислимыми отношениями являются:
Таким образом, программа является теоремой, и существующая итерация, на которой программа останавливается, подобна существующему доказательству, доказывающему теорему.
Когда программа правильно создана из спецификации, мы должны быть в состоянии доказать, что она удовлетворяет спецификации, и если мы можем доказать, что программа удовлетворяет спецификации, то это правильный синтез программы. Таким образом, мы выполняем программный синтез, если докажем, что программа удовлетворяет спецификации. Теорема о том, что программа удовлетворяет спецификации, является программой, в которой теорема относится к синтезированной программе.
Ложные выводы Мартина Лофа никогда не создавали компьютерных программ, и удивительно, что люди считают, что это методология синтеза программ. Полных примеров синтезируемой программы не было. Спецификация, такая как «ввод типа и вывод программы такого типа», не является функцией. Существует множество таких программ, и случайным образом выбрать одну из них не является рекурсивной функцией или даже функцией. Это просто глупая попытка показать синтез программы с помощью глупой программы, которая не представляет собой настоящую компьютерную программу, вычисляющую рекурсивную функцию.
источник
doesn't this really apply to pretty much all the programming languages?
" Этот ответ утверждает / показывает, что это предположение является недействительным, поэтому нет смысла обращаться к остальным вопросам, основанным на ошибочной предпосылке ,