11

我无法在 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)

有人可以解释为什么这不起作用以及我应该怎么做吗?

4

2 回答 2

17

您需要为每个备选方案添加构造函数名称:

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.NonEmptysemigroups中,您可以在此处找到

然后你的类型就变成了:

type NumPair = NonEmpty Int

...并且您可以从该模块免费获得一堆非空列表上的功能。

编辑:nm 让我注意到你可能想要的是:

data NumPair = Pair (Int, Int) | More ((Int, Int), NumPair)

...相当于:

type NumPair = NonEmpty (Int, Int)

不同之处在于,后一个允许您附加整数对,而前一个跟随您的问题类型仅允许您附加整数。

于 2012-11-05T18:21:35.870 回答
5

你想要的是一个“真正的联合”类型,它在 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))))
于 2012-11-05T19:28:12.080 回答