未定義の値に対して 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"
値の出力には値の評価が含まれるため、これは常にエラーになります。
一番下の値 (そのうちのundefined
1 つのフレーバー) は、構築されていないため観測できない値です。これは、印刷もできないことを意味します。この値を他の言語と比較することはできませんnull
。通常、この値は観察でき、照合することもできます。
無限ループの結果と同じように、他のすべてのボトムとundefined
同様に考えると便利です。error "blah"
無限ループの結果は構築されないため、観察できません。
より概念的には、「未定義」は「X」のような値ではありません。'X' 値の型は Char です。「未定義」にはどのようなタイプがありますか? シンボル「未定義」はポリモーフィックであり、任意の型 (任意の種類の *) を持つことができます。
「Show t」のような型クラスは、型 t でディスパッチします。したがって、タイプが異なれば、それらを表示する別の show 関数を持つことができます。どの関数が「未定義」になるかは、タイプによって異なります。
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
インスタンスを指定することはできませんが、次のコードで as を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)