ADT的集合,没有重复的构造函数

mcj*_*s45 1 haskell map set

如果我有数据类型:

data Component = PositionC Double Double | HealthC Double | NameC String
Run Code Online (Sandbox Code Playgroud)
  • 我想要一个Components 的集合
  • 我不会存储任何重复项(即:它不会有两个HealthC)
  • 我不想手动复制代码

我可以使用什么技术,数据结构,TemplateHaskell功能来满足上述标准?

我已经尝试过Data.Set和Data.Map但没有成功.

Data.Map尝试:

import Data.Map

data Component = PositionC Double Double | HealthC Double | NameC String

-- Unacceptable code duplication
data ComponentType = PositionCT | HealthCT | NameCT
    deriving (Eq, Ord)

type ComponentMap = Map ComponentType Component

foo :: ComponentMap
-- More annoying code duplication
foo = fromList [(HealthCT, HealthC 100), (NameCT, NameC "John")] 

fooHealth = foo ! HealthCT -- However, accessing works great
Run Code Online (Sandbox Code Playgroud)

Data.Set尝试:

import Data.Set (Set)
import qualified Data.Set as Set

data Component = PositionC Double Double | HealthC Double | NameC String
    deriving Eq

foo :: Set Component
foo = Set.fromAscList [HealthC 100, NameC "John"] -- This works well

-- But accessing elements is very bad
fooHealth = Set.elemAt 0 $ Set.filter p foo
    where p (HealthC _) = True
          p _           = False
Run Code Online (Sandbox Code Playgroud)

chi*_*chi 6

一个选项是使用带有可选字段的记录:

data Component = Component 
                 { positionC :: Maybe (Double, Double)
                 ; healthC :: Maybe Double 
                 ; nameC :: Maybe String
                 }
Run Code Online (Sandbox Code Playgroud)

直观地说,访问字段也比使用Set或更便宜Map.

设置字段

moveToOrigin c = c { positionC = Just (0,0) }
Run Code Online (Sandbox Code Playgroud)

得到一个领域

-- Requires health to be present
isDead c = fromJust (healthC c) == 0

-- If health is unknown returns False
saferIsDead c = health C == Just 0
Run Code Online (Sandbox Code Playgroud)