如何将返回 [] 的函数转换为 Traversable?
How to convert function returning [] to 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
它目前 return 是一个列表,但我希望它成为 return 一个 Traversable
:
walk :: (MonadIO m, Traversable t) => FilePath -> m (t (FilePath, [FilePath]))
如果我更改签名,我会收到以下错误:
• 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]))
我认为它在 :
上失败了?我不能确定。我该如何解决这个问题?
I think it's failing on the :
?
确实如此。如果您使用 (:)
构建结构,该结构将是一个列表,并且您无法更改 walk
的类型以将其声明为 returns 任意可遍历结构。也没有真正以 Traversable
为中心的解决方法:Traversable
意味着您通过其 Foldable
超类拥有 toList
,但没有 fromList
.
列表的多态生成以及通常为多态容器设计 classes 已被证明比最初看起来要困难得多。 GHC 当前用于生成完全多态容器的解决方案,与仅在 pre-existing 容器(例如 Traversable
上运行相比,是 IsList
class.
在GHC.Exts
中定义为:
class IsList l where
type Item l
fromList :: [Item l] -> l
...
已经有列表、非空列表、映射和大多数其他类型的实例,它们来自您认为的标准 Haskell 库。
请注意类型参数 l
属于 *
类型,而不是您对 * -> *
容器的期望。您提供完全应用的类型,如果需要,可以用类型相等来约束 Item l
类型。例如:
{-# LANGUAGE TypeFamilies #-}
module Walk
( walk
) where
import Control.Monad
import Control.Monad.IO.Class
import Data.List
import System.Directory
import System.FilePath
import GHC.Exts
walk :: (IsList l, Item l ~ (FilePath,[FilePath]), MonadIO m) => FilePath -> m l
walk root =
do entries <- liftIO $ listDirectory root
(files, dirs) <- partition snd <$> liftM2 (<$>) zip (mapM (liftIO . doesFileExist . (root </>))) entries
fromList . ((root, map fst files) :) . concat <$> mapM (walk . (root </>) . fst) dirs
我有以下实现目录遍历的模块:
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
它目前 return 是一个列表,但我希望它成为 return 一个 Traversable
:
walk :: (MonadIO m, Traversable t) => FilePath -> m (t (FilePath, [FilePath]))
如果我更改签名,我会收到以下错误:
• 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]))
我认为它在 :
上失败了?我不能确定。我该如何解决这个问题?
I think it's failing on the
:
?
确实如此。如果您使用 (:)
构建结构,该结构将是一个列表,并且您无法更改 walk
的类型以将其声明为 returns 任意可遍历结构。也没有真正以 Traversable
为中心的解决方法:Traversable
意味着您通过其 Foldable
超类拥有 toList
,但没有 fromList
.
列表的多态生成以及通常为多态容器设计 classes 已被证明比最初看起来要困难得多。 GHC 当前用于生成完全多态容器的解决方案,与仅在 pre-existing 容器(例如 Traversable
上运行相比,是 IsList
class.
在GHC.Exts
中定义为:
class IsList l where
type Item l
fromList :: [Item l] -> l
...
已经有列表、非空列表、映射和大多数其他类型的实例,它们来自您认为的标准 Haskell 库。
请注意类型参数 l
属于 *
类型,而不是您对 * -> *
容器的期望。您提供完全应用的类型,如果需要,可以用类型相等来约束 Item l
类型。例如:
{-# LANGUAGE TypeFamilies #-}
module Walk
( walk
) where
import Control.Monad
import Control.Monad.IO.Class
import Data.List
import System.Directory
import System.FilePath
import GHC.Exts
walk :: (IsList l, Item l ~ (FilePath,[FilePath]), MonadIO m) => FilePath -> m l
walk root =
do entries <- liftIO $ listDirectory root
(files, dirs) <- partition snd <$> liftM2 (<$>) zip (mapM (liftIO . doesFileExist . (root </>))) entries
fromList . ((root, map fst files) :) . concat <$> mapM (walk . (root </>) . fst) dirs