11

Haskellで新しいデータ型を定義するのに問題があります。

NumPair2つの整数、または整数と別の整数のいずれかを含むタプルになるデータ型を作成しようとしています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)))

タイプを改善するには、他に 2 つの方法があります。Haskell コンストラクターには複数のフィールドに対するサポートが組み込まれているため、タプルを使用するのではなく、次のようにコンストラクターで値を直接リストすることができます。

data NumPair = Pair Int Int | More Int NumPair deriving (Eq, Show)

それを改善するもう 1 つの方法は、空でないリストの型を記述したことを認識することです。空でないリストの最適な実装は、Data.List.NonEmptyここで見つけるsemigroupsことができるパッケージにあります。

次に、あなたのタイプは次のようになります。

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 に答える