Это частичный ответ (каламбур), где я перечислю лишь несколько, возможно, неочевидных способов достижения не прекращения.
Во-первых, я подтверждаю, что отрицательно-рекурсивные типы действительно могутпричина не прекращения. Действительно, известно, что разрешение рекурсивного типа, такого как
data R a = R (R a -> a)
, позволяет определять fix
и получать от него без завершения.
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS -Wall #-}
data R a = R (R a -> a)
selfApply :: R a -> a
selfApply t@(R x) = x t
-- Church's fixed point combinator Y
-- fix f = (\x. f (x x))(\x. f (x x))
fix :: forall a. (a -> a) -> a
fix f = selfApply (R (\x -> f (selfApply x)))
Всего языков, таких как Coq илиAgda запрещает это, требуя, чтобы рекурсивные типы использовали только строго положительную рекурсию.
Еще один потенциальный источник не-завершения - то, что Haskell допускает Type :: Type
. Насколько я могу видеть, это позволяет кодировать System U в Haskell, где парадокс Жирара может быть использован для создания логической несогласованности, создавая термин типа Void
. Этот термин (насколько я понимаю) был бы не окончательным.
Парадокс Жирара, к сожалению, довольно сложен для полного описания, и я еще не полностью изучил его. Я только знаю, что это связано с так называемой гиперигрой, игрой, в которой первым ходом является выбор конечной игры для игры. Конечная игра - это игра, в которой каждый матч заканчивается после конечного числа ходов. Следующие ходы после этого будут соответствовать матчу в соответствии с выбранной конечной игрой на первом этапе. Вот парадокс: поскольку выбранная игра должна быть конечной, независимо от того, что это такое, весь гиперигровой матч всегда заканчивается после конечного количества ходов. Это делает гиперигру самой конечной игрой, делая бесконечную последовательность ходов «Я выбираю гиперигру, я выбираю гиперигру ...» действительной игрой, в свою очередь, доказывая, что гиперигра не конечна.
По-видимому, этот аргумент может быть закодирован в достаточно богатой системе чистых типов, такой как System U, а Type :: Type
позволяет встраивать тот же аргумент.