2016-05-12 20 views
0

我知道,Haskell有paramaterized数据类型类型:限制一个类型Paramater可以采取在数据声明

data Maybe a = Nothing | Just a 

但是,有没有办法来限制排序是a可以表示类型?特别是,我想创建一个类型

data Tag a = Tag a 

这样a可以采取要么TagPrimitive类型TagComplex(但是,我不希望它是可能的,a是类型类型,例如,IntegerString或在我的程序中没有意义的东西)。

这可能吗?

+0

我想我有点困惑:为什么要有'Tag'类型呢?你是在寻找'type Tag = TagPrimitive TagComplex'(或者可能是'Tag Tag = Primitive TagPrimitive | Complex TagComplex') - 也就是一个* single *类型,它可以包含TagPrimitive或TagComplex的值类型 - 而不是? –

+0

是的,我很困惑,你说得对。你提到的这两种选择中哪一种更具惯用性? – George

+0

这取决于使用了一下。另请参阅[此问题](http://stackoverflow.com/q/19072930/791604),了解您为什么更喜欢自定义数据声明的一些讨论。 –

回答

4

你提出Tag类型是有点奇怪:它是一个参数化类型,其可以是专用的类型可以只有包含TagPrimitive s 可能是专门的类型,可以只有包含TagComplex s。但是这似乎有点无意义:我们已经有两种专门类型TagPrimitiveTagComplex来担任这两个角色。

相反,我建议您实际上想要的是一种可以包含任一类型值的单一类型。为此,我建议炮制新鲜的总和类型:

data Tag = Primitive TagPrimitive | Complex TagComplex 
    deriving (Eq, Ord, Read, Show) 

对于早期的原型,你可以使用规范的总和型,Either脱身,在

type Tag = Either TagPrimitive TagComplex 

,但我怀疑,作为您程序增长,这将成为increasingly bad choice

+0

但这种类型不告诉你,静态,这'TagPrimitive'或'的一个TagComplex'它包装,这可能是由OP是必需的。 – Cactus

+1

@Cactus正确。这就是为什么我在写这个答案之前就这个问题写了一个评论。但正如我在第一段中指出:在'TagPrimitive'和'TagComplex'类型本身确实是会保证做到这一点,静态,关于哪一个他们! –

7

你可以使用通常,单-Y方式:

{-# language GADTs #-} 

data Taggable a where 
    Primitive : Taggable TagPrimitive 
    Complex : Taggable TagComplex 

然后定义Tag

data Tag a where 
    Tag : Taggable a -> a -> Tag a 

那么当你发送一个给定Tag价值a,你可以匹配对单身人士:

f :: Tag a -> T 
f (Tag Primitive x) = ... - here, you know x :: TagPrimitive 
f (Tag Complex x) = ... -- here, you know x :: TagComplex 

或者,如@rampion在评论中提到,你可以折叠成TaggableTag,留给你

data Tag a where 
    Primitive :: TagPrimitive -> Tag TagPrimitive 
    Complex :: TagComplex -> Tag TagComplex