我想创建一个类型来存储一些通用信息,对我来说,这种类型是 分子,我存储化学图和分子属性。
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 e.t.c.
问题是如何形成分子数据结构,因此我将能够在Molecule中收集任意数量的任何类型的属性。如果我做
data Molecule a = Molecule {
name :: Maybe String,
graph :: Gr Atom Bond,
property :: Maybe [Property a]
} deriving(Show)
当我创造一个分子时,我必须直接指定一种类型。
答案 0 :(得分:3)
如果您事先知道分子可能具有的属性集,则可以定义总和类型:
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
包装器,因为空列表已经编码了没有属性的情况。
答案 1 :(得分:0)
您可能希望查看Data.Dynamic的伪动态类型解决方案。