代码之家  ›  专栏  ›  技术社区  ›  Yago

Haskell中随机数生成的参数化界

  •  1
  • Yago  · 技术社区  · 1 年前

    我是Haskell的新手,我正在尝试创建一个函数,该函数生成一个有限数数组,并考虑一些起始和结束界限。如果我使用以下函数。。。

     finiteRandoms :: (Eq n, Num n, RandomGen g, Random a, Num a) => n -> g -> ([a], g)
     finiteRandoms 0 g = ([], g)
     finiteRandoms n g =
         let (value, newGen) = randomR (20,100) g
             (restOfList, finalGen) = finiteRandoms (n-1) newGen
         in  (value:restOfList, finalGen)
    

    然后我运行以下命令。。。

    finiteRandoms 3 (mkStdGen 3)
    

    我用新的生成器获得了Int的数组

    ([61,33,82],StdGen {unStdGen = SMGen 9186733390819170434 2092789425003139053})
    

    我要做的是向标记起点和终点的函数添加两个新参数。在我分享的函数中,它表示数字20和100。像这样的东西

    finiteRandoms :: (Eq n, Num n, RandomGen g, Random a, Num a) => n -> n -> n-> g -> ([a], g)
       finiteRandoms 0 start end g = ([], g)
       finiteRandoms n start end g =
             let (value, newGen) = randomR (start,end) g
                 (restOfList, finalGen) = finiteRandoms (n-1) newGen
             in  (value:restOfList, finalGen)
    

    但是当我通过ghci加载它时,我会得到以下错误

    randomSample.hs:19:10: error: [GHC-83865]
        • Couldn't match expected type: n -> g0 -> ([a0], g0)
                      with actual type: (a1, b)
        • In the pattern: (restOfList, finalGen)
          In a pattern binding:
            (restOfList, finalGen) = finiteRandoms (n - 1) newGen
          In the expression:
            let
              (value, newGen) = randomR (start, end) g
              (restOfList, finalGen) = finiteRandoms (n - 1) newGen
            in (value : restOfList, finalGen)
        • Relevant bindings include
            value :: n (bound at randomSample.hs:18:11)
            end :: n (bound at randomSample.hs:17:24)
            start :: n (bound at randomSample.hs:17:18)
            n :: n (bound at randomSample.hs:17:16)
            finiteRandoms :: n -> n -> n -> g -> ([a], g)
              (bound at randomSample.hs:16:2)
       |
    19 |          (restOfList, finalGen) = finiteRandoms (n-1) newGen
       |          ^^^^^^^^^^^^^^^^^^^^^^
    
    randomSample.hs:20:11: error: [GHC-25897]
        • Couldn't match expected type ‘a’ with actual type ‘n’
          ‘n’ is a rigid type variable bound by
            the type signature for:
              finiteRandoms :: forall n g a.
                               (Eq n, Num n, RandomGen g, Random a, Num a) =>
                               n -> n -> n -> g -> ([a], g)
            at randomSample.hs:15:2-92
          ‘a’ is a rigid type variable bound by
            the type signature for:
              finiteRandoms :: forall n g a.
                               (Eq n, Num n, RandomGen g, Random a, Num a) =>
                               n -> n -> n -> g -> ([a], g)
            at randomSample.hs:15:2-92
        • In the first argument of ‘(:)’, namely ‘value’
          In the expression: value : restOfList
          In the expression: (value : restOfList, finalGen)
        • Relevant bindings include
            value :: n (bound at randomSample.hs:18:11)
            end :: n (bound at randomSample.hs:17:24)
            start :: n (bound at randomSample.hs:17:18)
            n :: n (bound at randomSample.hs:17:16)
            finiteRandoms :: n -> n -> n -> g -> ([a], g)
              (bound at randomSample.hs:16:2)
       |
    20 |      in  (value:restOfList, finalGen)
       |           ^^^^^
    Failed, no modules loaded.
    

    如何参数化这两个边界(开始/结束)?谢谢

    1 回复  |  直到 1 年前
        1
  •  1
  •   willeM_ Van Onsem    1 年前

    您忘记添加 start end 在递归调用中, 开始 终止 也需要是类型 g

    finiteRandoms :: (Eq n, Num n, RandomGen g, Random a, Num a) => n -> a -> a -> g -> ([a], g)
    finiteRandoms 0 start end g = ([], g)
    finiteRandoms n start end g =
         let (value, newGen) = randomR (start,end) g
             (restOfList, finalGen) = finiteRandoms (n-1) start end newGen
         in  (value:restOfList, finalGen)

    但很可能,最好在此处使用辅助函数:

    finiteRandoms :: (Eq n, Num n, RandomGen g, Random a, Num a) => a -> a -> n -> g -> ([a], g)
    finiteRandoms start end = go
       where go 0 g = ([], g)
             go n g =
                 let (value, newGen) = randomR (start,end) g
                     (restOfList, finalGen) = go (n-1) newGen
                 in  (value:restOfList, finalGen)

    例如,我们生成五个介于二十到一百之间的数字,其中:

    ghci> finiteRandoms 20 100 5 (mkStdGen 3)
    ([70,50,99,83,50],781515869 652912057)