haskell - 如何在 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’
解决方案
就像 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 中的类是不同的,它更像是一个接口,但比较不成立。
推荐阅读
- android - 在jetpack compose中创建视图和视图上创建替代品的片段?
- javascript - XMLHttp Javascript - 如何删除自动刷新
- plotly - 带有一个下拉列表和多个选择器的 Plotly Dash 散点图(全部)
- angular - 电容存储时序问题
- javascript - 如何在循环中执行事件,直到事件为真
- c# - C#:从数组中删除许多元素
- excel-2010 - 使用 excel 和 Visual Basic 每十秒计数一次
- python - Django 身份验证流程如何工作?【特例】
- node.js - find() 方法不适用于猫鼬中的异步函数
- java - JTable排序和渲染