从列表中选择一个随机元素

时间:2018-10-19 11:47:47

标签: haskell functional-programming

所以在我的项目中,我有一个常量函数,它返回一个数组:

import System.Random

giveList :: [Int]
giveList = [8,9,4,5,2]

,我想从该列表中随机选择一个元素,如下所示:

seed::Int
seed = 40

generator = mkStdGen seed

giveRandomElement :: Int
giveRandomElement = giveList !! rand where
    n = length tetrominoes
    (rand,generator) = randomR (0,(n-1)) generator

但是,由于生成器,它不能编译,我想将生成器保留为全局变量,这样就不必继续将其提供给函数。 我也不想处理IO包装器,那么我可以用什么方式呢?

寻求帮助:-)

2 个答案:

答案 0 :(得分:7)

工作代码示例

import System.Random

seed::Int
seed = 40

giveList :: [Int]
giveList = [8,9,4,5,2]

generator = mkStdGen seed

giveRandomElement :: Int
giveRandomElement = giveList !! rand where
  n = length giveList
  (rand, _) = randomR (0,(n-1)) generator

但这可能不起作用,您想要什么。

giveRandomElement将始终产生相同的结果。它是一个纯函数,没有任何输入,因此该怎么办?它只能是常数。

您要么需要使用IO,要么需要使生成器遍历代码并在某个位置进行跟踪。

您遇到的编译器错误:

test.hs:14:23: error:
    • Ambiguous type variable ‘g0’ arising from a use of ‘randomR’
      prevents the constraint ‘(RandomGen g0)’ from being solved.
      Relevant bindings include generator :: g0 (bound at test.hs:14:10)
      Probable fix: use a type annotation to specify what ‘g0’ should be.
      These potential instance exist:
        instance RandomGen StdGen -- Defined in ‘System.Random’
    • In the expression: randomR (0, (n - 1)) generator
      In a pattern binding:
        (rand, generator) = randomR (0, (n - 1)) generator
      In an equation for ‘giveRandomElement’:
          giveRandomElement
            = giveList !! rand
            where
                n = length giveList
                (rand, generator) = randomR (0, (n - 1)) generator
   |
14 |   (rand, generator) = randomR (0,(n-1)) generator
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^

是因为您在generator中用术语定义了符号giveRandomElement 它本身,因此编译器无法推断其类型。 (在这种情况下,未使用顶级声明generator,因为(rand, generator) =已经在等号后加上了阴影。

答案 1 :(得分:3)

  

我想将生成器保留为全局变量,因此不必一直将其提供给函数。我也不想处理IO包装器,那么我可以用什么方式呢?

对不起,函数giveRandomElement :: Int每次调用都不返回referentially transparent 时返回一个不同的随机数,因此Haskell的纯度不是允许您做自己想做的事。

我认为使用随机值是了解monad的绝好机会。 MonadRandom具有非常灵活的界面,可用于编写结果随机的函数:

die :: (MonadRandom m) => m Int
die = getRandomR (1, 6)

rollDice :: (MonadRandom m) => m (Int, Int)
rollDice = do
    x <- die
    y <- die
    return (x, y)

-- Your example
giveRandomElement :: (MonadRandom m) => m Int
giveRandomElement = do
    let n = length tetrominoes
    i <- getRandomR (0, n-1)
    return (giveList !! i)

此monad的实现将通过您的随机函数为您随机化随机状态。甚至还有instance MonadRandom IO,可以让您编写

main :: IO ()
main = do
    x <- giveRandomElement
    print x