如何将返回[]的函数转换为Traversable?

Lis*_*one 4 haskell list traversable

我有以下实现目录漫游的模块:

module Walk
  ( walk
  ) where

import           Control.Monad
import           Control.Monad.IO.Class
import           Data.List
import           System.Directory
import           System.FilePath

walk :: (MonadIO m) => FilePath -> m [(FilePath, [FilePath])]
walk root = do
  entries <- liftIO $ listDirectory root
  (files, dirs) <- partition snd <$> liftM2 (<$>) zip (mapM (liftIO . doesFileExist . (root </>))) entries
  ((root, map fst files) :) . concat <$> mapM (walk . (root </>) . fst) dirs
Run Code Online (Sandbox Code Playgroud)

它当前返回一个列表,但我希望它返回一个Traversable:

walk :: (MonadIO m, Traversable t) => FilePath -> m (t (FilePath, [FilePath]))
Run Code Online (Sandbox Code Playgroud)

如果更改签名,则会出现以下错误:

    • Couldn't match type ‘t’ with ‘[]’
      ‘t’ is a rigid type variable bound by
        the type signature for:
          walk :: forall (m :: * -> *) (t :: * -> *).
                  (MonadIO m, Traversable t) =>
                  FilePath -> m (t (FilePath, [FilePath]))
      Expected type: m (t (FilePath, [FilePath]))
        Actual type: m [(FilePath, [FilePath])]
    • In a stmt of a 'do' block:
        ((root, map fst files) :) . concat
          <$> mapM (walk . (root </>) . fst) dirs
      In the expression:
        do entries <- liftIO $ listDirectory root
           (files, dirs) <- partition snd
                              <$>
                                liftM2
                                  (<$>) zip (mapM (liftIO . doesFileExist .
(root </>))) entries
           ((root, map fst files) :) . concat
             <$> mapM (walk . (root </>) . fst) dirs
      In an equation for ‘walk’:
          walk root
            = do entries <- liftIO $ listDirectory root
                 (files, dirs) <- partition snd
                                    <$>
                                      liftM2
                                        (<$>)
                                        zip
                                        (mapM (liftIO . doesFileExist .
(root </>)))
                                        entries
                 ((root, map fst files) :) . concat
                   <$> mapM (walk . (root </>) . fst) dirs
    • Relevant bindings include
        walk :: FilePath -> m (t (FilePath, [FilePath]))
Run Code Online (Sandbox Code Playgroud)

我认为它失败了:吗?我不能确定 我该如何解决?

dup*_*ode 5

我认为它失败了:吗?

它的确是。如果(:)用于构建结构,则该结构将是一个列表,并且不能更改其类型walk以声明其返回任意可遍历的结构。也没有真正以中心为Traversable中心的解决方法:Traversable意味着您通过其Foldable超类拥有a toList,但没有a fromList。

  • 究竟。这可以通过查看Traversable方法的类型签名来确定。它们全部在负位置都具有可遍历的“ t”,因此不能用于产生任意的“ t”结果。 (2认同)