Call a function or build data at run time

Is it possible to create data at runtime? I mean something like the "read" function, but which applies [(field name, value)]. Let's say i have

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

I want to have a function like:

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

Therefore, I can use it as follows:

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

I don't need boilerplate code looking for something similar to the Reflection API for Java. You are currently browsing Data.Data and Data.Typeable modules, although you don't see how I can achieve this.

The purpose of all this is to create a binding between some data format and haskell data structures.

+4
source share
2 answers

Here is something close to what you are asking for.

 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"} 

Download this, and in ghci:

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

It seems to me that this is a lot for me. This is complicated because Haskell requires all types to be allowed at compile time; in this case, you are trying to create types with runtime information (for example, the string "Address"). It is possible, but you will struggle with the type system at every step. I agree with Jason that using a parser is probably the best approach.

+2
source

I think one problem with your area is that

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

all "arguments" must be of the same constructive type. So you need something in the lines

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

which I am not quite sure how to do this, I must admit.

Isn't it easier to just parse everything from a data format string?

0
source

Source: https://habr.com/ru/post/1333997/


All Articles