4

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
Will Ness
  • 70,110
  • 9
  • 98
  • 181
EvilGenius
  • 61
  • 3
  • 1
    I cannot reproduce the error you're getting with the code you've given, so I cannot help you. You must include the code that actually gets you this error. Please read up on [MCVE](https://stackoverflow.com/help/mcve). – AJF Jul 08 '18 at 08:12
  • 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 – EvilGenius Jul 08 '18 at 08:19
  • 4
    Don't post updates in comments, [edit] your question. – n. m. could be an AI Jul 08 '18 at 08:30
  • 5
    An `IO Double` is not a number, it's a recipe (or "action") for producing a number. – melpomene Jul 08 '18 at 08:31
  • @luqui it was at -2 because before the edit, it did not provide enough information, and therefore simply could not be answered. – AJF Jul 08 '18 at 08:40

1 Answers1

7

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).

Will Ness
  • 70,110
  • 9
  • 98
  • 181