執行 - 符號desugars至(>> =)語法以這種方式:
getPerson = do
name <- getLine -- step 1
age <- getInt -- step 2
return $ Just Person <*> Just name <*> age
getPerson2 =
getLine >>=
(\name -> getInt >>=
(\age -> return $ Just Person <*> Just name <*> age))
在DO-符號的每一行,所述第一後,被轉換成一個lambda其然後結合至前一行。這是將值綁定到名稱的完全機械過程。我不明白如何使用符號或不會影響組合性;這完全是語法問題。
你的另一個功能是相似的:
getInt :: IO (Maybe Int)
getInt = do
n <- fmap reads getLine :: IO [(Int,String)]
case n of
((x,""):[]) -> return (Just x)
_ -> return Nothing
getInt2 :: IO (Maybe Int)
getInt2 =
(fmap reads getLine :: IO [(Int,String)]) >>=
\n -> case n of
((x,""):[]) -> return (Just x)
_ -> return Nothing
的方向有幾個指針你似乎是領導:
當使用Control.Applicative
,通常很有用<$>
解除純函數放入單子。還有在最後一行的一個很好的機會:
Just Person <*> Just name <*> age
成爲
Person <$> Just name <*> age
此外,你應該看看單子變壓器。 mtl軟件包是最普遍的,因爲它帶有Haskell平臺,但還有其他選項。 Monad變換器允許您創建一個新的Monad,並具有底層monads的組合行爲。在這種情況下,您正在使用IO (Maybe a)
類型的函數。的MTL(實際上是一個基礎庫,變壓器)限定
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
這是一樣的,你正在使用的類型,與所述m
變量在IO
實例化。這意味着你可以這樣寫:
getPerson3 :: MaybeT IO Person
getPerson3 = Person <$> lift getLine <*> getInt3
getInt3 :: MaybeT IO Int
getInt3 = MaybeT $ do
n <- fmap reads getLine :: IO [(Int,String)]
case n of
((x,""):[]) -> return (Just x)
_ -> return Nothing
getInt3
正是除MaybeT
構造相同。基本上,任何時候你有一個m (Maybe a)
你可以把它包裝在MaybeT
創建一個MaybeT m a
。這可以獲得更簡單的組合性,正如您可以通過getPerson3
的新定義所看到的那樣。這個函數根本不用擔心失敗,因爲它全部由MaybeT管道處理。剩下的一件是getLine
,這只是一個IO String
。這通過函數lift
提升到MaybeT monad中。
編輯 newacct的評論建議我應該提供一個模式匹配的例子;這與一個重要的例外情況基本相同。考慮這個例子(列表單子是我們感興趣的單子,Maybe
就在那裏進行模式匹配):
f :: Num b => [Maybe b] -> [b]
f x = do
Just n <- x
[n+1]
-- first attempt at desugaring f
g :: Num b => [Maybe b] -> [b]
g x = x >>= \(Just n) -> [n+1]
這裏g
不完全一樣的東西爲f
,但如果模式匹配失敗?
Prelude> f [Nothing]
[]
Prelude> g [Nothing]
*** Exception: <interactive>:1:17-34: Non-exhaustive patterns in lambda
發生了什麼事?這種特殊情況是Haskell最大的疣(IMO)之一,Monad
類的fail
方法。在註釋中,當模式匹配失敗時調用fail
。一個實際的翻譯將接近:
g' :: Num b => [Maybe b] -> [b]
g' x = x >>= \x' -> case x' of
Just n -> [n+1]
_ -> fail "pattern match exception"
現在我們有
Prelude> g' [Nothing]
[]
fail
有用性依賴於單子。對於列表來說,它非常有用,基本上使列表解析中的模式匹配工作成爲可能。它在Maybe
monad中也很好,因爲模式匹配錯誤會導致計算失敗,這正是Maybe
應該是Nothing
。對於IO
,可能不是那麼多,因爲它只是通過error
引發用戶錯誤異常。
這就是完整的故事。
另請參見:[Haskell 2010 Report> Expressions#Do Expressions](http://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-470003.14) –
只是爲了挑選,請注意'getPerson' isn是一個函數,因爲它的類型簽名中沒有' - >';如果你想要一個比「價值」更精確的名字,我會去「IO行動」。請參閱[「Haskell中的所有函數」](http://conal.net/blog/posts/everything-is-a-function-in-haskell)瞭解更多信息。 –