【问题标题】:Datatypes that are represented by a choice of one of many other datatypes通过选择许多其他数据类型之一表示的数据类型
【发布时间】:2017-01-17 01:51:02
【问题描述】:

我正在尝试为 Exploding Kittens 的玩具实现生成套牌。

假设我有以下类型:

data ActionCard = Skip 
  | Attack 
  | Shuffle 
  | Nope 
  | Future 
  | Defuse 
  | Favor
  deriving Enum

data BasicCard = TacoCat 
  | MommaCat 
  | Catermelon 
  | BearCat 
  | PotatoCat 
  | BikiniCat 
  | RainboRalphingCat
  deriving Enum

data Card = ActionCard | BasicCard | BombCard

type Deck = [Card]

还有一个像这样的甲板生成器功能:

generateDeck :: Int -> Deck
generateDeck players = (concat (map (replicate 5) [TacoCat ..])) 
  ++ (replicate 2 Nope)
  ++ (replicate 4 Skip)
  ++ (replicate 4 Attack)
  ++ (replicate 4 Shuffle)
  ++ (replicate 4 Future)
  ++ (replicate 1 Defuse)
  ++ (replicate 4 Favor)
  ++ (replicate (players + 1) BombCard)

这失败了:

Couldn't match expected type ‘[BasicCard]’
                    with actual type ‘a7 -> [a7]’
        Probable cause: ‘replicate’ is applied to too few arguments
        In the first argument of ‘(+)’, namely
          ‘replicate (length $ _players state)’
        In the second argument of ‘(++)’, namely
          ‘(replicate (length $ _players state) + 1 BombCard)’

(以及其他非基本卡的类似错误)

这在某种程度上是有道理的,因为(concat (map (replicate 5) [TacoCat ..])) 返回一个[BasicCard],但是我希望函数签名强制使用更通用的类型?

如何允许Card 成为ActionCardBasicCardBombCard

【问题讨论】:

  • data Card = ActionCard | BasicCard | BombCard 并不意味着 Card 将是 Attack, ... , RainboRalphingCat 之一 - 而是创建三个 new 数据构造函数恰好与三个现有类型具有相同的名称。
  • 可能是data Card = Action ActionCard | Basic BasicCard | Bomb BombCard,那么您必须将[TacoCat ..] 更改为map Basic [TacoCat..] 并将Nope 更改为(Action Nope) 等等...

标签: haskell types algebraic-data-types


【解决方案1】:
data Card = ActionCard | BasicCard | BombCard

这将创建一个新的数据类型Card,其中包含三个构造函数,分别称为ActionCardBasicCardBombCard。这与称为ActionCardBasicCard 的其他两种数据类型无关;类型和构造函数的命名空间是不同的。

您要做的是将Card 定义为包含ActionCardBasic BasicCardBombCardAction

data Card = Action ActionCard | Basic BasicCard | BombCard

然后您可以通过将每种卡片类型包装在其正确的构造函数中来制作您的Deck

generateDeck :: Int -> Deck
generateDeck players = basics ++ actions ++ bombs
  where
    cats = concatMap (replicate 5 . Basic) [TacoCat ..]
    actions = map Action . concat $
              [ replicate 2 Nope
              , replicate 4 Skip
              , replicate 4 Attack
              , replicate 4 Shuffle
              , replicate 4 Future
              , replicate 1 Defuse
              , replicate 4 Favor
              ]
    bombs = replicate (players + 1) BombCard

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多