"No instance for (MonadLevelDB IO)" 测试套件中的编译错误

"No instance for (MonadLevelDB IO)" compilation error in test suite

我正在尝试在我的 Haskell 应用程序中使用 higher-leveldb,但在我的测试套件中遇到一个我不理解的编译错误(或者至少,我没有正确修复它的知识)。

对于上下文,我有以下助手来从数据库中获取和解码用户:

getUser :: (MonadLevelDB m) => Text -> m (Maybe User)
getUser uuid = do
  let key = toStrict . encode $ uuid
  result <- LevelDB.get key -- m (Maybe Value)
  case result of
      Just value -> return ( decodeStrict' value :: Maybe User) -- Ideal type
      Nothing    -> return Nothing

以及以下测试套件:


type EuphrateMonad m = (MonadLevelDB m, MonadUnliftIO m, MonadIO m)

main :: IO ()
main = runCreateLevelDB "/tmp/mydb" "test" levelDBMain

levelDBMain :: (EuphrateMonad m) => m ()
levelDBMain = do
    setup
    test <- liftIO $ testSpec "euphrate" spec
    liftIO $ Test.Tasty.defaultMain test


spec :: Spec
spec = parallel $ do
    it "Fetch an already-existing user" $ do
        user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
        user `shouldBe` ( Just $ User "toto" "664798e1-7fac-4e0b-9fc6-757f4fb0409c" True "toto92" "" )

    it "Delete a user" $ do
      deleteUser "2e940724-936e-4700-826b-367faabac141"
      user <- getUser "2e940724-936e-4700-826b-367faabac141"
      user `shouldBe` Nothing

users :: [User]
users = [ User "toto" "664798e1-7fac-4e0b-9fc6-757f4fb0409c" True "toto92" ""
        , User "Jérôme" "2e940724-936e-4700-826b-367faabac141" False "jéjédu32" "nah."
        ]

setup :: (EuphrateMonad m) => m ()
setup =
  for_ users createUser

现在,我得到的错误是:

euphrate/test/Main.hs:29:17: error:
    • No instance for (MonadLevelDB IO) arising from a use of ‘getUser’
    • In a stmt of a 'do' block:
        user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
      In the second argument of ‘($)’, namely
        ‘do user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
            user
              `shouldBe`
                (Just
                   $ User
                       "toto" "664798e1-7fac-4e0b-9fc6-757f4fb0409c" True "toto92" "")’
      In a stmt of a 'do' block:
        _ <- it "Fetch an already-existing user"
               $ do user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
                    user
                      `shouldBe`
                        (Just
                           $ User
                               "toto" "664798e1-7fac-4e0b-9fc6-757f4fb0409c" True "toto92" "")
   |
29 |         user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我首先要寻找更好地理解此类情况的方法。通过 Reader 和 Writer,我对变形金刚有了一些基本的了解,但我对这些知识的了解并没有太大帮助。

感谢阅读:)

我对higher-levelDB不熟悉,但是从代码来看,我认为问题可能是当你写这样的行时:

spec :: Spec
spec = parallel $ do
    it "Fetch an already-existing user" $ do
        user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
        user `shouldBe` ( Just $ User "toto" "664798e1-7fac-4e0b-9fc6-757f4fb0409c" True "toto92" "" )

你不在你需要的单子语境中。使用 it 你只生活在 hspec 上下文中,它不知道所有与数据库相关的事情。看看 it 的(相当抽象的)签名:

it :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)

我们远未达到您的 EuphrateMonad 堆栈的限制。因此,您需要在两者之间添加一些内容,以输入所需的上下文(获取与 levelDB 的连接、管理事务等)。

在这种情况下,我发现直接查看库代码并查看是否有任何测试套件以及作者如何创建它们的上下文会有所帮助。你很幸运,there are tests in this library。看看withDBTwithDBRT的定义和用法,应该能给你指明正确的方向。