在Haskell中进行JSON解析期间的重载分辨率

时间:2012-09-17 00:34:39

标签: parsing haskell overloading typeclass

我正在阅读“Real World Haskell”(好书),我对编译器如何选择重载函数感到困惑。

如果我有类型

type JSONError = String

class JSON a where
    toJValue :: a -> JValue
    fromJValue :: JValue -> Either JSONError a

和两个像这样的实例

instance JSON Bool where
    toJValue = JBool
    fromJValue (JBool b) = Right b
    fromJValue _ = Left "not a JSON boolean"

instance JSON String where
    toJValue = JString
    fromJValue (JString s) = Right s
    fromJValue _ = Left "not a JSON string"

编译器如何在两个“fromJValue”函数之间进行选择,例如,给出一个Integer?

2 个答案:

答案 0 :(得分:6)

如果使用fromJValue someValue作为某个表达式的一部分,Haskell将选择表达式所需的类型。所以,如果您这样做:

case fromJValue someValue of 
    Right str -> putStr str
    Left _ -> error

选择了JSON String的实例,因为putStr需要一个字符串。

如果无法明确确定所需类型,则会出现“模糊类型变量”错误,并且必须添加类型注释以手动选择要使用的实例。

请注意,JValue someValue包含哪种内容完全不相关。

答案 1 :(得分:1)

在OO语言中,如果返回一个对象,则虚拟方法表与一起返回。在Haskell中,如果返回类型类的成员,则字典作为隐藏参数传入

所以在运行时没有问题 - 隐藏的字典参数就像VTable一样用于实现。

现在你的问题就变成了编译器最初选择实例的方式。

了解fromJValue的使用方式。

首先是包含JSON数据的字符串,然后将其传递给解析函数:

foo :: String
foo = parseJsonString x

现在编译器知道它必须在调用链上传递instance JSON String的字典。

parseJsonString(我不记得正确的名称)将您的字符串解析为JSON数据类型。像

这样的东西
data ParsedJSON = JBool Bool | JString string | JObject ...

parseJsonString :: JSON a => String -> Either JSONError a 

首先,它尝试将传递的字符串转换为ParsedJSON数据结构。

其次,它将已经拥有的结构和字典传递给fromJValue

现在如果x"{ foo : 222 }",则实例仍为String,因此将调用Left分支并且解析器会说"而不是JSON字符串"

另一个小问题 - 在制作中,您应该使用returnthrowError代替MonadErrorLeft,以使您的意图更加清晰。但我认为它只是一个教程代码。