gpt4 book ai didi

haskell - 如何在 haskell 中使用 newStdGen 或 getStdGen 而不是 mkStdGen

转载 作者:行者123 更新时间:2023-12-03 14:24:20 30 4
gpt4 key购买 nike

试图解决problem 23 99 个 Haskell 问题。

我写了这个

rnd_select :: (Eq a) => [a] -> Int -> [a]
rnd_select [] _ = []
rnd_select _ 0 = []
rnd_select ys n =
let
(rnd_index, gen) = randomR (1, length ys) (mkStdGen 200)
(x, xs) = removeAt rnd_index ys
in x : rnd_select xs (n-1)

哪个有效,但我不想使用 mkStdGen 但使用
  newStdGen or getStdGen

反而。
我已经看到了问题的解决方案,但我想了解我应该如何修复这段代码来做到这一点,如果不可能,为什么不呢,因为直觉上感觉它应该可以工作,但事实并非如此。

最佳答案

请记住,Haskell 函数是纯函数;给定相同的输入,它们必须始终返回相同的结果。你可以让你的函数返回 IO [a]相反,这会让您调用 newStdGen ,但更好的方法是通过将随机数生成器作为函数的附加参数并在之后返回新生成器来保持代码纯净:

rnd_select :: (Eq a, RandomGen g) => [a] -> Int -> g -> ([a], g)
rnd_select [] _ gen = ([], gen)
rnd_select _ 0 gen = ([], gen)
rnd_select ys n gen =
let (rnd_index, gen') = randomR (1, length ys) gen
(x, xs) = removeAt rnd_index ys
(xs', gen'') = rnd_select xs (n-1) gen'
in (x : xs', gen'')

现在您可以使用它,例如 getStdRandom :: (StdGen -> (a, StdGen)) -> IO a像这样。
> getStdRandom (rnd_select [1..20] 10)
[12,11,14,4,16,7,1,2,18,15]

不过,手动传递生成器可能有点乏味。使这个更整洁的一种方法是使用 MonadRandom包裹。
rnd_select :: (MonadRandom m, Eq a) => [a] -> Int -> m [a]
rnd_select [] _ = return []
rnd_select _ 0 = return []
rnd_select ys n = do
rnd_index <- getRandomR (1, length ys)
let (x, xs) = removeAt rnd_index ys
xs' <- rnd_select xs (n-1)
return (x:xs')

由于 IOMonadRandom 的一个实例,您可以直接将其用作 IO行动。
> rnd_select [1..20] 10
[20,18,12,13,5,7,17,9,3,4]
> rnd_select [1..20] 10
[9,18,4,20,6,5,3,15,13,7]

或者您可以使用 evalRand在纯 monad 中运行它,提供你自己的随机数生成器,这样你就可以获得可重复的结果(有利于调试/测试)。
> evalRand (rnd_select [1..20] 10) (mkStdGen 200)
[4,16,15,13,8,20,6,14,5,3]
> evalRand (rnd_select [1..20] 10) (mkStdGen 200)
[4,16,15,13,8,20,6,14,5,3]

关于haskell - 如何在 haskell 中使用 newStdGen 或 getStdGen 而不是 mkStdGen,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10220463/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com