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

时间:2016-11-20 19:43:08

标签: haskell random monads

如何在算术和逻辑运算中使用从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而不是总是试图逃避它们。

2 个答案:

答案 0 :(得分:4)

在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

一般的想法是:使用<-暂时从Double中提取IO Double,然后使用IO将结果放回return

例如,这将两个统一数字相加:

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

do还有其他选择,但我建议先学习do,因为它相当通用且简单。当你越来越习惯于monadic计算,应用程序和仿函数时,你可能也会喜欢像sumTwo = (+) <$> uniform_float <*> uniform_float这样的紧凑型替代方案。

答案 1 :(得分:3)

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

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

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

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

最后,在像这样的情况下,其中第二个monadic计算只是一个非monadic计算后跟return,你甚至不需要(>>=) - {{ 1}}就足够了:

fmap