Haskell中Read类的实例

时间:2012-11-23 08:33:39

标签: haskell type-inference

当我遇到困难时,我才开始玩哈斯克尔。

我正在尝试创建MyType类的新数据类型(我们称之为Read)。 Mytype是一个类型构造函数,因此它需要另一个类型作为参数。我想写这种代码

    instance (Read a) => Read (MyType a) where
        readsPrec _ r = [foo (read r :: a ), r]

但是它给了我以下错误

Could not deduce (Read a2) arising from a use of `read' from the context (Read a).

我认为,因为a Readable我可以推断它,但显然我错了。有什么想法吗?

修改 我已将之前的代码更改为

readsPrec _ r = [foo (read r :: a ), ""]

所以,如果我输入:read "myString" :: MyType a,它的效果非常好。 现在我希望如果我在上下文中使用read "myString",我就不必指定要读取的类型。但问题在于

bar (read myString) a

bar:: MyType a -> a -> MyType a,我得到了       Ambiguos变量类型

是否有可能在没有出现这种错误的情况下做同样的事情?

我希望现在更清楚了,我正在尝试简化代码,但我希望我没有省略任何关键的内容。

1 个答案:

答案 0 :(得分:6)

如果编写为

,代码实际上会进行类型检查
instance (Read a) => Read (MyType a) where
        readsPrec _ r = [(foo (read r),r)]

如果foo的类型为a -> MyType a。编译器可以从readsPrec的预期类型签名中找出对foo的调用应该返回MyType a,因此(通过foo的类型),表达式read r应该有a类型。

但是当你使用:: a注释时,它为什么会失败?因为类型变量是它们出现的类型签名的本地变量。所以a与实例heade中的a完全无关,而read r :: a实际上是这样的:表达式{ {1}}可以有任意类型。但是任意类型没有read r实例,因此出现错误消息。在消息中,编译器将内部Read重命名为a以避免名称冲突。

但是,如果将a2添加到模块标头,则代码可以按预期工作。现在,{-# LANGUAGE ScopedTypeVariables #-}中的a引用了实例标题中read r :: a的类型,一切顺利。

请注意,您没有正确使用readsPrec,但我想这不是问题的一部分。