也许在一个单子里
Maybe in a monad
我想学习 Haskell 的正确使用方法。
我仍然不完全理解如何在另一个 monad 中使用 Maybe 作为 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 上进行模式匹配?
我尝试使用 >>=
但它需要奇怪的函数类型和 returns 奇怪的类型。我只是无法让它发挥作用。我查看了 MaybeT
,但这意味着我需要在我的示例中定义一个类似于 ugly
的函数,即 returns a MaybeT Handler MyObj
。好像太复杂了。
编辑:将 lookupSession 替换为 returns 一个 ByteString 的 lookupSessionBS。
由于基于类型签名 decode . encodeUtf8 . fromString
是一个函数 Text -> Maybe MyObj
,我们可以在这里使用 (>>=)
或其翻转对应物 (=<<) :: Monad m => (a -> m b) -> m a -> m b
:
ugly :: Maybe Text -> Maybe MyObj
ugly = <b>(=<<)</b> (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
...
这里你甚至不需要 monad——你可以使用 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 略有不同的观点。 Monad 不仅仅是一种删除模式匹配的工具——它们是对 运行 事物顺序概念的非常普遍的抽象。例如:
- 当使用
Maybe
、'运行' 时,计算包括检查它是否为 Nothing
,如果发生这种情况则中止计算,否则继续。 (这对应于可能会失败的计算。)
- 当使用列表时,“运行”的计算包括将计算分成多个部分,每个部分对应列表中的每个元素,然后将这些部分重新连接起来。 (这对应于非确定性计算。)
- 当使用
IO
时,'运行' 计算正在计算机上执行。
- 当使用
Handler
时,'运行' 计算正在与发送的请求交互 and/or 响应某些东西。
所以你不应该每次想要操纵一个 Maybe
时都使用 monads——相反,没有 monads 往往更容易做到这一点,正如我在上面展示的那样! Monad 仅在需要对事物进行排序时才有用。在您的示例中,Handler
就是这种情况——因为您需要对与请求的多次交互进行排序——但对 Maybe
没有用,因为您只需要对一个值应用一系列操作它恰好被包裹在 Maybe
.
中
我想学习 Haskell 的正确使用方法。
我仍然不完全理解如何在另一个 monad 中使用 Maybe 作为 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 上进行模式匹配?
我尝试使用 >>=
但它需要奇怪的函数类型和 returns 奇怪的类型。我只是无法让它发挥作用。我查看了 MaybeT
,但这意味着我需要在我的示例中定义一个类似于 ugly
的函数,即 returns a MaybeT Handler MyObj
。好像太复杂了。
编辑:将 lookupSession 替换为 returns 一个 ByteString 的 lookupSessionBS。
由于基于类型签名 decode . encodeUtf8 . fromString
是一个函数 Text -> Maybe MyObj
,我们可以在这里使用 (>>=)
或其翻转对应物 (=<<) :: Monad m => (a -> m b) -> m a -> m b
:
ugly :: Maybe Text -> Maybe MyObj
ugly = <b>(=<<)</b> (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
...
这里你甚至不需要 monad——你可以使用 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 略有不同的观点。 Monad 不仅仅是一种删除模式匹配的工具——它们是对 运行 事物顺序概念的非常普遍的抽象。例如:
- 当使用
Maybe
、'运行' 时,计算包括检查它是否为Nothing
,如果发生这种情况则中止计算,否则继续。 (这对应于可能会失败的计算。) - 当使用列表时,“运行”的计算包括将计算分成多个部分,每个部分对应列表中的每个元素,然后将这些部分重新连接起来。 (这对应于非确定性计算。)
- 当使用
IO
时,'运行' 计算正在计算机上执行。 - 当使用
Handler
时,'运行' 计算正在与发送的请求交互 and/or 响应某些东西。
所以你不应该每次想要操纵一个 Maybe
时都使用 monads——相反,没有 monads 往往更容易做到这一点,正如我在上面展示的那样! Monad 仅在需要对事物进行排序时才有用。在您的示例中,Handler
就是这种情况——因为您需要对与请求的多次交互进行排序——但对 Maybe
没有用,因为您只需要对一个值应用一系列操作它恰好被包裹在 Maybe
.