[英]Haskell Monadic forms
一個簡單的問題:給定定義,(來自 Haskell SOE)
do x — el; el\ ...; en
=> el »= \x — do e2\ ...; en
和:
do let decllist; el\...; en
=> let decllist in do e2\ ...; en
似乎這兩個構造是相同的:
do let x = e1
e2
和
do x <- e1
e2
都評估 e1,將其綁定到 e2,然后評估 e2。
是的?
讓我們在Maybe
monad 中做一個簡單的例子:
foo = do
let x = Just 1
return x
和
bar = do
x <- Just 1
return x
對兩者都進行脫糖,我們得到
foo = let x = Just 1 in return x -- do notation desugaring
= return (Just 1) -- let
= Just (Just 1) -- definition of return for the Maybe monad
bar = let ok x = return x in Just 1 >>= ok -- do notation desugaring
= let ok x = return x in ok 1 -- definition of >>= for the Maybe monad
= return 1 -- definiton of ok
= Just 1 -- definition of return for the Maybe monad
作為參考,我使用的是 Haskell 2010 報告第 3.14 節的翻譯。
不,它們不一樣。 例如,
do let x = getLine
print x
翻譯成
let x = getLine in print x
這是一個類型錯誤,因為x
的類型為IO String
。 我們要求打印計算本身,而不是其結果。
do x <- getLine
print x
翻譯成
getLine >>= \x -> print x
這里x
被綁定為計算的結果,它的類型是String
,所以這個類型檢查。
在do
-notation 中, let
像往常一樣將值綁定到名稱,而<-
用於執行單子綁定,即將名稱綁定到計算結果。
假設e1
是Monad m => ma
類型的計算,那么let x = e1
和x <- e1
意味着有些不同的東西。
在let
版本中,當您在 do 表達式中使用x
時,您正在處理Monad m => ma
類型的值。
在另一個版本中,當您在 do 表達式中使用x
時,您正在處理一個類型a
的值(因為 do-notation 隱式處理對 monad 的映射)。
例如:
e :: IO Int
f :: Int -> Int
-- the following will result in a type error, since f operates on `Int`, not `IO Int`:
g = do let x = e
return $ f x
-- the following will work:
g' = do x <- e
return $ f x
沒有。 x <- e1
轉換為e1 >>= \x ->
,一個不完整的表達式; let
表達式只是一個普通的let
。 或者您是在問let
和(>>=)
是否相同? 它們不是: (>>=)
將被 monad 包裹的東西暴露給 function,它必須產生包裹在 monad 中的東西。 換句話說,對於x <- e1
,對於某些a
, e1
的類型必須是IO a
,但是對於let x = e1
e1
的類型只是a
; 在這兩種情況下, x
的類型都是a
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.