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

卓美

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

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

现在给定一个字符串输入[String],我想随机分配每个字符串一个方向,例如[(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

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

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

您可能会考虑修改函数,以便通过获取RandomGen参数使它们保持纯净pickOri例如,可以函数进行如下修改:

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)

必须将新RandomGeng与选定的列表元素一起返回,以便下次将生成另一个伪随机数。

同样,您可以这样修改assignWordDir

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递归到时,递归函数调用将使用从g接收的pickOri

您可以使用mkStdGennewStdGen产生RandomGen值。这是一个使用示例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是一个纯函数,所以这是预料之中的。

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

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

如果要在已编译的模块中使用此功能,则可以保留此处显示的这些功能,然后入口点将其与newStdGen-generatedStdGen一起使用main

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章