i'm trying to generate a random index (Int), with this code: randomRIO (0, 2 :: Int)
. But its generate a IO Int, so i cant do something like this: [1,2,3] !! randomIndex
. What does it have to be done to convert the IO Int to Int? Thanks.

- 31
- 1
- 4
2 Answers
...this code:
randomRIO (0, 2 :: Int)
. But its generate aIO Int
...
no, it is an IO Int
value. Such a value is similar to a “function” int f()
in a procedural language. If this were, say, Python, then you could also not just write
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import random
In [2]: def f():
...: return random.randint(0,2)
...:
In [3]: [1,2,3][f]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-74d3c2a164a4> in <module>()
----> 1 [1,2,3][f]
TypeError: list indices must be integers or slices, not function
Instead, you need to invoke the action. Only that will in fact yield an Int
number. In most languages, this is done simply by supplying arguments, in this case just the empty tuple ()
:
In [4]: [1,2,3][f()]
Out[4]: 2
But that's mingling two different concepts, namely supplying arguments and causing side-effects. (The side-effect is in this case the modification of the built-in random generator's state, so you won't get every time the same number.)
Haskell does it better, it has dedicated operators for sorting out the order of side-effects. As Daniel Wagner said, these are fmap
and >>=
. But if those infix-operators and higher-order type signatures look cryptic to you, you can also use Haskell's do
notation, which is actually just syntactic sugar for the same thing:
main :: IO ()
main = do
randomIndex <- randomRIO (0,2)
print $ [1,2,3] !! randomIndex
or, at the ghci prompt (which is essentially one big IO
-do
-block)
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/sagemuej/.ghci
Loaded GHCi configuration from /home/sagemuej/.ghc/ghci.conf
Prelude> :m +System.Random
Prelude System.Random> randomIndex <- randomRIO (0,2 :: Int)
Prelude System.Random> [1,2,3] !! randomIndex
1
The difference between foo <- action
and let foo = action
is similar as in Python the difference between foo = action()
and foo = action
.

- 117,950
- 5
- 174
- 319
-
I have often wondered whether it is possible for beginners to make good use of `do` notation without first having a firm grasp of `(>>=)` or similar. sigfpe's [The IO Monad for People who Simply Don't Care](http://blog.sigfpe.com/2007/11/io-monad-for-people-who-simply-dont.html) article is the closest I've seen to a tutorial that takes that possibility seriously, so if you like this answer, I highly recommend it as a next step for understanding how to use `do` blocks properly. – Daniel Wagner Jun 25 '18 at 13:02
-
but my real code is: `newCard:: Card newCard = do index <- randomRIO(0,7) return (getCards deck) !! index` i want to return a Card, but it is IO Card – Felipe Emerson Jun 25 '18 at 16:23
-
1“i want to return a Card” – no you don't. Unless you want that every card in every game is the same. – leftaroundabout Jun 25 '18 at 20:27
-
@leftaroundabout so it's only possible to generate random numbers in the output? Thanks for your help. Is that I saw this System.Random package and thought I could use it to do things like this that I wanted ... – Felipe Emerson Jun 25 '18 at 22:35
You can't convert an IO a
to an a
; but you can convert a function which consumes an a
into one that consumes an IO a
instead. The two most important conversions are these:
(<$>) :: (a -> b) -> (IO a -> IO b)
(=<<) :: (a -> IO b) -> (IO a -> IO b)
Since the function you want to use, namely, \index -> [1,2,3] !! index
, does not have an IO
return type, (<$>)
is the more appropriate one for you. So:
System.Random> (\index -> [1,2,3] !! index) <$> randomRIO (0, 2)
1

- 145,880
- 9
- 220
- 380