I’m currently working on a Haskell project which automatically tests some functions based on an XML specification. The XML specification gives the arguments to each function and the expected result that the function will provide (the arguments are of many different types). I know how to extract the function arguments from the XML and parse them using the read function, but I haven’t figured out how to invoke the function using the arguments I get out.
What I basically want is to read and store the arguments in a heterogeneous list (my current thinking is to use a list of type Data.Dynamic) and then invoke the function, passing this heterogeneous list as its argument list. Is this possible? Modifying the functions under test is not an option.
I would recommend Nathan’s suggestion of using Haskell as the spec language. Haskell itself is the best possible data format for working with Haskell functions 🙂
But since it’s an interesting question, I’ll pretend that you, by some bizarre constraint, have to use XML. You are going to have to convert your XML to a real Haskell function somewhere. That means having some mapping:
Which looks up a func by name. You will have to write this mapping by hand, or generate it using Template Haskell. But importantly,
???is not a type, and this function needs a real type.Here’s a neat one, similar to your heterogeneous list but more optimized to the problem at hand:
This is your interface to the XML specification. It says that either I am done and already have a result (which has already been stringified) or I need another argument to continue (with the conversion from string baked into that function). (Geeky side note: this is called the “free monad over (String ->)” — but the monadiness is quite irrelevant to us right now).
Now we can write a typeclass to convert Haskell functions into their SpecFuncs, if their types meet our criteria:
Using some evil you can avoid having to specify one instance per result type. At the top of the file, enable overlapping instances:
Then use:
Then you can call a SpecFunc with something like:
I hope that made sense. But again, ditching the XML and using Haskell instead is far preferable to this.