当我遇到困难时,我才开始玩哈斯克尔。
我正在尝试创建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变量类型。
是否有可能在没有出现这种错误的情况下做同样的事情?
我希望现在更清楚了,我正在尝试简化代码,但我希望我没有省略任何关键的内容。
答案 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,但我想这不是问题的一部分。