1

假设有一个所有可能事物的列表

all3PStrategies :: [Strategy3P]
all3PStrategies = [strategyA, strategyB, strategyC, strategyD]  //could be longer, maybe even infinite, but this is good enough for demonstrating

现在我们有另一个函数,它接受一个整数N和两个策略,并使用第一个策略进行N次数,然后使用第二个策略进行N次数,并根据需要继续重复。
如果N是 0 会发生什么,我想返回一个随机策略,因为它破坏了函数的目的,但它必须最终应用特定策略。

rotatingStrategy [] [] _ = chooseRandom all3PStrategies
rotatingStrategy strategy3P1 strategy3P2 N =
  | … // other code for what really happens

所以我试图从列表中获得一个随机策略。我认为这会做到:

chooseRandom :: [a] -> RVar a

但是如何使用 Haddock/doctest 对其进行测试?

--  >>> chooseRandom all3PStrategies
--      // What goes here since I cant gurauntee what will be returned...?

我认为随机函数有点违背 Haskell 的函数思想,但我也可能错了。在命令式语言中,随机函数使用各种参数(如 Java 中的时间)来确定随机数,所以我不能只插入一个/特定参数来确保我会得到哪个随机数吗?

4

2 回答 2

2

如果您这样做:chooseRandom :: [a] -> RVar a,那么您将无法使用IO. 您需要能够在IO整个类型声明中包含 monad,包括测试用例。

说得更清楚一点,一旦你使用了IOmonad,所有的返回类型都必须包含IOmonad 的类型,这个类型不太可能包含在你想要返回的列表中,除非你编辑列表的结构来容纳那些包括IO类型。

于 2014-09-30T13:43:23.103 回答
1

有几种方法可以实现chooseRandom。如果您使用返回的版本RVar Strategy3P,您仍然需要对RVarusing进行采样runRVar以获得Strategy3P您可以实际执行的版本。

您也可以使用IOmonad 解决问题,这实际上没有什么不同:与其将其chooseRandom视为返回概率分布的函数,我们可以根据需要对其进行采样,我们可以将其视为返回计算的函数,我们可以根据需要进行评估。根据您的观点,这可能会使事情或多或少令人困惑,但至少它避免了安装 rvar 包的需要。chooseRandomusing的一种实现是this blog postIO中的函数:pick

import Random (randomRIO)

pick :: [a] -> IO a
pick xs = randomRIO (0, (length xs - 1)) >>= return . (xs !!)

这段代码可以说是有问题的:当你给它一个空列表时,它会在运行时崩溃。如果您担心这一点,您可以在编译时通过将结果包装在 中来检测错误Maybe,但如果您知道您的策略列表永远不会为空(例如,因为它是硬编码的),那么它可能不值得打扰.

很可能它也不值得测试,但有许多基本问题的解决方案,即如何测试单子函数。换句话说,给定一个单子值m a,我们如何在我们的测试框架中查询它(理想情况下通过重用对原始值起作用的函数a)?这是QuickCheck库和相关研究论文“使用 QuickCheck 测试 Monadic 代码”中解决的一个复杂问题)。

但是,将 QuickCheck 与 doctest 集成看起来并不容易,而且问题实在是太简单了,无法证明投资一个全新的测试框架是合理的!鉴于您只需要一些快速而肮脏的测试代码(实际上不会成为您应用程序的一部分),unsafePerformIO在这里使用可能没问题,即使许多 Haskeller 会认为它是代码异味:

{-|
>>> let xs = ["cat", "dog", "fish"]
>>> elem (unsafePerformIO $ pick xs) xs
True
-}
pick :: [a] -> IO a

只要确保你理解为什么使用unsafePerformIO是“不安全的”(它通常是不确定的),以及为什么它对这种情况并不重要(因为标准 RNG 的失败并不是一个足够大的风险,因为这个应用程序,以证明我们需要在类型系统中捕获它所需的额外工作)。

于 2014-09-18T04:21:57.010 回答