为Typeable编写实例声明而不导出

thy*_*222 10 haskell types instance

如何为Typeable编写实际的实例声明?例如,假设我想为Char编写一个实例,其中每个角色都有不同的类型,例如

instance Typeable Char where
    typeOf 'a' = C
    typeOf 'b' = C -> D
    typeOf 'c' = D -> E
    typeOf     = String
Run Code Online (Sandbox Code Playgroud)

显然这不会像这样写,因为typeOf的输出是TypeRep,但我无法弄清楚如何实际构造TypeRep.

这甚至可能吗?似乎所有关于Typeable的内容都假定您将使用DeriveDataTypeable.

Dan*_*zer 17

这样做有一些问题.

  1. 它坏了.typeOf不应该在它的论点中严格,所以typeOf (undefined :: Char)应该工作.

  2. 这是不安全的.实际上,如果您手动创建一个实例,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)
Run Code Online (Sandbox Code Playgroud)

现在作为为什么这是可怕的一个例子,考虑一下

what :: Char -> C
what c = if isJust weird then fromJust weird else error "Sanity!"
  where weird = fromDynamic . toDyn $ Foo c
Run Code Online (Sandbox Code Playgroud)

现在

> what 'a'
  C
> what 'b'
  *** Exception: Sanity!
Run Code Online (Sandbox Code Playgroud)

取决于Foo这可以做各种有趣的事情的表示,如段错,吐出无意义的答案,或让猴子飞出你的耳朵.

罗伯特哈珀给出了一个更具戏剧性的例子

{-# 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 ())
Run Code Online (Sandbox Code Playgroud)

这使

<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)
Run Code Online (Sandbox Code Playgroud)

  • @ thylacine222:还要注意,未来的ghc很可能只允许派生`Typeable`实例,而不是用户定义的. (10认同)
  • @JohnL那已经是这样了.GHC 7.8不允许用户定义的Typeable实例. (3认同)