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

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

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递归到 to 时,递归函数调用使用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-generated组合它们。StdGenmain


以上是从Haskell的列表中随机选择一个元素的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>