从Haskell的列表中选择一个随机元素 [英] Pick a random element from a list in Haskell

查看:56
本文介绍了从Haskell的列表中选择一个随机元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的代码旨在创建一个单词搜索难题.有一个名为Orientation的数据表示拼图中每个单词的方向.

My code aims to create a word search puzzle. There is a data called Orientation representing the direction of each word in the puzzle.

data Orientation =
  Forward | Back | Up | Down | UpForward | UpBack | DownForward | DownBack
  deriving (Eq, Ord, Show, Read)

现在给定输入的字符串是 [String] ,我想为每个字符串随机分配一个方向,例如 [(Orientation,String)]

Now given a input of strings which is [String], I want to randomly assign each string an orientation like [(Orientation, String)]

assignWordDir :: [String] -> [(Orientation, String)]
assignWordDir [] = []
assignWordDir (s:strs) = (ori, s) : assignWordDir
                        where ori = pickOri [Forward, Back, Up, Down, UpForward, UpBack, DownForward, DownBack]

pickOri :: [a] -> IO a
pickOri xs = do
  i <- randomRIO (0, len)
  pure $ xs !! i
  where len = length xs - 1

我无法编译,因为 pickOri 的输出是 IO Orientation ,是否有关于如何修改代码的建议?非常感谢

I cannot compile because the output of pickOri is IO Orientation, is there any suggestions on how to modify my code? Thanks a lot

Couldn't match expected type ‘[(IO Orientation, String)]’
                  with actual type ‘[String] -> [(Orientation, String)]’

推荐答案

您可以考虑通过使用 RandomGen 参数来修改函数,以使它们保持纯净.例如,可以这样修改 pickOri 函数:

You might consider modifying the functions so that they stay pure by taking a RandomGen parameter. The pickOri function, for example, might be modified thusly:

pickOri :: RandomGen g => g -> [a] -> (a, g)
pickOri rnd xs =
  let len = length xs - 1
      (i, g) = randomR (0, len) rnd
  in (xs !! i, g)

有必要返回新的 RandomGen g 以及所选的列表元素,以便下次生成另一个伪随机数.

It's necessary to return the new RandomGen value g together with the selected list element, so that it'll generate another pseudo-random number the next time around.

同样,您可以像这样修改 assignWordDir :

Likewise, you can modify assignWordDir like this:

assignWordDir :: RandomGen g => g -> [b] -> [(Orientation, b)]
assignWordDir _ [] = []
assignWordDir rnd (s:strs) = (ori, s) : assignWordDir g strs
  where (ori, g) =
    pickOri rnd [Forward, Back, Up, Down, UpForward, UpBack, DownForward, DownBack]

请注意,当递归到 assignWordDir 时,递归函数调用将使用从 pickOri 接收到的 g .

Notice that when recursing into to assignWordDir, the recursive function call uses the g it receives from pickOri.

您可以使用 mkStdGen newStdGen 生成 RandomGen 值.这是使用 newStdGen 的示例:

You can use mkStdGen or newStdGen to produce RandomGen values. Here's an example using newStdGen:

*Q65132918> rnd <- newStdGen
*Q65132918> assignWordDir rnd ["foo", "bar", "baz"]
[(UpBack,"foo"),(Up,"bar"),(UpBack,"baz")]
*Q65132918> assignWordDir rnd ["foo", "bar", "baz"]
[(UpBack,"foo"),(Up,"bar"),(UpBack,"baz")]

请注意,当您使用相同 RandomGen 值时,将获得相同的序列.这是因为 assignWordDir 是一个纯函数,所以可以预期.

Notice that when you use the same RandomGen value, you get the same sequence. That's because assignWordDir is a pure function, so that's expected.

但是,您可以通过创建或获取新的 StdGen 值来产生新的随机序列:

You can, however, produce a new random sequence by creating or getting a new StdGen value:

*Q65132918> rnd <- newStdGen
*Q65132918> assignWordDir rnd ["foo", "bar", "baz"]
[(Up,"foo"),(Up,"bar"),(Forward,"baz")]

如果要在已编译的模块中使用此功能,则可以保留此处显示的这些功能,然后将它们与 newStdGen -生成的 StdGen 组合在一起.主要入口点.

If you want to play with this in a compiled module, you can keep these functions as presented here, and then compose them with a newStdGen-generated StdGen in the main entry point.

这篇关于从Haskell的列表中选择一个随机元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