1

我想创建一个类型来存储一些通用信息,至于我,这种类型是 Molecule,我存储化学图和分子特性。

data Molecule = Molecule {
     name :: Maybe String,
     graph :: Gr Atom Bond,
     property :: Maybe [Property] -- that's a question
} deriving(Show)

我想表示为元组的属性

type Property a = (String,a)

因为属性可能有任何类型:Float、Int、String 等


问题是如何形成 Molecule 数据结构,因此我将能够在 Molecule 中收集任意数量的任何类型的属性。如果我做

data Molecule a = Molecule {
     name :: Maybe String,
     graph :: Gr Atom Bond,
     property :: Maybe [Property a]
} deriving(Show)

当我创建一个分子时,我必须直接指定一种类型。

4

2 回答 2

3

如果您事先知道一个分子可能具有的一组属性,您可以定义一个 sum 类型:

data Property = Mass Float | CatalogNum Int | Comment String

如果您希望这种类型是可扩展的,您可以使用 Data.Dynamic 作为另一个答案所建议的。例如:

data Molecule = Molecule { name :: Maybe String,
                           graph :: Gr Atom Bond,
                           property :: [(String,Dynamic)]
                         } deriving (Show)

mass :: Molecule -> Maybe Float
mass m = case lookup "mass" (property m) of
           Nothing -> Nothing
           Just  i -> fromDynamic i

您还可以摆脱“字符串类型”(String,a)对,例如:

-- in Molecule: 
--   property :: [Dynamic]

data Mass = Mass Float

mass :: Molecule -> Maybe Mass
mass m = ...

这些尝试都没有比仅仅解析成对提供更多的类型安全性,(String,String)因为没有办法强制用户创建格式良好的属性的不变量(缺少将属性包装在新类型中并将构造函数隐藏在另一个模块中,这又是破坏可扩展性)。

您可能想要的是 Ocaml 风格的多态变体。您可以查看Vinyl,它提供类型安全的可扩展记录。

顺便说一句,您可能希望摆脱Maybe属性列表的包装,因为空列表已经编码了没有属性的情况。

于 2013-07-24T15:57:47.543 回答
0

您可能想查看Data.Dynamic以获得伪动态类型解决方案。

于 2013-07-24T15:48:00.133 回答