13

次のことを考慮してください

data Point=Point{x::Float,y::Float}
data Shape=Circle{centre::Point,radius::Float}
           |Rectangle {uleft::Point,bRight::Point}

ここで、Shapeタイプは、CircleとRectangleの2つのタイプの余積です。CircleとRectangleのタイプを他の場所で再利用したいと思うかもしれません。したがって、代わりにこれを行うと便利です。

data Point=Point{x::Float,y::Float}
data Circle=Circle{centre::Point,radius::Float}
data Rectangle=Rectangle {uleft::Point,bRight::Point}
data Shape =Circle | Rectangle

しかし、これを行うとコンパイルエラーが発生します。Circleが2回宣言されています。これを試みるための正しい構文は何ですか、またはこれは不可能ですか?

4

2 に答える 2

17

Haskellのタイプの余積は、一般的に次のように表されEitherます。

data Either a b = Left a | Right b

type Shape = Either Circle Rectangle
-- so you have shapes as either Left c for some Circle c
-- or Right r for some Rectangle r

これは非常にうまく機能しますが、技術的な理由から、正確には副産物ではありません。もう1つの一般的な方法は、次のような型を定義することです。

data Shape = CircleShape Circle | RectangleShape Rectangle

そのためCircleShape :: Circle -> ShapeRectangleShape :: Rectangle -> Shape2回の注射です。

質問で言うように、オリジナルShapeはタイプCircleとの余積であると言うのは誤りRectangleです。後者の2つはタイプではないからです。型の値Circle p rと型の値の両方になるように設定したい場合、それはHaskellの型システムの精神に反しています(ただし、十分に多くの型システム拡張を使用すると、同様のことが可能になる場合があります)。CircleShape

于 2013-01-10T01:20:46.430 に答える
10

これは直接可能ではありませんが、いくつかのオプションがあります。この場合、:でインデックス付けされたインデックスGADTを使用します。DataKind

{-# LANGUAGE DataKinds, GADTs, KindSignatures #-}

data ShapeType = Circle | Rectangle

data Shape :: ShapeType -> * where
     CircleShape :: { centre :: Point, radius :: Float } -> Shape Circle
     RectangleShape { uleft :: Point, bRight :: Point } -> Shape Rectangle

次に、一般的な形状を処理する場合は常にShape a、を使用します。具体的に長方形または円が必要な場合は、それぞれShape Rectangleまたはを使用します。Shape Circle

于 2013-01-09T22:30:41.260 に答える