Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to correctly use >>= to replace the do and <- in this code?

I have a question that goes on how to work with monads. I have the following code:

import System.Random
import Data.Random.Normal
import Graphics.EasyPlot
import Data.List
import Data.Function 

random' mean randomGen = zip x y 
    where                
       x = normals' (mean, 0.2) randomGen :: [Float]
       y = normals' (mean, 0.2) randomGen :: [Float]

randomW1 randomGen = [[x,y] | (x,y) <- random' 1.0 randomGen]

main = do  
    randomGen <- getStdGen
    let w1 = take 50 (randomW1 randomGen)
    print w1 

and it works fine. However, I think its limiting to bind the output of getStdGen outside of randomW1, and thought I could be able to bind the getStdGen more directly to randomW1 by writing

w1 = take 50 (randomW1 =<< getStdGen) 

I believe I have utilised the >>= or =<< to "pipe" monadic structures together, and replacing the use of do and <-. When I am doing as I suggest I discover that it

Couldn't match type ‘IO’ with ‘[]’
Expected type: [StdGen]
  Actual type: IO StdGen  

is there a way to use >>= to replace the do and <- in this code?

like image 968
stian Avatar asked Mar 14 '23 15:03

stian


1 Answers

main = do  
    w1 <- getStdGen >>= (return . take 50 . randomW1)
    print w1 

(parentheses not actually needed)

Personally, I dislike the style above, since >>= (return . f) can be achieved with fmap f in a simpler way, as follows:

main = do  
    w1 <- (take 50 . randomW1) `fmap` getStdGen
    -- or: w1 <- take 50 . randomW1 <$> getStdGen
    print w1 

Removing the last <-, we get:

main = print . take 50 . randomW1 =<< getStdGen

Here's a more systematic approach to derive the last one, step by step. Start from the beginning:

main = do  
    randomGen <- getStdGen
    let w1 = take 50 (randomW1 randomGen)
    print w1 

Inline w1:

main = do  
    randomGen <- getStdGen
    print (take 50 (randomW1 randomGen))

Desugar do x <- m ; e into m >>= \x -> e. This is how the do syntax is defined.

main = getStdGen >>= \randomGen -> print (take 50 (randomW1 randomGen))

Use composition for the last lambda:

main = getStdGen >>= print . take 50 . randomW1
like image 63
chi Avatar answered Mar 23 '23 05:03

chi