再次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 编程基础上的一个漏洞;所以我真的很想理解这一点,而不是为了解决任何作业。
注意:标签是有理数 - 这使得插入和搜索比使用自然数或整数进行标签更容易。
提前致谢!
最佳答案
您的 fromInteger
的问题是 i
需要转换为 Val a
。
instance Num a => Num (ExprTree a) where
-- ...
fromInteger i = Leaf (0%1) (Val (fromInteger i))
Val
包装器使其成为 Val
;内部 fromInteger
创建一个 a
,它是调用者指定的类型,我们知道可以使用 fromInteger
创建它,因为 从
约束)。请密切注意最后一点:这是类型类背后的原因。 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
并在各处使用 a
,但这真的是您想要的吗?
关于class - haskell make(a类)其他类的实例',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6526017/