If foo
really behaves like some RNG, it must have some monadic type, or take as an additional input the state of the RNG.
Here's an example, using the system RNG (which lives in the 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
In main
, we simply call foo
twice, binding its results to x,y
, which have type Int
. Then, we can compare them as usual.
Note that we can not use foo /= foo
since foo :: IO Int
, an action returning an Int, and we can't compare actions, only basic data like integers. This is why we first execute the actions, and then compare their results.
The main
could be written in one line exploiting some more advanced combinators
main = print =<< ((/=) <$> foo <*> foo)
-- or
main = print =<< liftA2 (/=) foo foo
but I would not focus on these at the beginning.
A more general example of a side-effecful computation:
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