我刚开始在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。我仍然不知道是否存在一种具有将值作为参数的类型的语言。
答案 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有效地“在运行时创建类型”,但它可能会让初学者感到困惑。