我会推荐 Nathan 的建议,即使用 Haskell 作为规范语言。 Haskell 本身是使用 Haskell 函数的最佳数据格式:-)
但由于这是一个有趣的问题,我会假设您由于某种奇怪的限制而不得不使用 XML。您将不得不在某处将您的 XML 转换为真正的 Haskell 函数。这意味着有一些映射:
lookupFunc :: String -> ???
按名称查找函数。您必须手动编写此映射,或使用 Template Haskell 生成它。但重要的是,??? 不是类型,这个函数需要一个真实的类型。
这是一个简洁的列表,类似于您的异构列表,但更针对手头的问题进行了优化:
data SpecFunc = Result String | More (String -> SpecFunc)
这是您对 XML 规范的接口。它说要么我已经完成并且已经有了一个结果(已经被字符串化),要么我需要另一个参数来继续(从字符串转换到该函数中)。 (令人讨厌的旁注:这被称为“free monad over (String ->)”——但 monadiness 与我们现在完全无关)。
现在我们可以编写一个类型类来将 Haskell 函数转换为它们的 SpecFunc,如果它们的类型符合我们的标准:
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)
使用一些邪恶的方法可以避免必须为每个结果类型指定一个实例。在文件顶部,启用重叠实例:
{-# LANGUAGE OverlappingInstances #-}
然后使用:
instance (Show a) => HasSpecFunc a where
toSpecFunc x = Result (show x)
然后你可以调用一个 SpecFunc 类似的东西:
-- 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
我希望这是有道理的。但同样,放弃 XML 并改用 Haskell 比这要好得多。