【问题标题】:Invoke Haskell function with heterogeneous arguments?使用异构参数调用 Haskell 函数?
【发布时间】:2010-03-13 02:57:58
【问题描述】:

我目前正在开发一个 Haskell 项目,该项目会根据 XML 规范自动测试一些功能。 XML 规范为每个函数提供了参数以及函数将提供的预期结果(参数有许多不同的类型)。我知道如何从 XML 中提取函数参数并使用 read 函数解析它们,但我还没有弄清楚如何使用我得到的参数调用函数。

我基本上想要的是读取并将参数存储在异构列表中(我目前的想法是使用 Data.Dynamic 类型的列表),然后调用函数,将此异构列表作为其参数列表传递。这可能吗?修改被测函数不是一种选择。

【问题讨论】:

  • 是否可以使用 Haskell 作为规范语言而不是 XML?缺点是测试规范必须链接到源。 (并且您的规范必须在编译时而不是运行时输入良好......)
  • 嗯,也许吧。这当然是我没有考虑过的想法。谢谢。

标签: xml haskell types


【解决方案1】:

我会推荐 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 比这要好得多。

【讨论】:

  • 当然,如果您的参数和结果具有更多的结构,而不仅仅是可转换为字符串,则可以将其替换为 String 和 typeclasses 以在此处为 Read/Show 转换为该表示。
【解决方案2】:

一般来说,使用 Data.Dynamic 是个坏主意,因为您牺牲了 GHC 为您检查参数的能力。您几乎总是知道类型必须支持的有效函数,因此您可以始终使用存在类型的列表。

相反,是否可以构建一个数据类型来表示您的 XML 将生成的有效类型?也就是说,构建一个表示格式良好的 XML 参数的抽象语法的 ADT。

例如,查看 JSON ADT:http://hackage.haskell.org/packages/archive/json/0.4.3/doc/html/src/Text-JSON-Types.html#JSValue

或者,使用存在类型来(静态地)确保值支持您为它们声明的方法。例如,您的 XML 中的所有值可能都必须支持 Show,因此您可以将异构列表描述为:

data XMLList = forall a.显示一个 => XMLList [a])

来自 Haskell wikibook 的示例:http://en.wikibooks.org/wiki/Haskell/Existentially_quantified_types#Example:_heterogeneous_lists

【讨论】:

  • 那么如何将这种类型的列表作为参数列表传递给函数呢?
  • 存在主义在这里一无所获。 XMLList 与 [String] 同构,因此只需使用 [String]。
猜你喜欢
  • 1970-01-01
  • 2013-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-07
  • 1970-01-01
  • 2015-06-25
  • 2017-10-04
相关资源
最近更新 更多