Haskell:带参数的类型(编辑:又名依赖类型)

时间:2012-12-19 23:53:34

标签: haskell types set

我刚开始在Haskell中定义自己的类型,我在第3节中找到了这个例子 http://www.haskell.org/haskellwiki/Type 关于代表卡有用。有一些我想做的事情,我不知道如何实现它。我会尝试解释使用卡片类比。

我想使用不同的卡片集合。假设我们确定卡片总是有CardValue和Suit,但是除了标准系列之外,我还想允许一个有第五套“红宝石”的套牌。我希望能够做一些事情,比如Kind1和Kind2,并定义一种卡片Kind3,它尽可能适合Kind1和Kind2的套装,以及卡片套装来自Kind1的套装。我还想编译一个程序,用户可以在其中输入套装的名称等,然后我们可以使用她输入的卡片执行一些标准的卡片操作。 我不想做的只是写出有限数量的不同数据类型,因为我事先并不知道我的不同种类的卡会是什么

我可以想象一个涉及大量列表和大量检查的解决方案,看看事情是列表的元素,但我想这将是一个噩梦,写作效率很低。

让我写一些不起作用的伪代码,但可能会比我上面的描述更好地理解我想要做的事情。

-- this isn't real code!

type Suit = [String]
type CardValue = [String]

data (Card s v) = (Card s v) {suit :: (s :: Suit), value :: (v :: CardValue)}

usualSuit :: Suit
usualSuit = ["Club","Diamond","Heart","Spade"]

flowerSuit :: Suit
flowerSuit = ["Rose","Daisy","Poppy"]

当然我知道这是胡说八道,我想它违背了编译时所有类型的原则(我可以看到这是一个很好的原则)。

任何人都可以告诉我:

  • 有没有办法做我正在描述的事情?
  • 有没有更好的方法来实现同样的目标?

我也对链接​​/关键字有兴趣阅读,但请注意,我不太了解编程术语,甚至不了解Haskell。

我确实想用Haskell来做这个 - 懒惰的评估和无限列表对我来说非常有用,而且我已经编写了代码来做事。

我尝试使用谷歌搜索并查看一些Haskell教程(我还是初学者!)但是没有发现任何有用的东西。这可能是因为我不知道要搜索什么词。

由于

编辑:我担心我没有解释我想要做的事情。这里有一些真正的代码,编译时没有错误,注释可以解释我希望它做什么。

import Data.List

type Suit = String
type Value = Integer
type ListOfSuits = [Suit]
type ListOfValues = [Value]

data Deck = Deck {listofsuits :: ListOfSuits, listofvalues :: ListOfValues } deriving (Show)

sillyDeck :: Integer -> Deck
-- This is some function.  For example, we might have
sillyDeck n = Deck ["Heart","Spade"] [1..n]
-- Note that this defines infinitely many different decks

-- How should I define a card in sillyDeck n?  One option is
data Card = Card {suit :: Suit, value :: Value } deriving (Show)
-- but this doesn't reference the deck I'm using.  I could try
data Card2 = Card2 {suit2 :: Suit, value2 :: Value, deck2 :: Deck } deriving (Show)
-- but then
cardInWrongDeck :: Card2
cardInWrongDeck = Card2 "Cheese" 999 (sillyDeck 3)
-- is valid, when I'd hope for something like a type error.
-- Of course, I could write a function to check that each card is in the
-- deck it claims to be, and apply it regularly, but that's a horrible solution.

-- Is there a better way to do this?

希望这也解释了我的标题:我想定义一个类型(CardOfType套牌),它采用Deck类型的甲板作为参数。我想你不能这样做,但我不知道。

我想要做什么(基本上,有一组对象,每个对象都是一组对象)似乎是一个基本的东西 - 我敢打赌人们之前遇到过类似的问题,我希望有一些很好的结构方式来解决这个我不知道的事情。

编辑2:基于Philip JF指向GADT(=广义代数数据类型)并做一些阅读,我意识到我所寻找的东西被称为“依赖类型” 。所以我的原始标题“带参数的类型”听起来并不那么荒谬。似乎这些在Haskell中不存在。我找到了关于模拟它们的论文,并阅读了有关类型函数的Ωmega。我仍然不知道是否存在一种具有将值作为参数的类型的语言。

1 个答案:

答案 0 :(得分:3)

如果您愿意使用高级功能,Haskell的类型系统几乎可以做任何事情,但我会在学习Haskell时尽早使用大部分内容。在你的情况下,我可能会这样建模

data Card s v = Card {suit :: s, value :: v}

然后定义像

这样的套装
data UsualSuit = Club | Diamond | Heart | Spade deriving
data FlowerSuit = Rose | Daisy | Poppy

这可以满足您的大部分需求。例如,很容易定义像

这样的复合套装
data Rubies = Rubies
type UsualOrRubies = Either UsualSuit Rubies

我认为这完全解决了您在静态情况下的需求。如果您有一个动态输入套装的用户,事情会更复杂。一种选择是“串型”

type StringySuit = String

您可以使用GADTs执行某些操作,但除非您提供问题的更大示例,否则我不知道基于String的解决方案会出现什么问题。它实际上可以使用GADT有效地“在运行时创建类型”,但它可能会让初学者感到困惑。