【问题标题】:Haskell - class vs typeclass - what is the differenceHaskell - 类与类型类 - 有什么区别
【发布时间】:2011-09-25 07:52:50
【问题描述】:

你好 Haskellers 和 Haskellettes,

我已经在 Haskell 上摆弄了很长一段时间,但是我无法完全掌握这个类的概念。在以下示例中,我的数据类型为 ExprTree

data Val a = Num a | Var String deriving (Eq, Ord, Show)
data ExprTree = Leaf {lab::Label, val::(Val a)=> a}
          | Node {lab::Label, fun::Fun, lBranch::ExprTree, rBranch::ExprTree}
          deriving(Eq,Ord)

导致

Type constructor `Val' used as a class In the definition
of data constructor `Leaf' In the data type declaration for `ExprTree'

我也试过了

data ExprTree' = Leaf {lab::Label, val::Val}
         ...

但随机更改类型签名 - 听起来既不高效也不提供启发。

现在据我所知Num a 表示 Num 类的东西,但这不是数据类型的实例 - 并且不允许我编译。 那么我必须做什么才能使ExprTree 定义明确。

提前感谢您的提示和想法!


编辑

1) 感谢您的快速解答!

2) 我将val::(Val a)=>a 更改为val::Val a

我有类似的想法 - 但随后出现错误:Not in scope type variable a 发生 你还有什么建议吗??

【问题讨论】:

  • 注意答案包括左侧的类型变量adata ExprTree a = ...
  • 伙计,有时我比一块石头还笨 - 谢谢 ;-)

标签: class haskell types


【解决方案1】:

如果您来自 OOP 语言,一些简单的规则可能会帮助您适应:

  1. 当 Haskellers 谈到类或类型类时,这有点像 OOP 语言中的接口或特征。
  2. LHS 上出现的数据 ... = ... 隐约类似于抽象超类。您实际上无法创建一个,但您可以声明该类型的参数。
  3. RHS 上出现的数据 ... = ... 与特定的子类有点相似。
  4. 当您要求参数属于类型类时,该参数位于 => 的 LHS 上,如 Num t => t。

现在,这些都不完全正确,如果你停在这里,但粗略的想法确实帮助我站稳了脚跟。

【讨论】:

    【解决方案2】:

    你的问题已经解决了,但我看到你使用 GHC,有时——尤其是在开始时——Hugs 错误消息可能更容易阅读,在这种情况下:

    数据类型声明中的语法错误(意外的`=>')

    这实际上可能已经让您初步了解在哪里寻找。请注意,我并不是在这里提倡拥抱而不是 GHC,但作为一个 Haskell 初学者,我认为前者提供了更多有用的错误消息。

    【讨论】:

      【解决方案3】:

      正确的类型是

      data Val a = Num a | Var String deriving (Eq, Ord, Show)
      data ExprTree a = Leaf {lab::Label, val :: Val a}
                | Node {lab::Label, fun::Fun, lBranch::ExprTree a, rBranch::ExprTree a}
                deriving(Eq,Ord)
      

      由于类型Val 需要一个额外的类型参数,所以每次使用时都需要提供一个*。我使用了一个类型变量,就像在最初的定义中一样;这要求变量也被命名为ExprTree 的参数。 (其他可能性是使用具体类型,例如IntMaybe String 等,或者使用存在类型;在这里都没有意义。)

      您实际使用的是类型类上下文(“类”只是“类型类”的简写)。 Val 是一个类型,而不是一个类型类,所以它在那里是不合法的。

      * 这并不完全正确;你需要一种*。 kinds 是类型的类型:Int has kind *Val a has kind *Val has kind * -> *。也就是说,Val 本身就是一个类型函数,它需要一个参数才能成为一个完整的类型。

      【讨论】:

      • 从技术上讲,Val 甚至不是一个type,而是一个type constructor,或者一个简单的类型函数。
      【解决方案4】:

      回答标题中的问题:在谈到 Haskell 时,“class”这个词几乎总是用来表示“typeclass”,因为这是 Haskell 中唯一的类。所以没有区别。

      回答你身体里的问题:

      data ExprTree a =
          Leaf {lab::Label, val::(Val a)}
          | Node {lab::Label, fun::Fun, lBranch::(ExprTree a), rBranch::(ExprTree a)}
          deriving(Eq,Ord)
      

      (Val a)=>a 没有意义,因为Val 不是类型类,你不能只在类型定义的右侧引入类型类约束(无论如何都没有扩展 - 无论哪种方式都不是你想要的)。

      【讨论】:

        【解决方案5】:

        错误指向这部分类型定义:

        val::(Val a)=> a
        

        此语法的意思是,“对于类型类Val 的任何实例aval 的值属于a 类型。”但是(1)Val 不是类型类,(2)a 类型似乎是凭空出现的。

        你可能想说的是

        data Val a = Num a | Var String
                   deriving (Eq, Ord, Show)
        data ExprTree a = Leaf { val :: Val a }
                        | Node { lBranch :: ExprTree a, rBranch :: ExprTree a }
                        deriving (Eq, Ord)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-10-02
          • 2014-12-25
          • 1970-01-01
          • 2010-12-11
          • 1970-01-01
          • 2011-07-07
          • 1970-01-01
          相关资源
          最近更新 更多