关于 Haskell 中随机数的另一个问题

2023-12-30

我正在尝试制作一个版本Pokemon Gold and Silver 的 Voltorb 游戏 https://bulbapedia.bulbagarden.net/wiki/Voltorb_Flip在哈斯克尔。现在,为了生成板,我想要一个 (l,r,v) 三元组的列表,其中 l 是行,r 是行,v 是字段的值。

值 l 和 r 是通过列表理解实现的,因为它们每次都应该相同。至于 v,虽然我找不到实现它的选项,以便它是 0,1,2 或 3 “随机”(我知道 Haskell 是纯函数式的,没有真正的随机性,这就是我为什么这样做的部分原因)与此斗争)。

如果有人能提供帮助,我将非常感激。如果您还可以简短解释一下该解决方案为何有效,那将对我有很大帮助。

我当前的 l 和 r 实现:

field n = [(l,r,v) | l <- [0..n], r <- [0..n]]


如果我正确理解了这个问题,那么应该是one每个(Int,Int)棋盘位置的随机值。所以这个问题不能通过在理解列表中添加第三个子句来解决,例如:

field n = [(l,r,v) | l <- [0..n], r <- [0..n], v <- someRandomStuff]

作为长度field表达式将是 (n+1)x(n+1)x(随机内容的长度),而你想要的只是 (n+1)x(n+1)。

一种可能性包括分两步操作:

  1. 生成所需的 (n+1)*(n+1) 个 0 到 3 之间的随机值
  2. 将其与 (l,r) 值相结合

我假设读者了解命令式语言的伪随机数生成。

给定一个种子,您可以使用函数 mkStdGen 返回的一次性随机数生成器来生成随机值,使用函数randomRs https://hackage.haskell.org/package/random-1.1/docs/System-Random.html。让我们使用一个ghci会话作为测试平台。

关于步骤1:

 λ> import System.Random
 λ> :t randomRs
randomRs :: (Random a, RandomGen g) => (a, a) -> g -> [a]
 λ> 
 λ> seed1=42
 λ> 
 λ> getVSeq n seed = let rng0 = mkStdGen seed  in take  ((n+1)^2) (randomRs (0,3) rng0)
 λ> 
 λ> getVSeq 5 seed1
[1,1,3,0,2,1,0,1,0,1,3,1,2,0,2,3,1,1,3,2,0,2,2,0,2,0,0,0,1,0,2,1,0,2,0,1]
 λ> 
 λ> length $ getVSeq 5 seed1
36
 λ> field0 n = [(l,r) | l <- [0..n], r <- [0..n]]
 λ> field0 5
[(0,0),(0,1),(0,2),(0,3),(0,4),(0,5),(1,0),(1,1),(1,2),(1,3),(1,4),(1,5),(2,0),(2,1),(2,2),(2,3),(2,4),(2,5),(3,0),(3,1),(3,2),(3,3),(3,4),(3,5),(4,0),(4,1),(4,2),(4,3),(4,4),(4,5),(5,0),(5,1),(5,2),(5,3),(5,4),(5,5)]
 λ> 

 λ> 
 λ> 
 λ> length  $ field0 5
36
 λ> 

现在关于步骤 2,函数zip almost解决了我们的问题,只是我们没有完全得到三元组:

 λ> 
 λ> sol0 n seed = zip (field0 n) (getVSeq n seed)
 λ> sol0 5 seed1
[((0,0),1),((0,1),1),((0,2),3),((0,3),0),((0,4),2),((0,5),1),((1,0),0),((1,1),1),((1,2),0),((1,3),1),((1,4),3),((1,5),1),((2,0),2),((2,1),0),((2,2),2),((2,3),3),((2,4),1),((2,5),1),((3,0),3),((3,1),2),((3,2),0),((3,3),2),((3,4),2),((3,5),0),((4,0),2),((4,1),0),((4,2),0),((4,3),0),((4,4),1),((4,5),0),((5,0),2),((5,1),1),((5,2),0),((5,3),2),((5,4),0),((5,5),1)]
 λ> 

所以我们需要按摩结果sol0一点点:

 λ> 
 λ> sol1 n seed = let flatten = (\((a,b),c) -> (a,b,c))  in  map flatten (sol0 n seed)
 λ> sol1 5 seed1
[(0,0,1),(0,1,1),(0,2,3),(0,3,0),(0,4,2),(0,5,1),(1,0,0),(1,1,1),(1,2,0),(1,3,1),(1,4,3),(1,5,1),(2,0,2),(2,1,0),(2,2,2),(2,3,3),(2,4,1),(2,5,1),(3,0,3),(3,1,2),(3,2,0),(3,3,2),(3,4,2),(3,5,0),(4,0,2),(4,1,0),(4,2,0),(4,3,0),(4,4,1),(4,5,0),(5,0,2),(5,1,1),(5,2,0),(5,3,2),(5,4,0),(5,5,1)]
 λ> 

