haskell - 如何将随机数用作 Haskell 函数中的 Double?
问题描述
我正在尝试编写一个函数,它使用随机数作为条件来与列表进行比较(通过将函数映射到整数范围来创建)。我以交互方式进行操作,如果我通过单独定义每个术语来进行操作,则可以:
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 来说是新手,我希望暂时避免更广泛的哲学,而是尝试找到一个在一般函数中使用随机数的实用方法。
解决方案
当您在 GHCi 中评估表达式时,您已经在IO
monad 中了。这就是 OP GCHi 代码起作用的原因。
正如nm在评论中指出的那样,monad是在 Haskell 中使用随机数(以及所有其他非确定性或有效行为)的实用方法。如果你想编写 Haskell 代码,迟早你必须了解它们是什么。不过,好消息是,了解什么是 monad 并不像某些人认为的那么难。
Haskell 确实以符号的形式为 monad 提供了语法糖do
。使用它,您可以编写如下函数:
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 的重点是尽可能多地保持代码纯,因此应尽可能限制不纯代码的使用。
推荐阅读
- java - 打印从大到小和从小到大的数字列表
- nginx - 在nginx中查找错误页面的路径?
- asp.net - 如何在 Resolver 中拦截 GraphQL Hotchocolate Banana Cake Pop 查询
- webdriver - 尝试使用带有 AppiumDriver 的 AbstractWebDriverEventListener 的自定义侦听器
司机 - angular - getItemForm 不调用第二个承诺
- unit-testing - 期望将外部程序的退出命令识别为自己的
- https - 如何使用基本身份验证或 https 将用户从一个网页重定向到另一个受保护的网页
- java - Java Streams 按其键的属性分组 Map
- amazon-web-services - 通过访问点向 Amazon S3 授权角色
- android - 颤振 - 如何将类保存在变量中