【问题标题】:How to implement function with side effects?如何实现有副作用的功能?
【发布时间】:2016-11-03 13:39:11
【问题描述】:

我是使用 Haskell 语言编程的初学者。我对在 Haskell 中编写函数感兴趣,它有这样的副作用(出于教育目的,它可能有另一个副作用):

-- function foo behaves like random numbers generator
foo :: Int
{- foo = some magic -}
-- It can print True or False
print $ show (foo /= foo)

据我了解,我必须实现具有这种行为的某些类型的 Monad 实例(例如:IO Why are side-effects modeled as monads in Haskell?)。但我真的不明白如何为此目的编写简单的函数示例。

【问题讨论】:

  • 嗯,您希望我们做什么?你已经知道你需要学习处理 Monads,所以继续阅读你目前正在使用的 Haskell 简介!
  • Int 不是函数的类型。这只是一个数字。
  • 我只想看一些例子,这些例子展示了这种行为的实现
  • 好的,如果我理解你的话,你想看看在 Haskell 中如何实现随机数生成器?
  • 是的,例如一些简化版本。据我了解,有用于实现副作用的 IO 类型

标签: haskell monads side-effects


【解决方案1】:

如果foo 真的表现得像一些 RNG,它必须有一些 monadic 类型,或者将 RNG 的状态作为附加输入。

这是一个使用系统 RNG(位于 IO monad 中)的示例:

import System.Random

foo :: IO Int
foo = randomRIO (1,5)  -- random number between 1 and 5

main :: IO ()
main = do
  x <- foo
  y <- foo
  print $ x /= y

在main 中,我们只需调用foo 两次,将其结果绑定到x,y,其类型为Int。然后,我们可以照常进行比较。

请注意,我们不能使用foo /= foo,因为foo :: IO Int 是一个返回Int 的动作,我们不能比较动作,只能比较整数等基本数据。这就是为什么我们首先执行操作,然后比较它们的结果。

main 可以写在一行中,利用一些更高级的组合器

  main = print =<< ((/=) <$> foo <*> foo)
  -- or
  main = print =<< liftA2 (/=) foo foo

但我一开始不会关注这些。


一个更一般的副作用计算示例:

foo :: IORef String -> IO Int
foo s = do
  x <- readIORef s              -- reading a "variable"
  print x                       -- output
  w <- getLine                  -- input
  writeIORef s ("qwerty" ++ x)  -- writing a variable
  length <$> readIORef s

main :: IO ()
main = do
  s <- newIORef "dummy"
  print =<< foo s

【讨论】:

  • 我知道 System.Random。我只是想看看这种行为的一些实现(出于教育目的,它可能会产生另一个副作用)
  • @АлександрЛысенко 我添加了一个示例...我不确定我是否了解您真正想要的内容。
  • 我想创建自己的 monad,它允许创建具有副作用的函数。
  • 如果您只是想读/写变量,请查找State。或ST。如果你想要输入/输出,你需要IO 或StateT IO。 State 和 StateT 可以在 hackage 上使用它们的实现。 IO 只能通过使用低级“不安全”原语来实现。
猜你喜欢
  • 2011-04-05
  • 1970-01-01
  • 2019-09-05
  • 2014-04-16
  • 2018-05-23
  • 1970-01-01
  • 2022-07-04
  • 2022-11-02
  • 1970-01-01
相关资源
最近更新 更多