Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use IO Double as regular Double in Haskell

I have to following code

isInCircle::Double->Double->Bool
isInCircle p1 p2 = sqrt((p1*p1)+(p2*p2)) <= 1

and when I make a call like

isInCircle (random :: Double) (random :: Double)

I get this error

* Couldn't match expected type `Double' with actual type `g0 -> (a0, g0)'

If I change the argument of isInCircle function to IO Double I get errors with sqrt and addition...

Can you help me? My code:

import System.Random 
main :: IO () 
main = do 
    if isInCircle (random :: Double) (random :: Double) 
    then print "True" 
    else print "False" 

isInCircle::Double->Double->Bool 
isInCircle p1 p2 = sqrt((p1*p1)+(p2*p2)) <= 1
like image 987
EvilGenius Avatar asked Mar 05 '23 20:03

EvilGenius


1 Answers

Checking it out at the GHCi prompt,

> :i Random
class Random a where
  randomR  :: RandomGen g => (a, a) -> g -> (a, g)
  random   :: RandomGen g => g -> (a, g)
  randomRs :: RandomGen g => (a, a) -> g -> [a]
  randoms  :: RandomGen g => g -> [a]
  randomRIO :: (a, a) -> IO a
  randomIO  :: IO a
        -- Defined in `System.Random'
instance Random Integer -- Defined in `System.Random'
instance Random Int -- Defined in `System.Random'
instance Random Float -- Defined in `System.Random'
instance Random Double -- Defined in `System.Random'
instance Random Char -- Defined in `System.Random'
instance Random Bool -- Defined in `System.Random'

we see that instead of random, for Double, randomIO :: IO Double looks much more promising. If only we could somehow get at the Double "inside" the IO Double type of "value". Can we do it?

Yes we can. That's what the "bind" is for. In do notation it is done with <-:

import System.Random 
main :: IO () 
main = do 
    -- if isInCircle (random :: Double) (random :: Double) 
    x <- (randomIO :: IO Double)   -- thus, x :: Double
    y <- (randomIO :: IO Double)   -- thus, y :: Double
    if isInCircle x y
      then print "True"            -- print "True" :: IO ()
      else print "False"           -- (if ... ...) :: IO ()

The pure function isInCircle itself isn't changed nor does it need to be. It is still the same pure function operating on two pure values. But we embed it in a combined IO computation recipe, built from smaller IO computation recipes (including the "built-in" randomIO recipe) such that when the resulting combined (composed?) computation – referred to / described by the value named main – is performed, it will use the pure function inInCircle with the two values obtained through the two randomIOs.

That's Haskell. Pure on the inside, I/O on the outside (and how else could it communicate with us if not – by definition – through I/O).

like image 63
Will Ness Avatar answered Mar 09 '23 07:03

Will Ness