2

我刚刚开始在 Haskell 中定义自己的类型,我发现 http://www.haskell.org/haskellwiki/Type的第 3 节中 关于表示卡片的示例很有用。我想做一些事情,但我不知道如何实现它。我将尝试使用卡片类比进行解释。

我想使用不同的卡片集合。假设我们修复了卡总是有 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 牌组),它将一些牌组类型的牌组作为参数。我想你不能这样做,但我不知道。

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

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

4

1 回答 1

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 可以有效地“在运行时创建类型”,但对于初学者来说可能会感到困惑。

于 2012-12-20T02:45:21.673 回答