【问题标题】:Whats the syntax for the coproduct (disjoint union) of types in Haskell?Haskell中类型的协积(不相交联合)的语法是什么?
【发布时间】:2013-01-09 22:06:08
【问题描述】:

考虑以下

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

这里的 Shape 类型是 Circle 和 Rectangle 两种类型的联产品。我可能想在其他地方重用 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 被声明了两次。 尝试这个的正确语法是什么,或者这不可能?

【问题讨论】:

标签: haskell


【解决方案1】:

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

虽然出于技术原因it isn't exactly a coproduct,但效果非常好。另一种常见的方法是定义一个像这样的类型:

data Shape = CircleShape Circle | RectangleShape Rectangle

所以CircleShape :: Circle -> ShapeRectangleShape :: Rectangle -> Shape 是你的两次注射。

在您的问题中说原始ShapeCircleRectangle 类型的副产品是错误的,因为后两者不是类型。如果你想设置 Circle p r 既是 Circle 类型的值又是 Shape 类型的值,那么这真的与 Haskell 类型系统的精神背道而驰(尽管类似的东西可能有足够的可能许多类型系统扩展)。

【讨论】:

  • 它们是值构造函数,对吧?我喜欢你的第一个解决方案,但它似乎不容易扩展,这是四种类型中的三种的副产品。
  • 是的,值构造函数。第二种解决方案更易于扩展,因为您只需添加构造函数(也可以为它们想出更好的名称),并且几乎是相同的想法。
【解决方案2】:

这不是直接可能的,但您有几个选择。在这种情况下,我会使用由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

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

【讨论】:

    猜你喜欢
    • 2012-12-24
    • 1970-01-01
    • 1970-01-01
    • 2013-10-17
    • 1970-01-01
    • 2020-03-10
    • 2022-11-03
    • 2012-01-15
    • 1970-01-01
    相关资源
    最近更新 更多