Reputation: 19688
After reviewing this SO question I am trying to use the random number generator to return a random list item based on the return of the randomIO
generator.
Full Code:
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)
But I get the following errors:
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)
Why is the first error block wanting to expect a list of everything inside it?
What does the second code block mean?
Upvotes: 4
Views: 5506
Reputation: 4098
This answer offers a simple, effective solution to the problem posed in the title: "Get a random list item in Haskell".
The package Test.QuickCeck provides a number of helpful, straightforward functions for generating random values (http://hackage.haskell.org/package/QuickCheck-2.7.6/docs/Test-QuickCheck.html#g:5). A function that returns random values from a list (wrapped IO) can be built by composing the QuickTest functions elements
and generate
:
import Test.QuickCheck (generate, elements)
randItem :: [a] -> IO a
randItem = generate . elements
chris Frisina's function chooseRandomDecision
would then look like this:
chooseRandomDecision :: [ThreeHistoryDecisionMaker] -> IO ThreeHistoryDecisionMaker
chooseRandomDecision = randItem
The user Cale in the #haskell channel on freenode helped coach me to this solution.
note: This solution works with QuickCheck 2.7.6, but needs some alteration for earlier versions. You can update to the latest version with cabal install QuickCheck
. See this question.
Upvotes: 0
Reputation: 120711
randomIO
is not a "random function". Such a thing doesn't exist in Haskell, it wouldn't be referentially transparent. Instead, as the name suggests, it's an IO action which can yield a random value. It makes no sense to index a list with an IO action, !! randomIO(0,4)
isn't possible. (It's impossible also for another reason: randomIO
creates unlimited values, you want randomRIO
(with an R for "range parameter") if you need to specify a (0,4)
range.)
What you need to to do to get the value yielded by the action: well, monads! If you haven't learned the theory about those yet, never mind. A random-indexer could look thus:
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
I suggest you actually use that function to implement your task.
But back to the code you posted... there's more problems. If you specify the type of chooseRandomDecision
with two arguments, then you need to actually define it as a function of these arguments! But your definition doesn't accept any arguments at all, it merely uses the globally-defined list allThreeDecisionMakers
(use of global variables never needs to be stated in the type).
Moreover, if you're choosing from a list of THDMaker
s, then the resulting element will also have that type, what else! So unless Strategy3P
is simply another synonym of History -> History -> History -> Action
, this won't do as a result, even if you contain it in the right monad.
Upvotes: 13