没有因使用“lookupBlob”而产生的 (Git.Libgit2.HasLgRepo IO) 实例

No instance for (Git.Libgit2.HasLgRepo IO) arising from a use of ‘lookupBlob’

我正在尝试使用 gitlib 从 git 存储库中获取 HEAD 提交中所有文件的列表。这是我的代码:

{-# LANGUAGE OverloadedStrings #-}

module GitOperations where

import Git
import Git.Libgit2 (lgFactory, LgRepo(..) )
import qualified Data.Text as T
import Control.Monad.Trans.Reader
import Control.Monad.Trans
import Data.ByteString.Char8 as BS

repositoryOptions :: RepositoryOptions
repositoryOptions = RepositoryOptions { repoPath = ".git"
                                , repoWorkingDir = Just "."
                                , repoIsBare = False
                                , repoAutoCreate = True}
  
main :: IO ()
main = do
  repo <- openRepository lgFactory repositoryOptions
  runReaderT listHEADFiles repo

listHEADFiles:: ReaderT LgRepo IO ()
listHEADFiles = do 
  ref <- resolveReference $ T.pack "HEAD"
  case ref of
    Nothing -> fail $ "Could not resolve reference named 'HEAD'"
    Just reference -> do
      obj <- lookupObject reference
      case obj of
        CommitObj commit -> do 
          objects <- listAllObjects (Just $ commitOid commit) (commitOid commit)
          lift $ mapM_ (\o -> case o of BlobObjOid boOid -> do blob <- lookupBlob boOid; bc <- blobContents blob; case bc of BlobString bs -> BS.putStrLn bs) objects
        _ -> fail $ "'HEAD' is not a commit object"

我得到的错误是:

Main.hs:33:96: error:
    • Couldn't match kind ‘* -> *’ with ‘*’
      When matching types
        IO :: * -> *
        BlobContents :: (* -> *) -> *
      Expected type: IO (BlobContents m0)
        Actual type: BlobContents IO
    • In a stmt of a 'do' block: bc <- blobContents blob
      In the expression:
        do blob <- lookupBlob boOid
           bc <- blobContents blob
           case bc of { BlobString bs -> BS.putStrLn bs }
      In a case alternative:
          BlobObjOid boOid
            -> do blob <- lookupBlob boOid
                  bc <- blobContents blob
                  case bc of { BlobString bs -> BS.putStrLn bs }
   |
33 |           lift $ mapM_ (\o -> case o of BlobObjOid boOid -> do blob <- lookupBlob boOid; bc <- blobContents blob; case bc of BlobString bs -> BS.putStrLn bs) objects
   |                                                                                                ^^^^^^^^^^^^^^^^^
Failed, no modules loaded.

我不明白如何解决此错误消息以及如何调整我的代码以使类型检查器满意。任何提示表示赞赏。

请注意 git 存储库应至少包含一个提交才能使脚本正常工作。

UPD:根据@chi 的建议,我已将对 blobContents blob 的调用更改为非 monadic,但现在相关行看起来像 lift $ mapM_ (\o -> case o of BlobObjOid boOid -> do blob <- lookupBlob boOid; let bc = blobContents blob in case bc of BlobString bs -> BS.putStrLn bs) objects,出现另一个错误,但我没有知道如何修复它:

Main.hs:33:72: error:
    • No instance for (Git.Libgit2.HasLgRepo IO)
        arising from a use of ‘lookupBlob’
    • In a stmt of a 'do' block: blob <- lookupBlob boOid
      In the expression:
        do blob <- lookupBlob boOid
           let bc = ... in case bc of { BlobString bs -> BS.putStrLn bs }
      In a case alternative:
          BlobObjOid boOid
            -> do blob <- lookupBlob boOid
                  let ... in case bc of { BlobString bs -> ... }
   |
33 |           lift $ mapM_ (\o -> case o of BlobObjOid boOid -> do blob <- lookupBlob boOid; let bc = blobContents blob in case bc of BlobString bs -> BS.putStrLn bs) objects
   |                                                                        ^^^^^^^^^^^^^^^^
Failed, no modules loaded.

我是 gitlib 的新手,现在我尝试在 haskell 中使用 git 做一些简单的事情,这让我不知所措。有谁知道如何使这段代码成功编译?

如果我发现 the correct documentation pageblobContents 看起来像一个非单子函数,所以你不能使用 bc <- blobContents blob。请改用 let bc = blobContents blob.

这与错误消息一致,错误消息指出实际类型未包装在 IO 下。

  Expected type: IO (BlobContents m0)
    Actual type: BlobContents IO

此外,您使用 lift 太早了:

lift $ mapM_ (\o -> case o of 
   BlobObjOid boOid -> do
      blob <- lookupBlob boOid
      let bc = blobContents blob
      case bc of BlobString bs -> BS.putStrLn bs
   ) objects

lift 中,您只能使用 IO 操作,不能使用需要 ReaderT LgRepo IO 的操作。要解决此问题,只需将 lift 向内移动:

mapM_ (\o -> case o of 
   BlobObjOid boOid -> do
      blob <- lookupBlob boOid
      let bc = blobContents blob
      case bc of BlobString bs -> lift $ BS.putStrLn bs
   ) objects