如何为Typeable编写实际的实例声明?例如,假设我想为Char写一个实例,其中每个字符都有不同的类型,例如
instance Typeable Char where
typeOf 'a' = C
typeOf 'b' = C -> D
typeOf 'c' = D -> E
typeOf = String
显然这不会像这样写,因为typeOf的输出是TypeRep,但我无法弄清楚如何实际构造TypeRep。
这甚至可能吗?似乎所有关于Typeable的内容都假定您将使用DeriveDataTypeable。
答案 0 :(得分:17)
这样做有一些问题。
它坏了。 typeOf
在论证中不应该是严格的,因此typeOf (undefined :: Char)
应该有效。
这是不安全的。实际上,如果您手动创建Typeable
的实例,则不会在Safe Haskell下编译。
牢记这一点!
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Typeable
data C = C deriving (Typeable)
data D = D deriving (Typeable)
data E = E deriving (Typeable)
newtype Foo = Foo Char
instance Typeable Foo where
typeOf (Foo 'a') = typeOf (undefined :: C)
typeOf (Foo 'b') = typeOf (undefined :: C -> D)
typeOf (Foo 'c') = typeOf (undefined :: D -> E)
typeOf _ = typeOf (undefined :: String)
现在举例说明为什么会这么糟糕,请考虑
what :: Char -> C
what c = if isJust weird then fromJust weird else error "Sanity!"
where weird = fromDynamic . toDyn $ Foo c
现在
> what 'a'
C
> what 'b'
*** Exception: Sanity!
取决于Foo
如何表现各种有趣的事物,例如seg fault,吐出无意义的答案,或让猴子飞出你的耳朵。
Robert Harper给出了一个更具戏剧性的例子
{-# LANGUAGE DeriveDataTypeable #-}
import Control.Exception
import Data.Typeable
newtype Foo = Foo (() -> IO ())
{- set Foo’s TypeRep to be the same as ErrorCall’s -}
instance Typeable Foo where
typeOf _ = typeOf (undefined :: ErrorCall)
instance Show Foo where show _ = ""
instance Exception Foo
main = Control.Exception.catch (error "kaboom") (\ (Foo f) -> f ())
哪个给出了
<interactive>: internal error: stg_ap_v_ret
(GHC version 7.6.3 for x86_64_unknown_linux)
Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug
C-c C-c
Process haskell aborted (core dumped)