簡體   English   中英

也許在一個單子中

[英]Maybe in a monad

我想學習以正確的方式使用 Haskell。

我仍然不完全理解如何使用 Maybe 作為另一個 monad 中的 monad。 http://learnyouahaskell.com/a-fistful-of-monads告訴我,我可以使用 Maybe 做美妙的事情,而無需每一步的模式匹配 Just 和 Nothing。 請幫助我理解如何。

我正在編寫 Yesod 處理程序,但這在這種情況下並不重要。 重要的是Handler是一個monad。

ugly :: Maybe ByteString -> Maybe MyObj
ugly Nothing = Nothing
ugly (Just text) = (decode . fromStrict) text

getHelloWorldR :: Handler Html
getHelloWorldR = do
  myObjText <- lookupSessionBS "myobj"  :: Handler (Maybe ByteString) -- gets serialized MyObj from a session cookie, or Nothing
  myObj <- return $ ugly myObjText :: Handler (Maybe MyObj)

如何重寫它以避免在 Nothing 上進行模式匹配?

我嘗試使用>>=但它需要奇怪的函數類型並返回奇怪的類型。 我只是無法讓它發揮作用。 我查看了MaybeT ,但這意味着我需要在我的示例中定義一個類似於ugly的函數,該函數返回一個MaybeT Handler MyObj 好像太復雜了。

編輯:將lookupSession 替換為返回ByteString 的lookupSessionBS。

由於基於類型簽名decode . encodeUtf8 . fromString decode . encodeUtf8 . fromString decode . encodeUtf8 . fromString是一個函數Text -> Maybe MyObj ,我們可以在這里使用(>>=)或其翻轉的對應物(=<<) :: Monad m => (a -> mb) -> ma -> mb

ugly :: Maybe Text -> Maybe MyObj
ugly = (=<<) (decode . encodeUtf8 . fromStrict)

或更短:

ugly :: Maybe Text -> Maybe MyObj
ugly = (decode . encodeUtf8 . fromStrict =<<)
getHelloWorldR = do
  myObjText <- lookupSession "myobj"  :: Handler (Maybe Text)
  myObj <- return $ ugly myObjText :: Handler (Maybe MyObj)
  ...

可以改寫為

getHelloWorldR = do
  myObjText <- lookupSession "myobj"  :: Handler (Maybe Text)
  let myObj = ugly myObjText :: Maybe MyObj
  ...

然后,

ugly :: Maybe Text -> Maybe MyObj
ugly Nothing = Nothing
ugly (Just text) = (decode . encodeUtf8 . fromStrict) text

可以改寫為

ugly :: Maybe Text -> Maybe MyObj
ugly maytext = maytext >>= decode . encodeUtf8 . fromStrict

因此,

getHelloWorldR = do
  myObjText <- lookupSession "myobj"  :: Handler (Maybe Text)
  let myObj :: Maybe MyObj
      myObj = myObjTest >>= decode . encodeUtf8 . fromStrict
  ...

你在這里甚至不需要fmap你可以使用fmap重寫ugly

ugly = fmap $ decode . fromStrict

此時,您甚至可以將其內聯到getHelloWorldR

getHelloWorldR :: Handler Html
getHelloWorldR = do
  myObjText <- lookupSessionBS "myobj"  :: Handler (Maybe ByteString) -- gets serialized MyObj from a session cookie, or Nothing
  myObj <- return $ fmap (decode . fromStrict) myObjText :: Handler (Maybe MyObj)

或者您甚至可以使用<$>運算符,它是fmap的中綴版本:

getHelloWorldR :: Handler Html
getHelloWorldR = do
  myObjText <- lookupSessionBS "myobj"  :: Handler (Maybe ByteString) -- gets serialized MyObj from a session cookie, or Nothing
  myObj <- return $ (decode . fromStrict) <$> myObjText :: Handler (Maybe MyObj)

實際上,由於您正在運行return然后立即通過<-分配它,因此可以將其替換為let

getHelloWorldR :: Handler Html
getHelloWorldR = do
  myObjText <- lookupSessionBS "myobj"  :: Handler (Maybe ByteString) -- gets serialized MyObj from a session cookie, or Nothing
  let myObj :: Maybe MyObj
      myObj = (decode . fromStrict) <$> myObjText

但我也想對你的問題提出與 monad 略有不同的觀點。 Monads 不僅僅是刪除模式匹配的工具——它們是對按順序運行事物的概念的非常籠統的抽象。 例如:

  • 使用Maybe ,“運行”計算包括檢查它是否為Nothing ,如果發生這種情況則中止計算,否則繼續。 (這對應於可能失敗的計算。)
  • 使用列表時,“運行”計算包括將計算拆分為多個部分,列表中的每個元素一個,然后再次連接這些部分。 (這對應於非確定性計算。)
  • 使用IO ,“運行”計算是在計算機上執行它。
  • 使用Handler ,“運行”計算是與發送的請求交互和/或響應某些東西。

所以你不應該在每次你想要操作一個Maybe時都去訪問 monad——相反,沒有 monad 這樣做通常要容易得多,正如我上面展示的! Monad 僅在您需要對事物進行排序時才有用。 在您的示例中, Handler就是這種情況——因為您需要對與請求的多次交互進行排序——但對Maybe沒有用,因為您只需要對恰好包裝在Maybe的值應用一系列操作.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM