Подтвердить что ты не робот

В чем причина полной системы Turing?

Scala, а у Haskell есть системы полного типа Turing. Обычно полнота Тьюринга относится к вычислениям и языкам. Что это значит в контексте типов?

Может ли кто-нибудь привести пример того, как программист может извлечь из этого выгоду?

PS Я не хочу сравнивать системы типа Haskell vs Scala. Это больше о термине в целом.

PSS Если возможно более Scala примеров.

4b9b3361

Ответ 1

Что это значит в контексте типов?

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

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeOperators #-}

infixl 1 `App`
data Term = S | K | App Term Term

type family Reduce t where
    Reduce S = S
    Reduce K = K
    Reduce (S `App` x `App` y `App` z) = Reduce (x `App` z `App` (y `App` z))
    Reduce (K `App` x `App` y) = Reduce x
    Reduce (x `App` y) = Reduce (Reduce x `App` y)

Вы можете увидеть это в действии в командной строке ghci; например, в исчислении SK, термин SKSK сводит (в конечном итоге) к просто K:

> :kind! Reduce (S `App` K `App` S `App` K)
Reduce (S `App` K `App` S `App` K) :: Term
= 'K

Здесь весело, чтобы попробовать:

> type I = S `App` K `App` K
> type Rep = S `App` I `App` I
> :kind! Reduce (Rep `App` Rep)

Я не буду испортить веселье - попробуйте сами. Но знайте, как сначала прервать программы с крайним предрассудком.

Может ли кто-нибудь привести пример того, как программист может извлечь из этого выгоду?

Произвольное вычисление уровня на уровне позволяет вам выражать произвольные инварианты в ваших типах и проверять компилятор (во время компиляции), чтобы они сохранялись. Хотите красно-черное дерево? Как насчет красно-черного дерева, которое может проверить компилятор, сохраняет инварианты красно-черного дерева? Это было бы удобно, правильно, так как это исключает целый класс ошибок реализации? Как насчет типа для значений XML, которые статически известны в соответствии с конкретной схемой? На самом деле, почему бы не пойти дальше и записать параметризованный тип, параметр которого представляет собой схему? Затем вы можете прочитать схему во время выполнения, и ваши проверки времени компиляции гарантируют, что ваше параметризованное значение может представлять только хорошо сформированные значения в этой схеме. Ницца!

Или, возможно, более прозаичный пример: что, если вы хотите, чтобы ваш компилятор проверял, что вы никогда не индексировали ваш словарь с помощью ключа, которого там не было? С достаточно развитой системой типов вы можете.

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