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

标签 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 的新手,我希望暂时避免更广泛的哲学,而是尝试找到一种在通用函数中使用随机数的实用方法。

最佳答案

当您在 GHCi 中计算表达式时,您已经处于 IO monad 中。这就是 OP GCHi 代码起作用的原因。

正如n.m.在评论中指出的,monad是在Haskell中使用随机数(以及所有其他非确定性或有效行为)的实用方法。如果你想编写 Haskell 代码,你迟早必须了解它们是什么。不过,好消息是,了解单子(monad)是什么并不像某些人想象的那么困难。

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 的重点是尽可能保持代码的纯净,因此人们应该尽可能地限制不纯代码的使用有可能。

关于haskell - 如何在 Haskell 函数中将随机数用作 Double ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51568471/

相关文章:

c++ - clang,libtooling 添加新的规范内置数据类型

haskell - 如何实现这个 Haskell 函数?

java - 多范围随机数生成器

C++ 如何获得从 1 到 12 的随机值?

asp.net - asp.net 中的安全随机数

function - 结构嵌入、函数输入、多态性

haskell - 除 * 之外的 child 的字符串表示形式

haskell - 覆盖 LTS 的 cabal 版本

parsing - 秒差距解析和分离不同的结构

regex - 用于查找和替换的 Haskell 括号匹配