Можно ли что-нибудь сделать, чтобы определить экземпляр Show для неопределенного значения? Может быть, существуют какие-то расширения GHC? Я хочу что-то вроде этого:
> print (1,undefined)
(1,"undefined")
Можно ли что-нибудь сделать, чтобы определить экземпляр Show для неопределенного значения? Может быть, существуют какие-то расширения GHC? Я хочу что-то вроде этого:
> print (1,undefined)
(1,"undefined")
Согласно отчету Haskell 2010, глава 9, вычисление undefined
всегда должно вызывать ошибку :
-- 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"
Поскольку печать значения включает его оценку, это всегда будет приводить к ошибке.
print
не обязательно должна его оценивать, в зависимости от экземпляра Show
- person newacct; 24.05.2012
Нижнее значение (одним из вариантов которого является undefined
) — это значение, которое никогда не создается и, следовательно, не может наблюдаться. Это означает, что вы также не можете его распечатать. Это значение нельзя сравнивать с null
из других языков, которые обычно можно наблюдать и даже сравнивать.
Полезно думать о undefined
, а также error "blah"
и всех других основаниях как эквивалентных результатам бесконечных циклов. Результат бесконечного цикла никогда не создается и, следовательно, не может наблюдаться.
Более концептуально: «неопределенное» не является значением, подобным «X». Значение 'X' имеет тип Char. Какой тип имеет «неопределенное»? Символ "undefined" полиморфен, может иметь любой тип (любой тип вида *).
Типовые классы, такие как «Show t», отправляются на тип t. Таким образом, разные типы могут иметь и имеют разные функции отображения, которые их отображают. Какая функция получает ваше «неопределенное», зависит от типа.
В GHCI для большинства полиморфных типов по умолчанию используется (), поэтому он может выполнять команду. Можно сделать функцию show для нового типа, которая не смотрит на значение:
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"
Но, как вы можете видеть, это позволяет избежать ошибки с неопределенным значением, вообще не проверяя значение. Так что это немного бесполезно.
Вы можете создать свой собственный класс типов и механизм печати, который работает в IO, перехватывает ошибки и делает то, что вы хотите:
import Control.Exception
perr s = do x <- try (evaluate (show s)) :: IO (Either SomeException String)
return (either show id x))
Приведенное выше переводит ошибки в строковую форму ошибки:
Prelude Control.Exception> perr True
"True"
Prelude Control.Exception> perr (undefined :: Bool)
"Prelude.undefined"
Примечание. Лучший «perr» должен принудительно использовать всю строку, а не только WHNF.
Несмотря на то, что (как уже указывали другие) вы не можете указать экземпляр Show
для undefined
, вы можете найти обходной путь, используя catch
, как в следующем коде:
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)
Но этот пример будет работать только для простых выражений:
*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"
Это не будет работать для таких вызовов, как
showCatch (1,undefined)
+t
GHCI говорит, что showCatch 1
имеет тип String, но на самом деле это IO String
. Я исправил это в ответе.
- person Riccardo T.; 24.05.2012
undefined
— это value, и у него нет определенного типа, это просто Bottom, который может иметь любой тип. - person leftaroundabout   schedule 24.05.2012Maybe
. - person leftaroundabout   schedule 24.05.2012