在Haskell中获取随机列表项

时间:2014-09-18 22:50:31

标签: haskell

reviewing this SO question之后我试图使用随机数生成器根据randomIO生成器的返回值返回一个随机列表项。

完整代码:

module Randomizer where
import System.IO
import System.Random

data Action = Create | Destroy
  deriving (Enum, Eq, Show)

type History = [Action]

-- | this looks at three sets of histories, and returns an appropriate Action
type ThreeHistoryDecisionMaker = History -> History -> History -> Action

allThreeDecisionMakers :: [ThreeHistoryDecisionMaker]
allThreeDecisionMakers = [decision1, decision2, decision3, decision4, decision5]

chooseRandomDecision :: [ThreeHistoryDecisionMaker] -> Int -> Strategy3P
chooseRandomDecision = allThreeDecisionMakers !! randomIO(0,4) 

但我收到以下错误:

special_program1.hs:249:16:
    Couldn't match type ‘Action’
                  with ‘History -> History -> History -> Action’
    Expected type: [[ThreeHistoryDecisionMaker] -> Int -> ThreeHistoryDecisionMaker]
      Actual type: [ThreeHistoryDecisionMaker]
    In the first argument of ‘(!!)’, namely ‘allThreeDecisionMakers’
    In the expression: all3PStrategies !! randomIO (0, 4)

special_program1.hs:249:35:
    Couldn't match expected type ‘(t0, t1) -> Int’
                with actual type ‘IO a0’
    The function ‘randomIO’ is applied to one argument,
    but its type ‘IO a0’ has none
    In the second argument of ‘(!!)’, namely ‘randomIO (0, 4)’
    In the expression: all3PStrategies !! randomIO (0, 4)

为什么第一个错误块想要预期其中的所有内容列表?

第二个代码块是什么意思?

2 个答案:

答案 0 :(得分:10)

randomIO a"随机函数"。这样的事情在Haskell中并不存在,它不会是引用透明的。相反,顾名思义,它可以产生一个随机值的 IO动作。使用IO操作索引列表是没有意义的,!! randomIO(0,4)是不可能的。 (由于其他原因,这也是不可能的:randomIO创建无限值,如果需要指定{randomRIO(使用R代表"范围参数") {1}}范围。)

你需要做什么才能通过动作获得产生的价值:嗯,monads!如果你还没有学过关于那些的理论,那就别管了。因此,随机索引器看起来如此:

(0,4)

我建议您实际使用该功能来实现您的任务。

但回到您发布的代码......还有更多问题。如果使用两个参数指定atRandIndex :: [a] -> IO a -- note that this is gives itself an IO action atRandIndex l = do i <- randomRIO (0, length l - 1) return $ l !! i 的类型,则需要将其实际定义为这些参数的函数!但是你的定义根本不接受任何参数,它只使用全局定义的列表chooseRandomDecision(全局变量的使用永远不需要在类型中声明)。

此外,如果您从allThreeDecisionMakers列表中进行选择,那么结果元素也将具有该类型,还有什么!因此,除非THDMaker只是Strategy3P的另一个同义词,否则即使您将其包含在正确的monad中,也不会这样做。

答案 1 :(得分:1)

这个答案为标题中提出的问题提供了一个简单有效的解决方案:“在Haskell中获取一个随机列表项目。”

Test.QuickCeck提供了许多有用的,直接的函数来生成随机值(http://hackage.haskell.org/package/QuickCheck-2.7.6/docs/Test-QuickCheck.html#g:5)。可以通过编写QuickTest函数elementsgenerate来构建从列表(包装的IO)返回随机值的函数:

import Test.QuickCheck (generate, elements)

randItem :: [a] -> IO a
randItem = generate . elements

克里斯弗里西娜的函数chooseRandomDecision将如下所示:

chooseRandomDecision :: [ThreeHistoryDecisionMaker] -> IO ThreeHistoryDecisionMaker
chooseRandomDecision = randItem

#haskell channel on freenode中的用户Cale帮我指导了这个解决方案。

注意:此解决方案适用于QuickCheck 2.7.6,但需要对早期版本进行一些更改。您可以使用cabal install QuickCheck更新到最新版本。请参阅this question