Итак, я немного читал о coinduction в последнее время, и теперь мне интересно: являются ли списки Haskell индуктивными или коиндуктивными? Я также слышал, что Haskell не отличает этих двух, но если да, то как они делают это формально?
Списки определяются индуктивно, data [a] = [] | a : [a]
, но могут использоваться коиндуктивно, ones = a:ones
. Мы можем создавать бесконечные списки. Тем не менее, мы можем создавать конечные списки. Итак, каковы они?
Связано это в Идрисе, где тип List a
является строго индуктивным типом и, следовательно, является только конечным списком. Он определен сродни тому, как он находится в Хаскелле. Однако Stream a
является коиндуктивным типом, моделирующим бесконечный список. Он определяется как (точнее, определение эквивалентно) codata Stream a = a :: (Stream a)
. Невозможно создать бесконечный Список или конечный поток. Однако, когда я пишу определение
codata HList : Type -> Type where
Nil : HList a
Cons : a -> HList a -> HList a
Я получаю поведение, которое я ожидаю от списков Haskell, а именно, что могу создавать как конечные, так и бесконечные структуры.
Итак, позвольте мне сварить их до нескольких основных вопросов:
-
Разве Haskell не проводит различия между индуктивными и коиндуктивными типами? Если да, то для чего это формализация? Если нет, то что [a]?
-
Является ли HList коиндуктивным? Если да, то как коиндуктивный тип может содержать конечные значения?
-
А если мы определили
data HList' a = L (List a) | R (Stream a)
? Что бы это было рассмотрено и/или было бы полезно для всегоHList
?