在算术和逻辑运算中使用从 Haskell 中的全局随机数生成器获得的随机值

Using random values obtained from the global random number generator in Haskell in arithmetic and logic operations

如何在算术和逻辑运算中使用Haskell中全局随机数生成器获得的IO Double值?网上的大部分教程都侧重于获取随机数,但不知怎么的,我似乎无法用它们做一些有用的事情。

以下代码包含一些函数 test,其中包含我要执行的一些操作。

{-# LANGUAGE Strict #-}
module RNG where
import System.Random(setStdGen, mkStdGen, randomRIO)

seed_rng :: Int -> IO()
seed_rng seed = (setStdGen (mkStdGen seed))

uniform_float :: IO Double
uniform_float = (randomRIO (0.0, 1.0))

test :: Double -> Double -> IO Double
test a b = let u = (uniform_float)
              in if ((<) (return a) u) then ((+) (return b) u) else (return 2.0)

测试函数无法编译,因为没有 Ord (IO Double)Num (IO Double) 的实例。

请注意,我可以通过实现随机数生成器并自己跟踪+传递状态来避免 IO Monad。但我宁愿学习与 Monads 一起工作,而不是总是试图 运行 远离他们。

在 monadic 上下文中,您可以使用 do 实际 运行 计算:

test :: Double -> Double -> IO Double
test a b = do
   u <- uniform_float
   if a < u
      then return (b + u)
      else return 2.0

大意是:用<-暂时从一个IO Double中取出一个Double,然后用[=17=把结果放回IO里面].

例如,这对两个统一数求和:

sumTwo :: IO Double
sumTwo = do
   x <- uniform_float
   y <- uniform_float
   return (x+y)

do 的替代方法,但我建议先学习 do,因为它相当通用且足够简单。当您更习惯于单子计算、应用程序和仿函数时,您可能还会喜欢紧凑的替代方案,例如 sumTwo = (+) <$> uniform_float <*> uniform_float.

(>>=) 可用于链接使用 Double 值的第二个单子计算。

test :: Double -> Double -> IO Double
test a b = uniform_float >>= \u -> return (if a < u then b + u else 2.0)

另一种编写上述内容的方法是使用 do 块:

test :: Double -> Double -> IO Double
test a b = do
    u <- uniform_float
    return (if a < u then b + u else 2.0)

最后,在这种情况下,第二个单子计算只是一个非单子计算,后跟 return,你甚至不需要 (>>=) -- fmap 就够了:

test :: Double -> Double -> IO Double
test a b = fmap (\u -> if a < u then b + u else 2.0) uniform_float