2016-02-29 9 views

回答

2

<->>=bind)其中letfmapdo塊。偷

一個例子來自here

do x1 <- action1 x0 
    x2 <- action2 x1 
    action3 x1 x2 

-- is equivalent to: 
action1 x0 >>= \ x1 -> action2 x1 >>= \ x2 -> action3 x1 x2 

action1action2 & action3都返回某種單子,說:

action1 :: (Monad m) => a -> m b 
action2 :: (Monad m) => b -> m c 
action3 :: (Monad m) => b -> c -> m d 

你可以重寫讓綁定這樣:

-- assume action1 & action3 are the same 
-- but action2 is thus: 
action2 :: b -> c 

do 
    x1 <- action1 x0 
    let x2 = action2 x1 
    action3 x1 x2 

do 
    x1 <- action1 x0 
    x2 <- return & action2 x1 
    action3 x1 x2 

-- of course it doesn't make sense to call action2 
-- an action anymore, it's just a pure function. 
3

let給出函數調用結果的名稱。

<-將當前monad中的monadic操作的結果綁定到名稱。

它們完全不同。使用let作爲單子之外的函數的結果,即正常的純函數。使用<-來表示monadic的任何內容,因爲它可以「解開」monad結果,並讓您獲得其中的值。

例如:

承擔具有以下簽名

frobnicate :: String -> IO Bool 

和純功能的IO功能

dothing :: Bool -> Bool 

我們可以做到這一點

main :: IO() 
main = do 
    x <- frobnicate "Hello" 
    let y = frobnicate "Hello" 
    -- z <- dothing x 
    let z = dothing x 
    return() 

我們知道t因爲已經從我們的IO運算結果中提取了Bool(該運算運行,結果被稱爲x,因此我們可以稍後使用它)。

我們也知道y :: IO Bool - 該操作尚未運行,對於未來的IO操作而言,它是潛在的。所以我們可以用y做的唯一有用的事情是稍後運行它,綁定結果並在那裏得到Bool,但在let之後,Bool甚至還不存在。

第三行被註釋掉,因爲它不會編譯 - 你不能對不在相關monad中的操作進行monadic綁定。 dothing不會返回IO任何內容,因此您無法將其綁定到IO()函數中。

第四行是簡單的 - z被製成的dothing x,其中x物的值從運行frobnicate "Hello"較早解開的結果。

所有這一切都僅僅是「真正的」單子操作下語法糖,使膨脹(不註釋掉部分)像

main = frobnicate "Hello" >>= (\x -> let y = frobnicate "Hello" 
             z = dothing x 
             in return()) 

當然這個例子是沒有意義的,但希望它可以說明在do表示法中let<-的區別。

TL; DR:使用<-爲單名操作的結果命名,let命名爲其他所有。

1

一個很好的例子來可視化<-不:

do 
    a <- ['a'..'z'] 
    b <- [1..3] 
    pure (a,b) 

您可以在網上REPL在try.frege-lang.org試試這個 (您可以輸入這是一個單行:

do { a <- ['a'..'z']; b <- [1..3]; pure (a,b) } 
相關問題