调用函数或在运行时构造数据

时间:2011-01-02 16:55:59

标签: haskell

是否有可能在运行时构建数据?我的意思是“读”功能,但适用[(字段名称,值)]。假设我有

data Street = Street String
data City = City String
data ZipCode = ZipCode String

data Address = Address {
      street :: Street,
      city :: City,
      zipCode :: ZipCode
} 

我想要一个像:

这样的功能
genericConstructor :: (DataConstructable a) => String -> [(String, a)] -> a

所以我可以这样使用它:

genericConstructor "Address" [("street", Street "Baker"), 
                              ("city", City "London"),
                              ("zipCode", ZipCode "12345")] :: Address

我不想要任何样板代码,寻找与Reflection API for Java类似的东西。 目前正在查看Data.Data和Data.Typeable模块,但看不到我如何实现它。

所有这一切的目的是在某些数据格式和haskell数据结构之间创建绑定。

2 个答案:

答案 0 :(得分:2)

这就是你所要求的东西。

import Data.Data
import Data.Dynamic
import Data.Maybe

data City = City String deriving (Data, Typeable, Show, Eq)
data Street = Street String deriving (Data, Typeable, Show, Eq)

data Addr = Addr {
  city :: City
 ,street :: Street} deriving (Show, Eq, Data, Typeable)

class Foo a where
  genericConstr :: [(String,Dynamic)] -> a

instance Foo Addr where
  genericConstr = buildAddr

lf ls nm = fromMaybe (error $ nm ++ " not found") (lookup nm ls >>= fromDynamic)

buildAddr ls = Addr {city = lf ls "city", street = lf ls "street"}

加载它,并在ghci:

*Foo> genericConstr [("street", toDyn (Street "Baker")), ("city", toDyn (City "London"))] :: Addr
Addr {city = City "London", street = Street "Baker"}

但这似乎对我来说很重要。这很棘手,因为Haskell要求在编译时解析所有类型;在这种情况下,您尝试使用运行时信息创建类型(例如字符串“Address”)。这是可能的,但你会在每一步都与类型系统作斗争。我同意Jason的说法,使用解析器可能是一种更好的方法。

答案 1 :(得分:0)

我认为你的一个问题是用

genericConstructor :: (DataConstructable a) => String -> [(String, a)] -> a

所有'参数'必须具有相同的可构造类型。因此,你需要的东西是

genericConstructor :: (DataConstructable a) => String -> [forall b. DataConstructable b => (String, b)] -> a

我不能完全确定怎么做,我必须承认。

从数据格式字符串中解析所有内容会不容易吗?