如何实现副作用功能?

时间:2016-07-01 08:16:03

标签: haskell monads side-effects

我是通过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?)。但我真的不明白如何为此目的编写简单的函数示例。

1 个答案:

答案 0 :(得分: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