3

I am new to Haskell, also English is not my first language, so please do not rate this post down because of some typo or because the question is poorly formulated: for me this is a true struggle.

Anyway: I am trying to generate random coordinates (Int,Int) and then use it in another Haskell function. But I have some problems "exporting" the IO-functions result to the second pure-kind Haskell function.

Here is an example that I think and hope properly illustrate my problem:

genRandomPair = genRandNr

genRandNr :: IO (Int,Int)
genRandNr = do
    firstRandom <- randomRIO (1,10)
    secondRandom <- randomRIO (1,10)
    return (firstRandom,secondRandom)

If its not obvious it is the transgression from genRandNr to genRandomPair that is my problem.

I would be very thankful for all friendly input.

Please note: very advanced code will explanations won't really help me, since I am on a beginners level and until a week ago never worked with monads or IO in Haskell.

pedrofurla
  • 12,763
  • 1
  • 38
  • 49
  • `genRandNr` is `IO (Int, Int)` but you have it typed as `IO ()`. Also, what's `genRandCoord` supposed to be? – Aplet123 Feb 22 '21 at 13:28
  • Sorry @Aplet123, I edited that. The above function is mostly to illustrate that I want genRandomPair to have the same result as genRandNr. Well not exactly the same. But I want to work with the result inside genRandomPair. – NoName Agent Feb 22 '21 at 13:31
  • You can yet again use `do` notation: `genRandomPair = do \ pair <- genRandNr \ -- do stuff with pair` where `\` is a new line since comments can't have separate lines. Something else you may find useful is this [question and answer thread](https://stackoverflow.com/questions/44965/what-is-a-monad) as well as [this excellent chapter in Learn you a Haskell](http://learnyouahaskell.com/a-fistful-of-monads) – Aplet123 Feb 22 '21 at 13:34
  • 1
    @NoNameAgent I think you'll need to give us more information about what you want to do in `genRandomPair`. As is (after the edits), your code should work. `genRandomPair` uses `genRandNr`, and has type `IO (Int, Int)`. Are you hoping to be able to give `genRandomPair` the type `(Int, Int)`? That cannot be done; if that is your question an answer could elaborate on why it can't work like that, and why you don't need to do that. But it's not completely clear at the moment if that is what you are asking. – Ben Feb 22 '21 at 13:36
  • not `genRandomPair = genRandNr`, but ``do { (x,y) <- genRandNr ; z <- return ( genRandomPair (x,y) ) ; .... use `z` ....}``. now your pure function `genRandomPair` works with the randomly generated `(x,y)` pair, *inside* the `IO` `do` block. every other pure function you need to call, you put into the `do` in the same manner. in Haskell, you do not "get a value out of `IO` to give it to a pure function" but instead you "put the pure function into `IO` so it can work on the values produced there". – Will Ness Jun 25 '21 at 12:04
  • [once inside IO, there's no escape](https://stackoverflow.com/a/18215015/849891). but it's not a problem since your whole program is a `do` block, anyway. it's the one called `main`. (and that's the answer). – Will Ness Jun 25 '21 at 12:04

2 Answers2

6

If you have am IO (Int,Int) value and a function that takes, say, (Int,Int), you can use fmap to map the impure result through your pure function:

fmap myPureFunction anImpureTuple

In general, though, you may want to factor out the non-deterministic part of your code.

I realise that you're new to Haskell, but unfortunately, randomness in Haskell may not be a good beginner topic. Haskell explicitly distinguishes between pure functions and impure actions, and randomness is impure by nature.

Arriving at elegant decomposition of functions that rely on randomness requires understanding of some of Haskell's intermediary abstractions, such as Functors (in the case of fmap) or type classes (to understand RandomGen).

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
-2

Idea of pure function in Haskell is if some pure function take the same arguments, it always return the same result. In your case, it means that your genRandomPair is just pair of Ints, this pair don't depend from time, day, your system and so on. Therefore, you can't just create random pair without IO.

But, you really can this with function unsafePerformIO or with other functions like it. It's usually not recommended, but, if you want...

SergeyKuz1001
  • 875
  • 1
  • 4
  • 6
  • 6
    I know you've qualified it with "not recommended", but not only should `unsafePerformIO` be almost always avoided, it should *really* be avoided if you're generating random numbers. By using `unsafePerformIO` you're saying "this is really a pure function, even though I can't express it without using IO - compiler, you're just going to have to trust me on this". But of course randomness is fundamentally *not* pure. There have been several questions on SO where people have used `unsafePerformIO` for exactly this purpose, and wonder why their function always gives the same number... – Robin Zigmond Feb 22 '21 at 14:41