在值构造函数中指定类约束

时间:2011-01-26 21:32:17

标签: haskell constructor functional-programming

有没有办法为值构造函数的参数定义类约束?

这样的事情:

data Point2D = (Num a) => Point a a

这样只要Point属于Num类,它就可以接受任何参数吗?

4 个答案:

答案 0 :(得分:11)

您可以使用ExistentialQuantificationGADTs,但两者都不会按照您的意愿行事。您永远无法使用两个Point2D值进行算术运算。你对内容的所有了解都是他们的一些实例。您告诉编译器丢弃有关它们的所有其他信息。这意味着您告诉编译器丢弃它可能具有的特定一对Point2D值包含相同类型的任何信息。如果没有这些信息,您将无法对两个Point2D的值进行任何算术运算。

这几乎肯定不是你想要的。例如,您无法编写distance函数。对于如此有限的类型,您可以使用什么?关于你可以用它们做的所有事情是将它们的内容转换为String

编辑:

我想我知道你要做什么。您只想确保Point2D中的所有内容都是数字。我不认为你真的想要类型擦除。

在这种情况下,我会选择GADT版本,其中有一个非常重要的变化:

{-# LANGUAGE GADTs #-}
data Point2D a where
    Point :: (Num a) => a -> a -> Point2D a

这样做的最终结果是,您只能将Point构造函数与两个相同Num实例的值一起使用,但不会丢失类型。此外,由于使用GADTsPoint构造函数上的模式匹配为您恢复了Num上下文,这基本上是您所期望的。

但我认为这里最重要的不是扔掉内容的类型。这样做使得这种类型基本上无法使用。

答案 1 :(得分:4)

是的,,但您必须意识到约束的含义与通常的泛型类型不同。

通常,type Foo a = (a, a)中的泛型意味着

  所有类型的

aFoo a由两个a组成

但是,在您的示例中,需要以不同的方式表达:

  

对于某些类型 aPoint2D由两个a组成

  

<{1}} aPoint2D组成

因此,泛型类型不是通用(适用于所有类型......),但存在(它存在某种类型......)。在GHC下,我们可以通过扩展来实现这一目标

{-# ExistentialQuantification #-}

如此article on the topic中所述。毕竟,你的代码是

data Point2D = forall a . Num a => Point a a

答案 2 :(得分:2)

当然!

这应该做你想要的:

{-# LANGUAGE GADTs #-}

data Point2D a where
    Point :: Num a => a -> a -> Point2D a

p :: Num a => a -> a -> Point2D a
p = Point

sumP :: Point2D a -> Point2D a -> a
sumP (Point a b) (Point c d) = a + b + c + d

你也可以使用existensials,但是在模式匹配后你不能对数据做任何事情。

答案 3 :(得分:1)

{-# LANGUAGE GADTs #-}
data Point2D where
    Point :: (Num a) => a -> a -> Point2D

这是generalised algebraic datatype