繁体   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