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:
lookupFunc :: String -> ???
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:
data SpecFunc = Result String | More (String -> SpecFunc)
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:
class HasSpecFunc a where
toSpecFunc :: a -> SpecFunc
instance (Read a, HasSpecFunc b) => HasSpecFunc (a -> b) where
toSpecFunc f = More (\input -> toSpecFunc (f (read input)))
... -- one of these for each one of your "primitive" result types
instance HasSpecFunc String where
toSpecFunc x = Result (show x)
Using some evil you can avoid having to specify one instance per result type. At the top of the file, enable overlapping instances:
{-# LANGUAGE OverlappingInstances #-}
Then use:
instance (Show a) => HasSpecFunc a where
toSpecFunc x = Result (show x)
Then you can call a SpecFunc with something like:
-- returns Nothing if the wrong number of arguments were provided
runSpecFunc :: SpecFunc -> [String] -> Maybe String
runSpecFunc (Result x) [] = Just x
runSpecFunc (More f) (x:xs) = runSpecFunc (f x) xs
runSpecFunc _ _ = Nothing
I hope that made sense. But again, ditching the XML and using Haskell instead is far preferable to this.