【问题标题】:haskell make (class a) instance of other class'haskell make (class a) 其他类的实例'
【发布时间】:2011-09-25 10:38:15
【问题描述】:

又是 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编程基础上的一个漏洞;所以我真的很想了解这一点,而不是解决任何作业。

注意:标签是有理数 - 这使得插入和搜索比使用自然数或整数标签更容易。

提前致谢!

【问题讨论】:

  • 我认为eval 的类型不是您想要的。它太笼统了,因为它承诺适用于任何a,只要它在Num 中。

标签: class haskell types


【解决方案1】:

您的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 约束来自Integer。密切注意最后一点:这是类型类背后的原因。 Num a =&gt; 约束确保,给定 a,我们知道我们可以在其上使用任何 Num 实例方法。

另一个问题是相反的问题:您正在调用show,但您没有做任何事情来确保showa 上有意义。

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

【讨论】:

    【解决方案2】:

    Num 的实例定义的问题是你说你正在展示 任何ExprTreeNum 的实例(意味着任何类型a),而是 你展示了ExprTree Integer 如何是 Num 的一个实例。换句话说,你不能 除非您想像这样声明您的实例,否则专门化该类型变量 这个:

    instance Num (ExprTree Integer) where 
        ...
    

    Show 实例有一个类似的问题。你没有展示如何 ExprTree a 是任意 a 的 Show 实例,您正在展示它 仅适用于已经是 Show 实例的 as。换句话说,你会 需要像这样更改您的实例声明:

    instance (Show a) => Show (ExprTree a) where
         ...
    

    为了让它工作。

    Eval 实例声明中的第三个错误来自无关的东西 相当平凡,基本上你正在使用 a -> e -> e 类型的函数,并且 您正在返回第一个参数a。 Haskell 很困惑,因为你已经 鉴于没有迹象表明 ae 是同一类型,所以没有理由 它应该接受 a 类型的值作为返回类型。 (这可能只是一个案例 你有点困惑。 eval 有签名 (Num e)=> e -> a -> a,但是您在实例声明中将第一个变量命名为 a Val a.)

    所以,除了第三个实例声明之外,您的问题似乎是您 向 Haskell 承诺,您将为一个类型声明一个类型类的实例 非常通用的类型(例如 ExprTree a 用于任何 a),但随后你违背了你的 承诺要求a 是更具体的类型,例如Integer

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-09
      • 1970-01-01
      • 2015-05-30
      • 1970-01-01
      • 2022-07-28
      • 1970-01-01
      相关资源
      最近更新 更多