Haskell 无法推断(b~a)
我有下面的代码,我正试图为解释器编写一个抽象语法树,&我不想把所有内容都塞进同一个Haskell 无法推断(b~a),haskell,Haskell,我有下面的代码,我正试图为解释器编写一个抽象语法树,&我不想把所有内容都塞进同一个数据类型,所以我打算编写一个具有基本行为的typeclass(在本例中是AST) 当我在typeclassAST中删除reduce的默认实现时,它可以很好地编译,但当我提供一个返回它自己的实现时,它会抱怨。我得到以下编译器错误 src/Data/AbstractSyntaxTree.hs:13:18: Could not deduce (b ~ a) from the context (AST a)
数据类型,所以我打算编写一个具有基本行为的typeclass(在本例中是AST
)
当我在typeclassAST
中删除reduce
的默认实现时,它可以很好地编译,但当我提供一个返回它自己的实现时,它会抱怨。我得到以下编译器错误
src/Data/AbstractSyntaxTree.hs:13:18:
Could not deduce (b ~ a)
from the context (AST a)
bound by the class declaration for `AST'
at src/Data/AbstractSyntaxTree.hs:(11,1)-(13,20)
or from (AST b)
bound by the type signature for reduce :: AST b => a -> Env -> b
at src/Data/AbstractSyntaxTree.hs:12:13-36
`b' is a rigid type variable bound by
the type signature for reduce :: AST b => a -> Env -> b
at src/Data/AbstractSyntaxTree.hs:12:13
`a' is a rigid type variable bound by
the class declaration for `AST'
at src/Data/AbstractSyntaxTree.hs:11:11
In the expression: ast
In an equation for `reduce': reduce ast _ = ast
AST
的reduce
行为将评估AST
,偶尔返回不同类型的AST
,有时返回相同类型的AST
编辑:关于所有a的数据表达式。AST a=>Expr a
&GADT
s
我最初使用的是dataexpr=forall a。AST a=>Expr a
,因为我想表示这样的类型
(+ 2 true) -> Compound [Expr (Ref "+"), Expr 2, Expr true]
(+ a 2) -> Compound [Expr (Ref "+"), Expr (Ref "a"), Expr 2]
(eval (+ 2 2)) -> Compound [Expr (Ref "eval"),
Compound [
Expr (Ref "+"),
Expr 2,
Expr 2]]
((lambda (a b) (+ a b)) 2 2) -> Compound [Expr SomeLambdaAST, Expr 2, Expr 2]
因为我是从文本生成AST的,所以我觉得在GADT中表示严格类型的AST是一个负担,尽管我确实看到它们在Haskell中的DSL这样的情况下有何用处
但由于我是从文本生成AST(可能包含上面的一些示例),所以可能有点难以预测我最终会得到什么AST。我也不想在和
s&之间玩杂耍,也许
s。这就是我上次所做的&那是一场混乱&我放弃了在哈斯克尔尝试这一点
但是我又不是最有经验的Haskell程序员,所以也许我看错了,也许我可以用更严格的打字来实现AST,所以我会看一看,看看我是否能想出GADT,但我有疑问&我有一种感觉,它可能会像上次那样结束
最终,我现在只是想通过一个有趣的、可完成的项目来学习Haskell,所以我不介意我的第一个Haskell项目是否真的不是地道的Haskell。让某些东西发挥作用是一个更高的优先事项,这样我就可以在语言中找到自己的路,并为它展示一些东西
更新:
我采纳了@cdk&@bheklir的建议,抛弃了存在主义类型,尽管我选择了一种更简单的类型,而不是使用GADTs(也由@cdk&@bheklir建议)。它可能是一个更强的类型,但我只是想熟悉Haskell,所以我在几个小时后放弃了&使用了一个简单的数据类型,如:P
import qualified Data.Map as M
type Environment = [M.Map String AST]
data AST
= Compound [AST]
| FNum Double
| Func Function
| Err String
| Ref String
data Function
= NativeFn ([AST] -> AST)
| LangFn [String] AST
-- previously called reduce
eval :: Environment -> AST -> AST
eval env ast = case ast of
Ref ref -> case (lookup ref env ) of
Just ast -> ast
Nothing -> Err ("Not in scope `" ++ ref ++ "'")
Compound elements -> case elements of
[] -> Err "You tried to invoke `()'"
function : args -> case (eval env function) of
Func fn -> invoke env fn args
other -> Err $ "Cannot invoke " ++ (show other)
_ -> ast
-- invoke & lookup are defined else where
尽管我可能仍然会关注gadt,因为它们看起来非常有趣&这让我找到了一些关于在haskell中实现抽象语法树的有趣阅读材料。您在理解错误消息的哪一部分方面有困难?我想这很清楚
reduce
的类型为
reduce :: AST b => a -> Env -> b
第一个参数的类型为a
,GHC希望reduce
返回b
类型的内容,这可能与a
完全不同。GHC抱怨您试图返回值a
,而它期望b
,这是正确的
“类型类的存在量化”是一种反模式(如贝克利尔所指出的)。更好的方法是为AST
创建代数数据类型:
data AST a
现在reduce
变成了一个简单的函数:
reduce :: Env -> AST a -> AST b
如果希望reduce
能够返回不同类型的AST
,可以使用或
reduce :: Env -> AST a -> Either (AST a) (AST b)
但我不认为这是你真正想要的。我的建议是查看创建AST的GADT
风格,并重新评估您的方法。您在理解错误信息的哪一部分方面有困难?我想这很清楚
reduce
的类型为
reduce :: AST b => a -> Env -> b
第一个参数的类型为a
,GHC希望reduce
返回b
类型的内容,这可能与a
完全不同。GHC抱怨您试图返回值a
,而它期望b
,这是正确的
“类型类的存在量化”是一种反模式(如贝克利尔所指出的)。更好的方法是为AST
创建代数数据类型:
data AST a
现在reduce
变成了一个简单的函数:
reduce :: Env -> AST a -> AST b
如果希望reduce
能够返回不同类型的AST
,可以使用或
reduce :: Env -> AST a -> Either (AST a) (AST b)
但我不认为这是你真正想要的。我的建议是查看创建AST的GADT
风格,并重新评估您的方法。您的默认实现无法编译,因为它的定义错误
reduce :: AST b => a -> b -> Env -> b
reduce ast _ = ast
现在,ast
具有类型a
,reduce函数返回类型b
,但根据您的实现,您返回类型为a
的ast
,但编译器需要b
即使是这样的事情也能奏效:
reduce :: AST b => a -> b -> Env -> b
reduce _ ast _ = ast
默认实现无法编译,因为它的定义错误
reduce :: AST b => a -> b -> Env -> b
reduce ast _ = ast
现在,ast
具有类型a
,reduce函数返回类型b
,但根据您的实现,您返回类型为a
的ast
,但编译器需要b
即使是这样的事情也能奏效:
reduce :: AST b => a -> b -> Env -> b
reduce _ ast _ = ast
您错误地解释了此类型签名(以OO程序员常见的方式):
这并不意味着reduce可以选择它喜欢的任何类型(即AST的成员)并返回该类型的值。如果是这样,您的实现将是有效的。相反,这意味着对于调用者喜欢的任何类型b(即AST的成员),reduce必须能够返回该类型的值。b有时很可能与a相同,但这是呼叫者的选择,而不是reduce的选择
如果您的实现返回类型为a的值,那么只有当b始终相等时,这才是真的