这就是我理解你想要的。 如果这是您的应用程序中唯一使用随机数,那么这可能就足够了。否则,恐怕需要在 Haskell 函数式编程环境中建立一些有关随机数生成的知识。你可能想开始here https://www.schoolofhaskell.com/school/starting-with-haskell/libraries-and-frameworks/randoms or there https://en.wikibooks.org/wiki/Haskell/Libraries/Random.

此外,正如 Thomas M. DuBuisson 所提到的,这已在几个 SO 问题中得到解决。您可以使用本地搜索引擎。这是最近的其中之一 https://stackoverflow.com/questions/57836652/how-can-i-generate-different-random-values-in-haskell例如。

如果您需要收回发电机以供重复使用怎么办?

在这种情况下,您需要有一个函数,它接受预先构建的生成器,并以 (list,finalRng) 对的形式返回“字段”三元组列表和生成器(的最终状态)。

您可以将困难(随机)工作分包给一个函数,该函数返回另一个更简单的对,其中仅包含 v 值列表和生成器的最终状态。该函数可以用递归方式编写,如下所示。


import  System.Random
import  Control.Monad.Random

-- returns the random v values AND the final state of the generator
seqAndGen :: RandomGen tg => (Int,Int) -> Int-> tg -> ([Int], tg)
seqAndGen range count rng0 =
    if (count <= 0)
        then ([],rng0)
        else
            let (v,rng1) = randomR range rng0
                nextSeq  = seqAndGen range (count-1) rng1  -- recursive call
            in
                (v:(fst nextSeq), snd nextSeq)

-- returns the "field" values AND the final state of the generator
fieldAndGen :: RandomGen tg => Int -> tg -> ([(Int,Int,Int)], tg)
fieldAndGen n rng0 =
    let  field0  = [(l,r) | l <- [0..n], r <- [0..n]]
         range   = (0,3)       -- at that level, range gets hardwired
         count   = (n+1)*(n+1) -- number of field/board positions
         pair    = seqAndGen range count rng0  -- the hard work
         vSeq    = fst pair
         endRng  = snd pair
         flatten = \((a,b),c) -> (a,b,c)
         field   = map flatten  (zip field0 vSeq)
    in
         (field, endRng)

主要程序:

main = do
    let mySeed = 42
        n      = 5
    putStrLn $ "seed=" ++ (show mySeed) ++ "  " ++ "n=" ++ (show n)
    -- get a random number generator:
    let rng0    = mkStdGen mySeed  

    let (field, endRng) = fieldAndGen n rng0
        fieldv = map  (\(a,b,c) -> c)  field
    putStrLn $ "endRng = " ++ (show endRng)
    putStrLn $ "field  = " ++ (show field)

程序输出:


seed=42  n=5
endRng = 1388741923 1700779863
field  = [(0,0,1),(0,1,1),(0,2,3),(0,3,0),(0,4,2),(0,5,1),(1,0,0),(1,1,1),(1,2,0),(1,3,1),(1,4,3),(1,5,1),(2,0,2),(2,1,0),(2,2,2),(2,3,3),(2,4,1),(2,5,1),(3,0,3),(3,1,2),(3,2,0),(3,3,2),(3,4,2),(3,5,0),(4,0,2),(4,1,0),(4,2,0),(4,3,0),(4,4,1),(4,5,0),(5,0,2),(5,1,1),(5,2,0),(5,3,2),(5,4,0),(5,5,1)]

