链接数据库插入而不明确检查是否成功

Chaining DB Insertions Without Explicitly Checking for Success

我想弄清楚是否有办法在将记录插入数据库时​​避免大量 case 语句。

我当前的代码看起来像这样:

mt1 <- runDb $ do
        muid <- insertUnique user
        case muid of 
            Just uid -> do
                let t1 = Table1 {..., user = uid} 
                maid  <- insertUnique t1
                case maid of
                    Just aid -> do 
                        mo <- getBy $ UniqueField "somevalue" 
                        case mo of
                            Just (Entity oid o) -> do
                                mcid <- insertUnique Table2 {..., oid = oid} 
                                case mcid of
                                    Just cid -> do 
                                        mfid <- insertUnique Table3 {..., cid = cid} 
                                        case mfid of 
                                            Just fid -> Just t1 -- original t1 that was created at the top of the chain
                                            Nothing  -> Nothing
                                    Nothing  -> Nothing 
                            Nothing -> Nothing 
                    Nothing -> Nothing 
                Nothing -> Nothing
            Nothing  -> Nothing

首先,我在编译代码时遇到问题,但我没有尝试调试它,而是想看看是否有更好的方法来执行此操作。

在概念层面上,我想做类似下面的事情,其中​​所有 Maybe 值都会自动展开以用于后续调用。如果有一点,我们打一个Nothing,我只想returnNothing。整个代码将 运行 在单个事务中,因此如果我们在两者之间点击 Nothing,事务将回滚

runDb $ do
    uid <- insertUnique user
    let t1 = Table1 {..., user = uid} -- uid is unwrapped to just the value 
    aid  <- insertUnique t1
    o <- getBy $ UniqueField "somevalue"
    cid <- insertUnique Table2 {..., oid = oid}
    fid <- insertUnique Table3 {..., cid = cid} 
    Just t1 

我是 Haskell 初学者,所以我对 Monads 只有肤浅的了解(我可以使用简单的很好)但是当涉及到在 Persistent 的 runDb 之类的东西中使用它时,我有不知道如何将各个部分放在一起。

关于如何简化逻辑以便我最终不会在每一步都检查失败的任何建议?

更新:根据 Michael 的回答,我做了类似的事情,它在使用时自动打开 maybes。

mt1 <- runDb $ runMaybeT $ do 
           uid <- MaybeT $ insertUnique user
           ... 
case mt1 of
    Just t -> return t
    Nothing -> lift $ left ... 

谢谢!

像这样的事情的标准方法是 MaybeT monad transformer。像下面这样的东西可能会起作用:

runMaybeT $ do
    uid <- MaybeT $ insertUnique user
    ...