Haskell 中的基本伪随机数生成器函数



我正在尝试编写一个简单的Lehmer算法伪随机数生成器,以更好地了解如何处理Haskell中的IO值,并且我一直得到类型不匹配。

我的代码如下所示:

import Data.Time.Clock.POSIX
generator :: Int -> Int -> Int -> Int
generator x i m
| i <= 0 = error "Index out of bounds"
| i == 1 = x * ( x `mod` m )
| otherwise = generator (generator x (i - 1) m) 1 m
pseudorand :: Int -> Int -> IO Int
pseudorand i m = do t <- round `fmap` getPOSIXTime
return (  i m -> generator t i m )

生成器函数接收种子、多次迭代和模参数,并运行递归模计算,其中x_(i+1) = x_0 * x_i mod m,足够简单。将毫秒时间作为 IO Int 也是可行的。我遇到的麻烦是之后将 IO Int 传递给我的生成器函数。

上面的代码需要"IO Int",但得到"IO(Int -> Int -> Int("。这显然是我的生成器函数的类型,所以我尝试了

pseudorand :: Int -> Int -> IO Int
pseudorand i m = do t <- round `fmap` getPOSIXTime
return ( fmap generator t i m )

它期望一个"Int",但得到一个"Int -> Int"。

为什么它不需要输入?为什么看不到im

也感谢您就如何为此编写代码提供意见

只是

pseudorand :: Int -> Int -> IO Int
pseudorand i m = do
t <- round <$> getPOSIXTime -- infix fmap is (<$>), evoking "fancy function application"
-- here, t :: Int, i :: Int, m :: Int, so generator t i m :: Int
-- t IS NOT an IO Int: the whole point of do-notation is "unwrapping" (<-)
-- monadic values and using them like normal ones
-- return (generator t i m) :: IO Int; we're done
return $ generator t i m

您也可以以应用样式编写以下内容:

pseudorand i m = generator <$> (round <$> getPOSIXTime) <*> pure i <*> pure m
-- read this as: generator(round(getPOSIXTIME()), i, m)
-- as you would write in an imperative language

或者只有一个中缀 fmap:

pseudorand i m = (t -> generator (round t) i m) <$> getPOSIXTime

最新更新