2011-01-26 75 views
9

是否有方法为值构造函数的参数定义类约束?在值构造函数中指定类约束

事情是这样的:

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

使点可以采用任何参数,只要他们属于民课吗?

+0

一般来说,最好将您的类型约束放在实际需要的地方。这不是数据类型,而是需要Num类型的方法,所以应该在那里声明。类型系统将负责其余部分。 – amccausl 2011-01-27 06:45:58

回答

11

您可以使用ExistentialQuantificationGADTs,但都不会做你想要的。您将永远无法使用两个Point2D值进行算术运算。所有你知道的内容是,他们是一些 Num的实例。您正在告诉编译器放弃关于它们的所有其他信息。这意味着您要告诉编译器放弃任何可能具有的信息,即一对Point2D值包含相同的类型。如果没有这些信息,您将无法对两个Point2D的值进行任何算术运算。

这几乎肯定不是你想要的。例如,你不能写一个distance函数。对于这种有限的类型你有什么可能的用途?关于你所能做的所有事情是把他们的内容转换为String

编辑:

我想我明白你在做什么。你只是想确保Point2D中的所有内容都是一个数字。我不认为你真的想要类型擦除。

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

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

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

但我认为这里最重要的不是丢弃内容的类型。这样做使得该类型基本上不可能合作。

+0

为数据成员恢复实例上下文似乎只在数据类型(使用`(Point a b)`或使用记录字段名称`Point {x = a,y = b}`)进行模式匹配时才起作用。但有什么办法可以让这个字段访问功能?也就是说,当用像`(x p)`这样的表达式来访问`Point`` p`时。 – Lii 2016-06-09 14:14:49

4

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

通常情况下,像仿制药type Foo a = (a, a)意味着

为各类aFoo a由两a

然而,在你的榜样,需要短语是不同的:

对于索姆e型aPoint2D由两a

一个类型aPoint2D

因此,通用的类型不是通用(适用于所有类型...),但是存在(它存在某种类型...)。在GHC,我们可以通过extenstion

{-# ExistentialQuantification #-} 

在本article on the topic描述允许这样。您的代码,毕竟是

data Point2D = forall a . Num a => Point a a 
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,但你不能做后它的模式匹配的数据什么。