Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell GHCI可以';在编译时不能推断Eq类,但在运行时可以吗?_Haskell - Fatal编程技术网

Haskell GHCI可以';在编译时不能推断Eq类,但在运行时可以吗?

Haskell GHCI可以';在编译时不能推断Eq类,但在运行时可以吗?,haskell,Haskell,对不起,标题很混乱。为了好玩,我正在Haskell中编写一个解析器组合器库。以下是所有(我想!)相关的类型注释和定义: data Parser a = Parser (State -> Reply a) parse :: Parser a -> [Char] -> Either ParseError a nil :: Parser [a] nil = Parser $ \state -> Ok [] state 基本上,parse函数将解析器所包装的函数应用于当前状

对不起,标题很混乱。为了好玩,我正在Haskell中编写一个解析器组合器库。以下是所有(我想!)相关的类型注释和定义:

data Parser a = Parser (State -> Reply a)

parse :: Parser a -> [Char] -> Either ParseError a

nil :: Parser [a]
nil = Parser $ \state -> Ok [] state
基本上,
parse
函数将
解析器所包装的函数应用于当前状态,如果解析成功,则将结果包装为
nil
解析器获取一个状态并返回对空列表的成功解析。所以我们应该

事实上,如果我只是加载所有这些活动的模块,那么它将编译并计算为True

不过,我实际上正在尝试对库运行一些快速检查测试,所以我写了以下内容:

import Parsimony
import Test.QuickCheck

prop_nil :: [Char] -> Bool
prop_nil xs = parse nil xs == Right []
这无法编译!它抛出以下错误:

No instance for (Eq a0) arising from a use of `=='
The type variable `a0' is ambiguous

在这一点上,我很困惑为什么一个表达式在评估时可以很好地工作,但是不能在一个参数化的版本中编译。

因为nIL/COD>是多态的,<代码>右[]/COD>也是多态的,GHC有一个表达式:<代码> BOOL ,但是中间有一些未绑定的类型变量。由于GHC不知道使用哪种混凝土,所以它的龙骨会断裂并死亡。GHCi无论好坏,都会根据其默认规则推断出
[()]
或类似的结果。这是ghci的一个奇怪的怪癖,它将自动默认类型变量

要解决此问题,只需手动强制绑定
a

-- It's important that whatever you force it to actually is comparable
-- eg there should be an instance like
instance Eq ParseError where
-- Otherwise you're kinda stuck.

prop_nil xs = parse nil xs == (Right xs :: Either ParseError String)

PS我喜欢解析器库的名字“简约”,祝你好运

问题是
nil
的类型是
Parser[a]
。因此,
parse nil xs
的类型是
ParseError[a]
Right[]
通常为l[a]
类型;将其与
parse nil xs
进行比较会强制
l
ParseError
,但列表中的类型仍然完全不受约束。没有更多的上下文,它仍然是完全多态的;
a
不一定是
Eq
类型类的成员,即使是,也无法知道使用哪个实例来实现
=
,因此在这两个术语上调用
=
是无效的

在一个现实的程序中,你很可能会从中解脱出来,因为你会将结果用于某些事情,这将迫使特定的事件与你使用它的目的一致。这可能是某种具体的类型,它具有
Eq
的实现

当您谈到加载模块时,我想您的意思是在GHCI解释器中。GHCI添加了一些额外的默认规则。特别是,它倾向于将无约束类型变量(不是顶级函数的类型)默认为
()
,这样就不必经常抱怨不明确的类型变量

GHCi中的交互式会话往往比完整编译的实际模块更容易遇到不明确的类型变量,因为它必须独立编译小片段。GHCi扩展了默认规则,以使这些规则更频繁地工作(尽管它通常只会在用户期望不同类型时将错误延迟到下一个引用,并且GHCi和GHC之间的差异通常会导致混淆)

测试片段可能会遇到类似的问题。如果您正在测试多态函数,您通常不会像在真正有目的地使用函数时那样,对某些类型进行充分的约束,以使类型推理能够工作。但是,如果没有GHCi的扩展默认规则,这个问题在问题所在的位置表现为实际的不明确类型错误,而不是通过任意选择类型来掩盖它

要解决这个问题,您只需要添加一个类型注释来修复列表的类型。声明
parse nil xs
Right[]
的完整类型,只需声明右侧空列表文本的类型。像这样的事情应该能奏效:

prop_nil :: [Char] -> Bool
prop_nil xs = parse nil xs == Right ([] :: [Int])

另一种方法是首先避免Eq约束:

prop_nil xs = either (const False) null (parse nil xs) 
或者,更明确一些

prop_nil xs = case parse nil xs of
   Right [] -> True
   _        -> False

parse nil xs
的类型为
ParseError a
。它没有说
a
在任何地方都有一个
Eq
实例。如果我将
parse
的类型签名更改为
parse::Eq a=>Parser a->[Char]->parserror a
@Cardano:那么它可以推断出无论
a
是什么,它都有一个
Eq
的实例,但它仍然不知道什么是
a
;这就是它抱怨的原因。好吧,这是有道理的。仅“保证”GHC两个多态值的类型是
Eq
的实例是不够的,因为它需要能够相互比较它们。有没有一种方法可以跨类型注释定义类型变量的范围,这样您就可以告诉编译器这里的多态类型与那边的多态类型相同,并且它还实现了
Eq
?您能澄清一下您的意思吗,哪两个类型变量需要统一吗?平等的左右两边将统一起来。强制GHC统一2个表达式类型的最简单方法是在函数中使用它们,这将强制它们统一。Prelude的功能是
asTypeOf
,正是出于这个目的,最好避免使用文本类型,例如
Right([]:[Int])
,或者
解析错误字符串
。有没有一种方法可以声明像
[]:[a1]
这样的东西,其中编译器知道
a1
引用与
parse(nil::Eq a1=>Parser[a1])xs中变量
a1
相同的类型?@Cardano问题是在某个点上
a1
必须绑定到一个具体的类型。如果你在某个时候不给它一个,GHC猜不出它应该是什么,这就是为什么你必须给它一些(任意的)类型
prop_nil xs = case parse nil xs of
   Right [] -> True
   _        -> False