Haskell函数中如何将随机数用作Double?

时间:2018-07-28 05:49:04

标签: haskell random types monads

我正在尝试编写一个函数,该函数使用随机数作为与列表进行比较的条件(该列表是通过将函数映射到整数范围而创建的)。我正在以交互方式进行操作,如果我通过分别定义每个术语来进行操作,那么它将起作用:

import System.Random.MWC (create)
import Statistics.Distribution (genContVar)
import Statistics.Distribution.Uniform (uniformDistr)

rng <- create
rd <- (genContVar (uniformDistr 0 1)) rng

f x = takeWhile (<rd) $ fmap (*x) [1..10]

或者,我可以使用带有let表达式的非随机Double,也没有问题

f x = let rd = 0.4 in takeWhile (<rd) $ fmap (*x) [1..10]

但是,如果我尝试将所有内容放在一起,就会收到错误消息

f x = let rand <- (genContVar (uniformDistr 0 1) g) in takeWhile (<rand) $ fmap (*x) [1..10]

<interactive>:39:16: error:
parse error on input ‘<-’
Perhaps this statement should be within a 'do' block?

我知道拥有不同的变量类型会阻止加法运算,Int和Double运算,并且monad非常特殊,但是对于Haskell来说,我希望暂时避免使用更广泛的哲学,而是尝试寻找在一般函数中使用随机数的实用方法。

1 个答案:

答案 0 :(得分:2)

在GHCi中评估表达式时,您已经在IO monad中。这就是OP GCHi代码起作用的原因。

正如 n.m。在评论中指出的那样,单子(em)是在Haskell中使用随机数(以及所有其他非确定性或有效行为)的实用方法。如果要编写Haskell代码,则迟早必须了解它们的含义。不过,好消息是,学习单子论并不像有些人所相信的那样困难。

Haskell确实有do表示法形式的monad语法糖。使用它,您可以编写如下函数:

f x = do
  rng <- create
  rd <- (genContVar (uniformDistr 0 1)) rng

  return $ takeWhile (<rd) $ fmap (*x) [1..10]

此函数的类型为PrimMonad m => Double -> m [Double]。输出类型中PrimMonad的存在暗含某种效果。该功能可能(并且可能)不纯。

从理论上讲,可以使用上述不纯的语言构造来编写整个Haskell程序,但是Haskell的目的是保持尽可能多的代码纯净,因此应尽可能限制不纯代码的使用。可能。