首页 > 解决方案 > 如何在 Haskell 中说 A 类型的数据也是 B 类型的数据?

问题描述

我正在学习haskell,并且在遵循思路时遇到了麻烦。我试图用 C++ 术语思考,但我无法在 Haskell 中找到 C++ 子类的等价物。我怎么说数据 B 也是简单结构 A 和 B 的数据 A?

背景:我至少读了三次LearnYouAHaskell。我能够编写基本的 Haskell 代码,但没有什么非常先进的,并且在 C++ 中工作经验丰富。

尝试:我试图将 A 定义为类型类并使 B 成为 A 的实例。但是,我不想编写方法/数据成员的新定义,只想使用 A 的定义. 我无法理解错误信息。

-- Trial.hs 

class A a where 
    data_member :: Int 

data B = B { 
    x :: Int 
}

instance A B;
Trial.hs:2:9: error:
    • Could not deduce (A a0)
      from the context: A a
        bound by the type signature for:
                   data_member :: A a => Int
        at Trial.hs:2:9-26
      The type variable ‘a0’ is ambiguous
    • In the ambiguity check for ‘data_member’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      When checking the class method: data_member :: forall a. A a => Int
      In the class declaration for ‘A’

标签: haskell

解决方案


就像 Damian 建议的那样,使用 Sum 类型:|类型运算符/构造函数。

使用 ADT(代数数据类型)是 Haskell 的一大优势。尽可能盲目地使用它们,我认为所有学习 haskell 的具有命令式背景的程序员都会得出同样的结论:ADT 非常有用和简洁。

来自 C++ 背景,当我第一次摸索 Sum 类型时,我在脑海中是这样将它翻译成 C++ 的:

data PureVirtualClassA = ConcreteClassB Member1 Member2 | ConcreteClassC Member3

其中 Member1、Member2 和 Member3 将是结构成员的类型。您可以简化这个例子,所有三个都是 Int:

data PureVirtualClassA = ConcreteClassB Int Int | ConcreteClassC Int

(如果你想要一个命名的数据成员,你应该去使用记录,但它们并不总是需要)

现在您可以在函数中使用它,就像使用 C++ 多态性一样,其中 ConcreteClassB 和 ConcreteClassC 将派生自 PureVirtualClassA:

myFunction :: PureVirtualClassA -> Int
myFunction (ConcreteClassB x y) = x + y
myFunction (ConcreteClassC z) = z

重要提示:在这些 C++ 程序员的示例中,我使用了具有 C++ 含义的类这个词!不要在 Haskell 中以这种方式使用 Class 一词。Haskell 中的类是不同的,它更像是一个接口,但比较不成立。


推荐阅读