再次Haskellers& Haskellettes,
我仍有问题,我真的不知道何时使用(Class a) => a
,Type
或
Type a
其中Type是“联合类型”,例如Val
和ExprTree
现在我想通过添加几个实例使我的数据类型ExprTree
更加通用:
import Ratio
data Fun = Add|Sub|Mul|Div|Pow
deriving (Eq,Ord)
instance Show Fun where
show Add = "+"
show Sub = "-"
show Mul = "*"
show Div = "/"
show Pow = "^"
type Label = Rational
type Var = String
class Eval e where
eval :: (Num a) => e -> a -> a
data ExprTree a = Leaf {lab::Label, val::Val a}
| Node {lab::Label, fun::Fun, lBranch::ExprTree a, rBranch::ExprTree a}
deriving(Eq,Ord)
data Val a = Num a | Var String deriving (Eq, Ord, Show)
instance (Num a) => Num (ExprTree a) where
...
fromInteger i = Leaf (0%1) i -- <--error
instance Show (ExprTree a) where
show (Leaf l a) = show a -- <-- error
show (Node l f lb rb) = (show lb)++" "++(show l)
++(show f)++" "++(show rb)++"\n"
instance Eval (Val a) where
eval (Var v) n = n
eval a _ = a -- <-- error
我认为这个问题 - 都是一样的。并且在一个非常简单的环境中理解类和类型等之间的差异 - 是我的haskell编程基础上的漏洞;所以我真的很想理解这不是为了解决任何作业。
注意:标签是一个Rational - 这使得插入和搜索比使用自然数或整数标记更容易。
提前致谢!
答案 0 :(得分:2)
Num
的实例定义问题在于您说您正在展示
任何ExprTree
是Num
的实例(对于任何类型a
而言意义),而是如何
你展示ExprTree Integer
是一个Num的实例。换句话说,你不能
如果除非你想声明你的实例,否则专门化那个类型变量
这样:
instance Num (ExprTree Integer) where
...
Show实例有一些类似的问题。你没有表现出如何
ExprTree a
是任意a
的显示实例,您正在显示它
仅适用于已显示Show的a
s。换句话说,你会的
需要像这样更改你的实例声明:
instance (Show a) => Show (ExprTree a) where
...
为了使其发挥作用。
Eval实例声明中的第三个错误来自不相关的东西
而且相当平凡,基本上你正在采用类型a的功能 - &gt; e - &gt; e和
你正在返回第一个参数a
。哈斯凯尔很困惑,因为你已经
鉴于没有迹象表明a
和e
属于同一类型,因此没有理由
它应该接受a
类型的值作为返回类型。 (这可能只是一个案例
你有点困惑。 eval
具有签名(Num e)=&gt; e - &gt; a - &gt;
a,但是您已在实例声明中为您的第一个变量a
命名
Val a
。)
因此,排除第三个实例声明,您的问题似乎就是您
有希望Haskell你将为a声明一个类型类的实例
非常一般的类型(对于任何ExprTree a
都是a
),但是你背叛了你的。{
承诺要求a
是更具体的类型,例如Integer
答案 1 :(得分:2)
fromInteger
的问题是i
需要转换为Val a
。
instance Num a => Num (ExprTree a) where
-- ...
fromInteger i = Leaf (0%1) (Val (fromInteger i))
Val
包装器使其成为Val
;内部fromInteger
创建一个a
,这是一个调用者指定的类型,我们知道可以使用fromInteger
来创建Num a
约束来自{{1} }}。密切关注最后一个:这是类型类背后的原因。 Integer
约束确保在给定Num a =>
的情况下,我们知道我们可以使用任何a
实例方法。
另一个问题是相反的问题:您正在调用Num
,但是您没有采取任何措施来确保show
对show
有意义。
a
instance Show a => ExprTree a where
show (Leaf _ a) = show a -- this works now because we told it a is show-able
-- ...
的问题略有不同:Eval
只显示没有任何来源,因此编译器对此一无所知。特别是,a
要求eval a _ = a
是有效e
- 但a
是未知的,因此编译器正确地说“什么?”。对于这个你需要考虑你真正想要做的事情;最简单的解决方案是放弃a
并在任何地方使用e
,但这真的是你想要的吗?