请注意,存在一种可能的变体,即不传递生成器,而是传递由函数生成的 v 值的无限列表randomRs https://hackage.haskell.org/package/random-1.1/docs/System-Random.html#v:randomRs。使用功能很方便splitAt https://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#v:splitAt为了这样的目的。 但这假设您仅对 v 值使用随机性,而不使用其他任何东西,因此它不太通用且不太灵活。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于 Haskell 中随机数的另一个问题 的相关文章

  • 以线程安全的方式获取随机数

    这是一篇描述随机数线程安全性的好文章 以线程安全的方式获取随机数 http blogs msdn com b pfxteam archive 2009 02 19 9434171 aspx 但我坚持使用 RandomGen2 示例 publ
  • 为什么我不能将 Int 类型与 a 类型匹配

    哈斯克尔新手在这里 我在这里尝试做的事情的一个过于简单的例子 test Int gt a test i i Couldn t match expected type a with actual type Int a is a rigid t
  • Haskell 中的所有图形和 Web 库是如何实现的?

    我才开始学习Haskell 我读到它是一种纯函数式语言 其中的所有内容都是不可变的 因此 输入输出 写入和读取数据库之类的事情会导致状态的可变性 我知道 Haskell 中有一种叫做 monad 的东西 它允许在 Haskell 中使用命令
  • Repa 数组上的并行 mapM

    在我最近的work https github com bgamari mixture model with Gibbs sampling 我一直在充分利用RVar http hackage haskell org packages arch
  • 加到 100 的随机数:Matlab

    我将人口数量分成不同的矩阵 现在想使用随机数测试我的代码 快速提问 谢谢你们提前的帮助 如果我使用 100 rand 9 1 使这 9 个数字相加等于 100 的最佳方法是什么 我想要 9 个 0 到 100 之间的随机数 加起来为 100
  • 为什么我的 Haskell 断言只发生在 IHaskell 中?

    如果我定义 import Control Exception assert import Data Char ord f String gt String f s assert all elem letters s letters lt g
  • 不明白这个 haskell 代码中的内容

    我有一些 Haskell 代码 我正在尝试完成它 但我不明白其中发生了什么 type Bag a a gt Int emptyB Bag a emptyB e gt 0 countB Eq a gt Bag a gt a gt Int co
  • `arr fst` 是如何自然变换的?

    I asked 这个问题 https stackoverflow com q 62733726 11143763不久以前 这是关于以下箭头定律 arr fst first f f arr fst Category k gt k b c gt
  • 如何计算函数被调用的次数,FP方式

    我目前正在通过SICP http mitpress mit edu sicp 与哈斯克尔 练习 1 15 询问一个函数被调用了多少次 这个想法可能是您应该使用替换方法 但我想知道如何在代码中执行此操作 在命令式语言中 我们可以保留一个全局变
  • 在类型级别未定义

    通常 当我使用 Haskell 代码时 我会使用类型注释将内容存根并undefined foo String gt Int foo undefined 是否有类型级别的 未定义 我可以以类似的方式使用 理想情况下 与某种注释结合使用 typ
  • 如何在 Haskell 中创建异构列表? (最初是Java)

    如何将以下 Java 实现转换为 Haskell 这里的主要目的是拥有一个包含作为特定接口的子类型的各种元素的列表 我尝试制作下面的 Haskell 版本 但未能达到我的目的 这里的重点是xs有类型 Bar 而不是Foo a gt a 这是
  • 如何避免 numpy.random.choice 中的舍入错误?

    假设 x 1 x 2 x n 是 n 个对象 并且想要选择其中一个 以便选择 x i 的概率与某个数字 u i 成正比 Numpy 为此提供了一个函数 x u np array x 1 x 2 x n np array u 1 u n np
  • Haskell 中是否可以部分应用第 n 个参数?

    我很好奇是否可以写一个函数apply nth它接受一个函数 参数的数量以及该参数的值 然后返回一个新的 部分应用的函数 我的感觉是 由于类型系统的原因 这是不可能的 但我无法给出令人满意的答案 我也无法提出工作类型签名 如果语言的类型更加松
  • 在 Haskell 中使用 Maybe 类型

    我正在尝试利用 Haskell 中的 Maybe 类型 我有一个查找返回 Maybe 的键 值元组 如何访问 Maybe 包装的数据 例如 我想将 Maybe 包含的整数与另一个整数相加 或者 您可以进行模式匹配 case maybeVal
  • 在 Web.Scotty 中使用 StateT

    我正在尝试制作一个愚蠢的网络服务器 将数据存储为State 我在用着Web Scotty http hackage haskell org package scotty 我之前用过 ReaderT 和 scotty 来访问配置 https
  • 如何为伪随机数生成器设置自定义种子

    我需要在使用的地方进行一些测试randn伪随机数生成器 我如何自己设置种子 以便每次运行此测试时都会得到相同的结果 是的 我知道这有点奇怪 但这就是问题所在 我找到了RANDSTREAM对象具有seed属性 但它是只读的 有什么方法可以用它
  • Haskell 中的 Monad 和 Purity

    我的问题是 Haskell 中的 monad 是否真正保持了 Haskell 的纯度 如果是的话 又是如何保持的 我经常读到副作用是如何不纯粹的 但有用的程序 例如 I O 需要副作用 下一句指出 Haskell 对此的解决方案是 mona
  • 是否可以反转伪随机数生成器?

    是否可以反转伪随机数生成器 例如 获取生成数字的数组并获取原始种子 如果是这样 这将如何实施 这绝对是可能的 您只需创建一个适合您目的的 PRNG 即可 这完全取决于您需要完成的任务 如果您更详细地描述您的情况 我很乐意提供更多建议 对于一
  • Haskell 乘加运算的数学性能

    我正在用 Haskell 编写一个游戏 我当前在 UI 上的传递涉及大量几何图形的程序生成 我目前专注于识别一项特定操作的性能 C ish 伪代码 Vec4f multiplier addend Vec4f vecList for int
  • 从子字符串中提取的映射运算符

    I have list of dicts print L 0 x 1 1 y 2 2 z 1 0 x 1 1 y lt 3 2 z gt 1 我想创建元组 其值位于运算符之前 运算符之后 值之后 first step wanted x 1

随机推荐