读取Haskell中的实例

读取Haskell中的实例,haskell,Haskell,我创建了一个类似于的类型,可能 数据定义a=为|未定义 我做了Showinstance instance Show a => Show (Defined a) where show (Is a) = show a show Undefined = "?" 因此,我尝试实现实例Read instance Read a => Read (Defined a) where readsPrec _ s = case (take 1 s) of

我创建了一个类似于
的类型,可能

数据定义a=为|未定义

我做了
Show
instance

instance Show a => Show (Defined a) where
    show (Is a) = show a
    show Undefined = "?"
因此,我尝试实现实例
Read

instance Read a => Read (Defined a) where
    readsPrec _ s = case (take 1 s) of
                    "?" -> [(Undefined,tail s)]
                    otherwise -> map (\(a,b) -> (Is a,b)) $ readsPrec 0 s
这是工作,但我不明白为什么。为什么这里没有无限循环:

otherwise -> map (\(a,b) -> (Is a,b)) $ readsPrec 0 s
readsPrec 0 s
尝试读取输入中的相同字符串,不是吗?所以它必须转到
否则
块,并形成一个无限循环。但代码确实有效

readsPrec 0 s
尝试读取输入中的相同字符串,不是吗

是的,它是,但它不是相同的
readsPrec
!让我添加几个类型注释:

{-# LANGUAGE ScopedTypeVariables #-}

instance Read a => Read (Defined a) where
  readsPrec _ = readsDefined

readsDefined :: forall a . Read a => String -> ReadS (Defined a)
readsDefined s = case (take 1 s) of
                    "?" -> [(Undefined,tail s)]
                    otherwise -> map (\(a,b) -> (Is a,b)) $ readsContent s
 where readsContent :: String -> ReadS a
       readsContent = readsPrec 0

请注意,在这里我不能用
readsDefined
替换
readsContent
,它们是两个不同的函数,具有不兼容的类型签名。这与代码中的情况相同,只是
readsDefined
readsContent
都是
readsPrec
方法的(不同)实例化,也就是说,它们共享相同的名称,但仍有不同的实现。

注意,Haskell中避免使用此类
Show
Read
实例:
Show
应生成有效的Haskell代码,因此,
“?”
不会产生任何结果。如果您想做的只是漂亮的打印,例如ghci,然后你应该继续使用
Maybe
容器,只是。对于我来说,使用标准的
Maybe
容器可能不是一个好主意,因为我用不同的行为创建了
Eq
定义的
类型的
Eq
实例?我打赌这是一个更糟糕的主意(但是如果你正确地隐藏了
未定义的
构造函数,它可能还可以)。无论如何,你不应该让
显示(Is a)
只打印
a
值,而不提及它被包装在
定义的
(Nothing==Nothing)
Eq
for
的实现中是
真的
可能
这不是我想要的
定义的
类型,因此,我必须创建自己的类型,或者为
重载
Eq
,这可能更糟。但是,您不应该希望
Undefined==Undefined
为false!至少不会,除非
Undefined
确实是一种在应用程序中永远不会出现的异常值。(是的,我知道类似地,对于浮点数,IEEE754指定
NaN==NaN
为false,但这确实是一个可怕的黑客攻击,它自己也造成了很多问题。)