【问题标题】:Getting random numbers from non-monadic functions从非单子函数中获取随机数
【发布时间】:2016-01-10 00:04:58
【问题描述】:

所以我的目标是能够调用一个非单子函数并让它返回一个随机值。

getNums :: [Int] -- this only works when the type signature is "IO [Int]"
getNums = getListFromIO 10

getListFromIO :: Int -> IO [Int]
getListFromIO n = do
  gen <- newStdGen
  return $ generateList n gen

generateList :: Int -> StdGen -> [Int]
generateList n gen = take n $ randomRs (1,9) $ gen

如果我打电话给getListFromIO,一切都很好;我得到了我珍贵的随机整数列表,每次都不一样。但是调用它的每个函数都必须使用IO [Int] 类型签名。我不想那样。

我如何构造它以便能够获得[Int] 类型的随机数列表?

【问题讨论】:

  • 你不能。 IO 类型的全部意义在于阻止您执行此操作。如果你可以,它会破坏你的程序。相反,您应该询问如何使用getNums :: IO [Int],以使您可以使用它在其他函数中计算的[Int] 值。这就是 MonadFunctor 类型类方法的用途。
  • 如果您喜欢冒险,可以使用unsafePerformIO。注意 unsafe 位。
  • 请不要将unsafePerformIO 推荐给不了解使用它的危险后果或没有它的情况下编写 Haskell 的惯用方式的人。这是有害的。
  • 我更愿意学习正确的方法
  • 再一次,这不是建议,而是一些相关的信息,可以引起人们的兴趣并提供一些教育价值(如果他在使用它时遇到一些问题)。我非常怀疑 OP 是在写生产代码,所以你用枪的类比在这里不适用。

标签: haskell random monads type-signature


【解决方案1】:

你不能、不应该、也不需要这样做。

您声称所有使用getNums :: IO [Int] 的函数的类型中都必须有IO。这是不正确的。您可以使用 IO [Int] 操作以多种方式计算的 [Int] 值,例如:

main = do
  ints <- getNums -- ints is now of type [Int]
  return (map (+1) ints) -- map (+1) does not have IO in its type.

这是引入FunctorApplicativeMonad 类型类的原因之一:当您想避免处理IO 时,提供一种一致的方式来处理IO [Int] 之类的东西无处不在。

【讨论】:

  • 这有帮助。我将不得不考虑如何将其应用到我的代码中,但我现在知道了它的发展方向。
  • @MarkKaravan 一种简单的看待方式:您不会从 IO 中获取数据并将其发送到您的函数。您的顶级胶水代码使用 monad 组合器将纯函数放入 IO monad 以对其所在的数据进行操作。 (或编写 do 块,这是执行此操作的语法糖)。
【解决方案2】:

IO 的目的就是不允许纯代码产生副作用。所有非纯代码都必须在 IO monad 中运行。随机性也基于状态,或从外部资源(全局状态)读取。因此,如果没有 hack,您正在尝试的事情是不可能的。我强烈敦促你不要使用任何黑客。这种黑客攻击完全绕过了类型系统提供的安全性;它们应该仅限于本地化、安全的黑客攻击,主要是当类型系统不够智能并且需要一些说服力时。但这不是这里的情况——故意让一个纯函数表现得像一个非纯函数,这在很大程度上不是一种本地化的黑客攻击,因为任何调用它的代码都会继承破坏的语义,无法跟踪纯函数的结束位置和非纯函数的位置。纯洁开始。

最好重新设计代码,使其无需在纯代码中生成随机数。只需从位于 IO 中的代码层次结构中的高级点传递随机性。

【讨论】:

  • 也许我应该添加上下文。我正在制作一个 CLI 数独生成器,它可以输出一个随机板。 1) 提示用户进行显式随机输入,或者 2) 在整个代码中传递 IO Type 是否更像 Haskelian?
  • @MarkKaravan 错误的二分法。这两件事都不做更像是哈斯克尔式的。请参阅我的答案。
  • @Erik Allik:您能否提供一个从位于 IO 中的代码层次结构中的高级点传入随机性的示例?
  • 我在手机上打字……在星期六晚上写代码 sn-ps 有点太乏味了。 Rein 已经领先于我并且做得很完美。
猜你喜欢
  • 2012-08-04
  • 2017-04-07
  • 2018-06-17
  • 1970-01-01
  • 2019-12-10
  • 2015-05-22
  • 1970-01-01
  • 1970-01-01
  • 2019-07-01
相关资源
最近更新 更多