a Show instance for undefined

送分小仙女□ 提交于 2019-12-22 10:41:01

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!