haskell make(class a)其他类的实例'

时间:2011-06-29 19:19:37

标签: class haskell types

再次Haskellers& Haskellettes,

我仍有问题,我真的不知道何时使用(Class a) => aTypeType a其中Type是“联合类型”,例如ValExprTree

现在我想通过添加几个实例使我的数据类型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 - 这使得插入和搜索比使用自然数或整数标记更容易。

提前致谢!

2 个答案:

答案 0 :(得分:2)

Num的实例定义问题在于您说您正在展示 任何ExprTreeNum的实例(对于任何类型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。哈斯凯尔很困惑,因为你已经 鉴于没有迹象表明ae属于同一类型,因此没有理由 它应该接受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,但是您没有采取任何措施来确保showshow有意义。

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,但这真的是你想要的吗?