As I understand it, Haskell's undefined value - of a particular type - is a value that can't be determined, for whatever reason (maybe there is no sensible definition, or the calculation diverges). For instance: undefined :: [Int] is a list, so it must be constructed with either [] or (:), but it doesn't know which one! Hence it makes sense that case splitting on undefined makes the whole expression undefined: I don't know whether null (undefined :: [a]) is True or False, because I don't know whether undefined :: [a] is empty or not.
(By the way - if you disagree with my suggestion that undefined is built with a constructor, then surely null (undefined :: [a]) should evaluate to False? After all undefined isn't equivalent to []!)
However, Haskell pattern matching doesn't follow this way of thinking.
data Foo = Foo Int String -- Only one data constructor
silly :: Foo -> Bool
silly (Foo _ _) = True
ghci> silly (undefined :: Foo)
*** Exception: Prelude.undefined -- But whatever the value is, it must
-- be constructed with Foo.
-- So why fail to match?
(I know that newtype behaves differently here.)
Also:
foo :: Int -> String -> Bool
foo 8 "Hello" = True
foo _ _ = False
ghci> foo undefined undefined
*** Exception: Prelude.undefined -- GOOD - can't tell which case to choose.
ghci> foo undefined "Hello"
*** Exception: Prelude.undefined -- GOOD - still can't tell.
ghci> foo undefined "Goodbye"
*** Exception: Prelude.undefined -- BAD - should return false!
-- Pattern match on first line should fail,
-- because whatever the int is, the
-- string can't match the given pattern.
I think the rules on pattern matching currently say that if a sub-pattern fails then the pattern should immediately fail; if it diverges, then the whole pattern should also diverge; and if it succeeds, then the next sub-pattern should be tried. If all sub-patterns succeed, then the whole pattern succeeds.
What I am suggesting is that if any of the sub-patterns fail then the whole pattern should fail; if none fail but some diverge then the whole pattern should diverge; and if all succeed then the whole pattern should succeed.
Why is this not how Haskell does things?
EDIT:
So to summarise my interpretation of the responses I've read:
undefined should be read as "This would cause your program to run forever" not "This is not well defined", and Exception: Prelude.undefined should be read as "Watch out! Your program would have never terminated if undefined was an infinite loop" rather than "I don't know what to do because I don't know what value undefined is".
Could somebody please verify that this is correct? If so then I will probably accept mb14's answer.
Thanks everyone. Sorry for being so slow on the uptake!
undefined = error "Prelude.undefined", anderroris basically raising an exception:error s = throw (errorCallException s). So it's an exception, hidden in the darks, getting thrown when you try to look into the value. And when you usefoo undefined "Goodbye", you're actually usingfoo (undefined :: Int) "Goodbye", so the compiler still generates code that checks the value ofundefined. - Zeta