Каково математическое значение "все (== 1) [1,1..]" не заканчивается?

Интуитивно я ожидал бы, что "математический" ответ all (==1) [1,1..] будет True, потому что все элементы в списке, который содержит только 1, равны 1. Однако я понимаю, что "вычислительно", процесс оценка бесконечного списка для проверки того, что каждый элемент действительно равен 1, никогда не будет завершаться, поэтому выражение вместо этого "оценивает" снизу или .

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

Мой вопрос в том, что это самый математически правильный ответ? или True? Некоторая разработка относительно того, почему один ответ является более правильным, чем другой, также будет высоко оценен.

edit: Это может косвенно иметь отношение к изоморфизму Карри-Говарда (Программы являются доказательствами и типами являются теоремами) и Теоремы о неполноте Гёделя. Если я правильно помню, одна из теорем о неполноте может быть (невероятно грубо) обобщена, говоря, что "достаточно мощные формальные системы (например, математика или язык программирования) не могут доказать все истинные утверждения, которые могут быть выражены в системе"

Ответ 1

Значение

all (==1) [1,1..]

- наименьшая верхняя граница последовательности

all (==1) (⊥)
all (==1) (1 : ⊥)
all (==1) (1 : 1 : ⊥)
...

и все члены этой последовательности ⊥, поэтому наименьшая верхняя грань также равна ⊥. (Все функции Haskell непрерывны: сохраняйте наименьшие верхние границы.)

Это использует денотационную семантику для Haskell и не зависит (напрямую) от выбора какой-либо конкретной стратегии оценки.

Ответ 2

В программировании мы используем не классическую логику, а интуиционистскую (конструктивную) логику. Мы все еще можем интерпретировать типы как теоремы, но мы не заботимся об истине этих теорем; вместо этого мы говорим о том, конструктивно ли они созданы. Даже если all (== 1) [1, 1 ..] истинно, мы не можем доказать это в Haskell, поэтому мы получаем ⊥ (здесь бесконечный цикл).

В конструктивной логике у нас нет закона исключенного среднего, а в результате - двойного отрицания. Тип функции Haskell all (== 1) :: [Int] -> Bool не представляет теорему [Int] → Bool, которая была бы полной функцией; он представляет собой теорему [Int] → ¬¬Bool. Если all может доказать теорему, производя результат, то этот результат будет иметь тип Bool; в противном случае результатом будет дно.

Ответ 3

Я не знаю достаточно о вычислимости, чтобы ответить на это правильно, но я действительно утешаю простоту в оформлении языка. В этом случае я считаю простым и элегантным, что all не должен знать ничего о введенном им вводе. Возможно, человеку легче рассуждать о том, что вы дали.

Конечно, теперь было бы полезно для понимания бесконечного списка как-то сказать all, что это бесконечный список из них. Но... это то, что он говорит, "имея это значение". Наличие нескольких более общих метаданных о повторяющейся последовательности было бы более успешным для целей оптимизации, но я думаю, что простота будет уменьшена, а сложность будет введена.