Crash in GHCI - what is the correct behavior here?

Basically just learning haskell, I would have posted this in the beginners list but since it involves a segfault of GHCI, I figured it might be worth posting here. I was trying to get a good understanding of local variable scoping issues, so I tried the following: f :: (Num a) => a -> a f x = let p = x*x in let p = x*p in p I have some background in ML, which led me to believe that what should happen here is that the function would return x^3. Instead, GHCI just completely terminates, I guess with a segfault. What's the "correct" behavior here? Should it even compile? I understand that you can't redefine the same symbol twice in the same scope, so I tried this specifically to see what would happen if you defined the same variable again in a nested scope. I thought it would just shadow the original declaration, while still using the original p to calculate the value of the new p. I don't think the problem is the re-declaration of the same symbol in a nested scope (although if someone could clarify that would be nice), but rather the fact that I've attempted to use the previous declaration of p in defining the new declaration of p. Would it be a safe assumption that a bug report should be submitted over this?

2009/3/18 Zachary Turner
Basically just learning haskell, I would have posted this in the beginners list but since it involves a segfault of GHCI, I figured it might be worth posting here.
I was trying to get a good understanding of local variable scoping issues, so I tried the following:
f :: (Num a) => a -> a f x = let p = x*x in let p = x*p in p
I have some background in ML, which led me to believe that what should happen here is that the function would return x^3. Instead, GHCI just completely terminates, I guess with a segfault. What's the "correct" behavior here? Should it even compile? I understand that you can't redefine the same symbol twice in the same scope, so I tried this specifically to see what would happen if you defined the same variable again in a nested scope. I thought it would just shadow the original declaration, while still using the original p to calculate the value of the new p. I don't think the problem is the re-declaration of the same symbol in a nested scope (although if someone could clarify that would be nice), but rather the fact that I've attempted to use the previous declaration of p in defining the new declaration of p.
You are correct that the inner p shadows the outer p. However, you are incorrect that "p" on the right side of the inner definition is the outer p (man this is hard to talk about). Lets in Haskell are recursive, so your program is equivalent to: f x = let p = x*p in p I'm going to do a little domain theory now, because I'm in the mood :-). So p is the least value which satisfies the equation p = x*p. For most numeric types, (*) is strict in its right argument, so _|_ = x*_|_. And in fact this is the equation we had to satisfy, and there is no value less than _|_, so p = _|_. So, f x = _|_. (an infinite loop) I love Haskell so much. T'aint no language more precise. Anyway, there are various ways that Haskell handles bottom. If you're seeing ghci immediately exit, you're probably observing "black hole detection", in which ghci prints <loop> to inform you you have an infinite loop instead of actually looping forever. There are certain cases where this can be done. If that's not consistent with what you observed, more details please! Including version, OS, compiler flags, and transcript. It might indeed be a bug :-) Luke

On Wed, Mar 18, 2009 at 11:46 PM, Luke Palmer
2009/3/18 Zachary Turner
Basically just learning haskell, I would have posted this in the beginners list but since it involves a segfault of GHCI, I figured it might be worth posting here.
I was trying to get a good understanding of local variable scoping issues, so I tried the following:
f :: (Num a) => a -> a f x = let p = x*x in let p = x*p in p
I have some background in ML, which led me to believe that what should happen here is that the function would return x^3. Instead, GHCI just completely terminates, I guess with a segfault. What's the "correct" behavior here? Should it even compile? I understand that you can't redefine the same symbol twice in the same scope, so I tried this specifically to see what would happen if you defined the same variable again in a nested scope. I thought it would just shadow the original declaration, while still using the original p to calculate the value of the new p. I don't think the problem is the re-declaration of the same symbol in a nested scope (although if someone could clarify that would be nice), but rather the fact that I've attempted to use the previous declaration of p in defining the new declaration of p.
You are correct that the inner p shadows the outer p. However, you are incorrect that "p" on the right side of the inner definition is the outer p (man this is hard to talk about). Lets in Haskell are recursive, so your program is equivalent to:
f x = let p = x*p in p
I'm going to do a little domain theory now, because I'm in the mood :-). So p is the least value which satisfies the equation p = x*p. For most numeric types, (*) is strict in its right argument, so _|_ = x*_|_. And in fact this is the equation we had to satisfy, and there is no value less than _|_, so p = _|_.
So, f x = _|_. (an infinite loop)
I love Haskell so much. T'aint no language more precise.
Anyway, there are various ways that Haskell handles bottom. If you're seeing ghci immediately exit, you're probably observing "black hole detection", in which ghci prints <loop> to inform you you have an infinite loop instead of actually looping forever. There are certain cases where this can be done.
If that's not consistent with what you observed, more details please! Including version, OS, compiler flags, and transcript. It might indeed be a bug :-)
Regarding the "black hole detection", is GHCI supposed to exit after printing <loop>? Or is just supposed to print <loop> then return to a GHCI prompt? Here's a transcript: C:\Documents and Settings\Zach>ghci GHCi, version 6.10.1: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer ... linking ... done. Loading package base ... linking ... done. Prelude> let f x = let p = x*x in let p = x*p in p Prelude> f 7 C:\Documents and Settings\Zach> That's it. This is on Windows XP Service Pack 2.

On Wed, Mar 18, 2009 at 10:55 PM, Zachary Turner
Regarding the "black hole detection", is GHCI supposed to exit after printing <loop>? Or is just supposed to print <loop> then return to a GHCI prompt? Here's a transcript:
C:\Documents and Settings\Zach>ghci GHCi, version 6.10.1: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer ... linking ... done. Loading package base ... linking ... done. Prelude> let f x = let p = x*x in let p = x*p in p Prelude> f 7
C:\Documents and Settings\Zach>
Hmm, that's weird. I note that here on linux, this expression gobbles up memory like nobody's business. Maybe it's being killed for eating too much? (I dunno) Luke

I also see a segfault on Windows XP SP2 and GHC 6.10.1, very quick so
I'm fairly sure it's not memory.
I agree this should be a bug report.
________________________________
From: haskell-cafe-bounces@haskell.org
[mailto:haskell-cafe-bounces@haskell.org] On Behalf Of Luke Palmer
Sent: 19 March 2009 05:00
To: Zachary Turner
Cc: haskell-cafe@haskell.org
Subject: Re: [Haskell-cafe] Crash in GHCI - what is the correct behavior
here?
On Wed, Mar 18, 2009 at 10:55 PM, Zachary Turner
participants (3)
-
Luke Palmer
-
Sittampalam, Ganesh
-
Zachary Turner