List 如何将返回[]的函数转换为可遍历函数?
我有以下模块实现目录漫游:List 如何将返回[]的函数转换为可遍历函数?,list,haskell,traversable,List,Haskell,Traversable,我有以下模块实现目录漫游: 模块漫游 (步行 )在哪里 进口管制 导入控制.Monad.IO.Class 导入数据。列表 导入系统目录 导入System.FilePath walk::(MonadIO m)=>FilePath->m[(FilePath,[FilePath])] 走根=做 条目*)(t::*->*)。 (MonadIO m,可遍历t)=> FilePath->m(t(FilePath,[FilePath])) 预期类型:m(t(FilePath,[FilePath])) 实际类型
模块漫游
(步行
)在哪里
进口管制
导入控制.Monad.IO.Class
导入数据。列表
导入系统目录
导入System.FilePath
walk::(MonadIO m)=>FilePath->m[(FilePath,[FilePath])]
走根=做
条目*)(t::*->*)。
(MonadIO m,可遍历t)=>
FilePath->m(t(FilePath,[FilePath]))
预期类型:m(t(FilePath,[FilePath]))
实际类型:m[(FilePath,[FilePath])]
•在“do”块的stmt中:
((根,映射fst文件):)。海螺
mapM(walk.(root).fst)dirs
在表达式中:
输入
我认为它在:
上失败了
的确如此。如果使用(:)
构建结构,该结构将是一个列表,并且不能更改walk
的类型以声明它返回任意可遍历的结构。实际上也没有一个好的以可遍历
为中心的解决方法:可遍历
意味着,通过它的可折叠
超类,您有一个toList
,但没有一个fromList
列表的多态生成,并且通常为多态容器设计类,事实证明,这比最初看起来要困难得多。GHC目前生产完全多态容器的解决方案是IsList
类,而不是只在预先存在的容器上操作,例如使用Traversable
在GHC.Exts
中定义为:
class IsList l where
type Item l
fromList :: [Item l] -> l
...
已经有列表、非空列表、映射和大多数其他类型的实例,它们来自于您认为的标准Haskell库
请注意,类型参数l
,属于*
类型,而不是您从*->*
容器中所期望的类型。您可以提供完全应用的类型,并且如果需要,可以使用类型相等来约束项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
{-#语言类型族}
模块步行
(步行
)在哪里
进口管制
导入控制.Monad.IO.Class
导入数据。列表
导入系统目录
导入System.FilePath
导入GHC.Exts
walk::(IsList l,Item l~(FilePath,[FilePath]),MonadIO m)=>FilePath->ml
步行根=
您知道通用版本的用途是什么吗?我倾向于认为让walk
返回一个特定的结构(可以是列表、地图或其他东西),然后在单独的步骤中将其转换为其他内容就足够了,但这可能有助于准确地了解您的预期用例。这可以通过查看可遍历方法的类型签名来确定。它们都将可遍历的t
置于负位置,因此不能用于生成任意的t
结果。
{-# 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