问题
Can anything be done to define a Show instance for an undefined value? Maybe some GHC extensions exist? I want something like this:
> print (1,undefined)
(1,"undefined")
回答1:
According to the Haskell 2010 report, chapter 9, evaluating undefined
should always cause an error:
-- It is expected that compilers will recognize this and insert error
-- messages that are more appropriate to the context in which undefined
-- appears.
undefined :: a
undefined = error "Prelude.undefined"
Since printing a value includes evaluating it, this will always give an error.
回答2:
The bottom value (of which undefined
is one flavor) is a value that is never constructed and hence can't be observed. This implies that you can't print it either. This value can't be compared to null
from other languages, which usually can be observed and even checked against.
It is useful to think of undefined
as well as error "blah"
and all other bottoms as equivalent to results of infinite loops. The result of an infinite loop is never constructed and hence can't be observed.
回答3:
More conceptually: The "undefined" is not a value like 'X'. The 'X' value has type Char. What type does "undefined" have? The symbol "undefined" is polymorphic, it can have any type (any type of kind *).
Type classes like "Show t" dispatch on the type t. So different type can and do have different show functions that display them. Which function gets your "undefined" depends on the type.
In GHCI most polymorphic types are defaulted to () so it can run the command. One can make a show function for a new type that does not look at the value:
Prelude> data Test = Test
Prelude> instance Show Test where show x = "I did not look at x"
Prelude> show Test
"I did not look at x"
Prelude> show (undefined :: Test)
"I did not look at x"
But as you can see this avoids the error with undefined by never examining the value at all. So this is a bit useless.
You could make your own type class and printing machinery that runs in IO and catches errors and does sort of what you want:
import Control.Exception
perr s = do x <- try (evaluate (show s)) :: IO (Either SomeException String)
return (either show id x))
The above translates errors into the error's string form:
Prelude Control.Exception> perr True
"True"
Prelude Control.Exception> perr (undefined :: Bool)
"Prelude.undefined"
Note: A better 'perr' needs to force the whole String instead of just the WHNF.
回答4:
Even though (as the others already pointed out) you can't specify a Show
instance for undefined
, you may be able to put together a workaround by using catch
as in the following code:
import qualified Control.Exception as C
import System.IO.Unsafe (unsafePerformIO)
showCatch :: (Show a) => a -> IO String
showCatch = showCatch' "undefined"
showCatch' :: (Show a) => String -> a -> IO String
showCatch' undef x = C.catch (C.evaluate (show x)) showUndefined
where
showUndefined :: C.ErrorCall -> IO String
showUndefined _ = return undef
unsafeShowCatch :: (Show a) => a -> String
unsafeShowCatch x = unsafePerformIO (showCatch x)
But this example will only work for simple expressions:
*Main> let v1 = showCatch 1
v1 :: IO String
*Main> let v2 = showCatch $ if True then undefined else 0
v2 :: IO String
*Main> v1
"1"
*Main> v2
"undefined"
*Main> let v3 = unsafeShowCatch 1
v3 :: String
*Main> let v4 = unsafeShowCatch $ undefined
v4 :: String
*Main> v3
"1"
*Main> v4
"undefined"
It won't work for calls like
showCatch (1,undefined)
来源:https://stackoverflow.com/questions/10738806/a-show-instance-for-undefined