问题
In GHCi let y = y + 1
compiles fine, but when I try to evaluate y I got *** Exception: <<loop>>
Why is there no compile error and what does it mean <<loop>>
?
回答1:
Haskell let
, where
and top-level bindings are recursive by default, even if they're not for a function. So let y = y + 1
defines an infinite loop of adding 1
to a number. GHC represents loops like this with the <<loop>>
exception—if it can catch them, of course!
This is usable for lazy operations, because it allows us to easily define things like infinite lists (let xs = 0:xs
), which are well-defined and actually useful for normal code. However, it can't work for strict operations like +
(for most numeric types) because they require evaluating the whole (infinite) thing right away.
回答2:
I wanted to add a minimal example of where this might actually be useful.
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
In this case, y
is infinity, up to isomorphism. (Though, my fromInteger
is clearly a poor implementation, so changing either literal 1
to something else without fixing fromInteger
will fail.)
Note that this only works because the (+)
I've defined is lazy in it's first argument and the compare
I've defined is also sufficiently lazy.
来源:https://stackoverflow.com/questions/27557380/why-does-let-y-1-y-compile-and-what-does-it-mean