有没有办法为值构造函数的参数定义类约束?
这样的事情:
data Point2D = (Num a) => Point a a
这样只要Point属于Num类,它就可以接受任何参数吗?
答案 0 :(得分:11)
您可以使用ExistentialQuantification
或GADTs
,但两者都不会按照您的意愿行事。您永远无法使用两个Point2D
值进行算术运算。你对内容的所有了解都是他们Point2D
值包含相同类型的任何信息。如果没有这些信息,您将无法对两个Point2D
的值进行任何算术运算。
这几乎肯定不是你想要的。例如,您无法编写distance
函数。对于如此有限的类型,您可以使用什么?关于你可以用它们做的所有事情是将它们的内容转换为String
。
编辑:
我想我知道你要做什么。您只想确保Point2D中的所有内容都是数字。我不认为你真的想要类型擦除。
在这种情况下,我会选择GADT版本,其中有一个非常重要的变化:
{-# LANGUAGE GADTs #-}
data Point2D a where
Point :: (Num a) => a -> a -> Point2D a
这样做的最终结果是,您只能将Point
构造函数与两个相同Num实例的值一起使用,但不会丢失类型。此外,由于使用GADTs
,Point
构造函数上的模式匹配为您恢复了Num上下文,这基本上是您所期望的。
但我认为这里最重要的不是扔掉内容的类型。这样做使得这种类型基本上无法使用。
答案 1 :(得分:4)
是的,,但您必须意识到约束的含义与通常的泛型类型不同。
通常,type Foo a = (a, a)
中的泛型意味着
所有类型的
a
,Foo a
由两个a
组成
但是,在您的示例中,需要以不同的方式表达:
对于某些类型
a
,Point2D
由两个a
组成
或
<{1}}
a
由Point2D
组成
因此,泛型类型不是通用(适用于所有类型......),但存在(它存在某种类型......)。在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