我在Haskell中定义新数据类型时遇到了麻烦。
我正在尝试创建一个数据类型NumPair
,它将是一个包含两个整数,或整数和另一个NumPair
的元组。
例如,(2, 2), (0, 5), (1, (2, 3)) and (0, (4, (3, 121)))
应该都有效NumPairs
。
这是我为了尝试这样做而编写的代码:
data NumPair = (Int, Int) | (Int, NumPair) deriving (Eq, Show)
有人可以解释为什么这不起作用,而我应该做什么呢?
答案 0 :(得分:15)
您需要为每个替代方案添加构造函数名称:
data NumPair = Pair (Int, Int) | More (Int, NumPair) deriving (Eq, Show)
这些构造函数名称允许您在数据类型上进行模式匹配,如下所示:
f :: NumPair -> A
f (Pair (x, y )) = ...
f (More (x, np)) = ...
然后,您可以使用构造函数构建一个值(这就是它们被称为构造函数的原因):
myNumPair :: NumPair
myNumPair = More (1, More (2, Pair (3, 4)))
还有其他两种方法可以改善您的类型。 Haskell构造函数内置了对多个字段的支持,因此您可以直接在构造函数中列出值,而不是使用元组,如下所示:
data NumPair = Pair Int Int | More Int NumPair deriving (Eq, Show)
您可以改进的另一种方法是识别您刚刚为非空列表编写了类型。非空列表的最佳实现位于Data.List.NonEmpty
包的semigroups
,您可以find here。
然后你的类型就变成了:
type NumPair = NonEmpty Int
...你可以在非空列表上获得一堆免费的模块功能。
修改:n.m。引起我的注意,你可能想要的是:
data NumPair = Pair (Int, Int) | More ((Int, Int), NumPair)
......相当于:
type NumPair = NonEmpty (Int, Int)
不同之处在于后一个允许你追加整数对,其中前一个跟随你的问题的类型只允许你追加整数。
答案 1 :(得分:4)
你想要的是一种“真正的联合”类型,它在Haskell中不存在。 Haskell仅提供标记的联合,其中程序员必须将附加信息附加到所有数据。使用真正的工会与被标记的工会有一些权衡;我不会试图以某种方式卖给你。但是,可以通过使用提供真正联合类型的语言(例如Typed Racket)来完全按照需要定义类型。
#lang typed/racket
(define-type Num-Pair
(Rec R
(U (Pair Integer Integer)
(Pair Integer R))))
(: foo Num-Pair)
(define foo '(0 . (4 . (3 . 121))))