如何正确使用 >>= 替换这段代码中的 do 和 <- ?

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

我有一个关于如何使用 monad 的问题。我有以下代码:

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 

而且效果很好。但是,我认为它限制了将 getStdGen 的输出绑定到 randomW1 之外,并且我认为我可以通过编写 [=] 将 getStdGen 更直接地绑定到 randomW1 24=]

w1 = take 50 (randomW1 =<< getStdGen) 

我相信我已经将 >>==<< 与 "pipe" 单子结构一起使用,并替换了 do<- 的使用。当我按照我的建议去做时,我发现它

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

有没有办法用>>=代替这段代码中的do<-

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

(实际上不需要括号)

个人不喜欢上面的样式,因为>>= (return . f)可以用fmap f实现,更简单的方法如下:

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

删除最后一个 <-,我们得到:

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

这里有一个更系统的方法来推导最后一个,一步一步。从头开始:

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

内联w1:

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

do x <- m ; e 脱糖为 m >>= \x -> e。这就是 do 语法的定义方式。

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

对最后一个 lambda 使用组合:

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