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