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

Почему y = 1 + y компилируется, и что это значит?

В GHCi let y = y + 1 компилируется отлично, но когда я пытаюсь оценить y, я получил *** Exception: <<loop>>

Почему нет ошибки компиляции и что это значит <<loop>>?

4b9b3361

Ответ 1

Haskell let, where и привязки верхнего уровня рекурсивны по умолчанию, даже если они не для функции. Таким образом, let y = y + 1 определяет бесконечный цикл добавления 1 к числу. GHC представляет такие петли, как это, с исключением <<loop>> - если он может их поймать, конечно!

Это полезно для ленивых операций, поскольку позволяет нам легко определять такие вещи, как бесконечные списки (let xs = 0:xs), которые хорошо определены и действительно полезны для обычного кода. Тем не менее, он не может работать для строгих операций, таких как + (для большинства числовых типов), потому что им необходимо сразу оценить всю (бесконечную) вещь.

Ответ 2

Я хотел добавить минимальный пример того, где это может быть полезно.

data Peano = Z | S Peano

instance Num Peano where
    p + Z     = p
    p + (S q) = S (p + q)
    fromInteger 1 = S Z

instance Eq Peano where
    Z     == Z     = True
    Z     == _     = False
    _     == Z     = False
    (S p) == (S q) = p == q

instance Ord Peano where
    Z     `compare` Z     = EQ
    Z     `compare` _     = LT
    _     `compare` Z     = GT
    (S p) `compare` (S q) = p `compare` q

y :: Peano
y = y + 1

main :: IO ()
main = print $ 1 < y

В этом случае y бесконечно, с точностью до изоморфизма. (Хотя мой fromInteger явно слабая реализация, поэтому изменение литерального 1 на что-то другое без исправления fromInteger не удастся.)

Обратите внимание, что это работает только потому, что (+), который я определил, ленив в этом первом аргументе, и compare, который я определил, также достаточно ленив.