[英]Haskell bind with multiple monads
现在,我的代码如下所示:
postUser :: ServerPart Response
postUser = do
-- parseBody :: ServerPart (Maybe User)
parsedUser <- parseBody
case parsedUser of
Just user -> do
-- saveUser :: User -> ServerPart (Maybe (Key User))
savedUser <- saveUser user
case savedUser of
Just user -> successResponse
Nothing -> errorResponse "user already exists"
Nothing -> errorResponse "couldn't parse user"
哪个可行,但是我知道有一种避免嵌套模式匹配的方法。 我以为这就是bind对我的影响,所以我尝试了
parseUser :: ServerPart (Maybe User)
addUser :: User -> ServerPart (Maybe ())
case parseUser >>= saveUser of
Just _ -> success
Nothing -> error
和
savedUser <- (parseUser >>= saveUser)
case savedUser of
Just _ -> success
Nothing -> error
但是我收到以下错误:
Couldn't match type ‘Maybe a0’ with ‘User’
Expected type: Maybe a0 -> ServerPartT IO (Maybe (Key User))
Actual type: User -> ServerPart (Maybe (Key User))
In the second argument of ‘(>>=)’, namely ‘saveUser’
In the expression: parseBody >>= saveUser
我的意思是>>=
正在将saveUser
应用于Maybe User
而不是我需要的User
,而且我不确定如何确定类型以匹配。 我该如何重写以避免嵌套模式匹配?
尽管我认为原始的编写方式是最易读的方法,但作为练习,MaybeT monad转换器正是您所需要的。
您遇到的问题是您正在尝试在ServerPart monad和Maybe monad之间跳转。 这就是为什么您不能直接绑定parseBody和saveUser的原因。 Monad变压器使您可以组合Monad来避免此问题。
import Control.Monad.Trans.Maybe
postUser :: ServerPart Response
postUser = do
-- parseBody :: MaybeT ServerPart User
-- saveUser :: User -> MaybeT ServerPart (Key User)
user <- runMaybeT $ parseBody >>= saveUser
case user of
Just _ -> successResponse
Nothing -> errorResponse "Error saving user"
您将需要重构parseBody和saveUser函数以使用MaybeT monad。 由于看不到这些功能,因此无法为您提供帮助,但是通常可以使用Control.Applicative中的lift
轻松完成此操作。
monad变压器上的有用链接:
https://zh.wikibooks.org/wiki/Haskell/Monad_transformers https://www.schoolofhaskell.com/user/commercial/content/monad-transformers
编辑:也许是parseBody
parseBody :: FromJSON a => MaybeT ServerPart a
parseBody = MaybeT $ fmap A.decode getBody
就像一般提示: bar >>= (return . f)
fmap f bar
bar >>= (return . f)
等效于fmap f bar
。 后者更干净,更通用,因为它不需要monad实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.