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数据结构之间创建绑定.

最佳答案 这是你要求的东西.

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的说法,使用解析器可能是一种更好的方法.

点赞