Haskell中类型的余积(不相交并集)的语法是什么?

Haskell中类型的余积(不相交并集)的语法是什么?,haskell,Haskell,考虑以下几点 data Point=Point{x::Float,y::Float} data Shape=Circle{centre::Point,radius::Float} |Rectangle {uleft::Point,bRight::Point} 这里的类型形状是圆形和矩形两种类型的副产品。我可能想在其他地方重用Circle和Rectangle类型。因此,这样做会很有用: data Point=Point{x::Float,y::Float} data Cir

考虑以下几点

data Point=Point{x::Float,y::Float}
data Shape=Circle{centre::Point,radius::Float}
           |Rectangle {uleft::Point,bRight::Point}
这里的类型形状是圆形和矩形两种类型的副产品。我可能想在其他地方重用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声明了两次。
尝试此操作的正确语法是什么?还是不可能?

这不是直接可能的,但您有几个选项。在本例中,我将使用由
DataKind
索引的
GADT

{-# 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

然后,当你想处理一般的形状时,你只需要使用
形状a
,如果你想要一个矩形或一个圆,你可以分别使用
形状矩形
形状圆

Haskell中类型的副产品通常用
表示:

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
尽管出于技术原因,这项工作还是相当不错的。另一种常见的方法是定义如下类型:

data Shape = CircleShape Circle | RectangleShape Rectangle
因此,
CircleShape::Circle->Shape
RectangleShape::Rectangle->Shape
是您的两个注射剂


正如你在问题中所做的那样,说原始的
形状
圆形
矩形
类型的副产品是错误的,因为后两种类型不是类型。如果你想将事物设置为
Circle p r
既是
Circle
类型的值,也是
Shape
类型的值,那么这确实与Haskell类型系统的精神背道而驰(尽管在足够多的类型系统扩展中可能会出现类似的情况)。

他们是值构造函数,对吗?我喜欢您的第一个解决方案,但它似乎不容易扩展,即四种类型中的三种类型的副产品。是的,值构造函数。第二种解决方案更易于扩展,因为您可以添加构造函数(也可以为它们提供更好的名称),并且基本上是相同的想法。请看: