File 使用Haskell迭代文件
我有一个Haskell函数,它对单个文件进行操作以生成地图。我想迭代一个目录中的所有文件,并应用此函数生成一个映射 我正试图这样做:File 使用Haskell迭代文件,file,haskell,directory,File,Haskell,Directory,我有一个Haskell函数,它对单个文件进行操作以生成地图。我想迭代一个目录中的所有文件,并应用此函数生成一个映射 我正试图这样做: perFileFunc :: Int -> FilePath -> IO (Map.Map [Char] Double) allFilesIn dir = filter (/= "..")<$>(filter(/= ".")<$>(getDirectoryContents dir) perFileFunc::Int->Fi
perFileFunc :: Int -> FilePath -> IO (Map.Map [Char] Double)
allFilesIn dir = filter (/= "..")<$>(filter(/= ".")<$>(getDirectoryContents dir)
perFileFunc::Int->FilePath->IO(Map.Map[Char]Double)
allFilesIn dir=filter(/=”)(filter(/=”)(getDirectoryContents dir)
这将为我提供目录中除.and.之外的所有文件名的列表
现在当我试着去做
myFunc dir n = map (perFileFunc n) <$> allFilesIn dir
myFunc dir n=map(perFileFunc n)allFilesIn dir
它会进行打字检查,但什么也不做。我希望有一个地图列表,我可能会使用unionWith(+)加入其中
这似乎不是正确的方法。您的代码工作不正常,因为
()
用于将纯操作提升到一元(实际应用)上下文中,因此您的myFunc dir n
类型为IO[IO(Map.Map[Char]Double)]
;一种IO操作,执行时在目录中查找文件列表,并将每个文件映射到另一个IO操作,执行时生成所需的映射
,而不实际执行任何一个。这可能不是您想要的:)
您希望对列表的每个元素执行一个返回一元操作的函数,并返回结果值的列表。这就是为什么:
所以你真正想要的是:
myFunc dir n = allFilesIn dir >>= mapM (perFileFunc n)
之所以使用(>>=)
,是因为allfilesindir
本身是一个一元操作,您希望将其传递给一个函数,该函数期望其结果类型并返回另一个操作(在本例中为mapM
)
请注意,
mapM
与map
的不同之处在于,在IO
中(并非每个monad的行为都是这样,但大多数都是这样),它将在返回列表之前执行每个操作;这意味着每个动作的结果都必须集中在内存中,您将无法以增量方式处理结果。如果您想要这样做,您需要的不是mapM
,而是迭代对象。了解Haskell最棘手的事情是如何识别和编写IO操作。让我们看看一些类型签名
dir :: FilePath
allFilesIn :: FilePath -> IO [FilePath]
perFileFunc :: Int -> FilePath -> IO (Map.Map [Char] Double)
现在,您说对于myFunc
:
我在等一份地图清单
因此,对于该函数,您需要类型签名
myFunc :: Int -> FilePath -> [Map.Map String Double]
当然,返回类型不能只是[Map.Map String Double]
,因为我们需要执行一些IO来计算myFunc
。因此,给定一个Int
和一个FilePath
,我们实际上希望返回类型是一个生成[Map.Map String Double]
的IO操作:
myFunc :: Int -> FilePath -> IO [Map.Map String Double]
现在,让我们看一下创建此函数将要编写的IO操作
allFilesIn dir :: IO [FilePath]
perFileFunc n :: FilePath -> IO (Map.Map String Double)
perFileFunc
实际上不是一个IO操作,但它是一个函数,给定一个FilePath
,它会生成一个IO操作。让我们看看……如果我们运行allFilesIn
操作,那么我们可以使用该列表并对其每个元素运行perFileFunc n
myFunc dir n = do
files <- allFilesIn dir
???
如果你去掉这个do符号,你会发现它简化为ehird的答案:
myFunc dir n = allFilesIn dir >>= (\files -> mapM (perFileFunc n) files)
-- eta reduce (\x -> f x) ==> f
myFunc dir n = allFilesIn dir >>= mapM (perFileFunc n)
你真的想让
allFilesIn
有两个参数吗?不,我没有..我的坏..编辑了..+1,机械地得出正确答案肯定是解决此类问题的方法。
myFunc dir n = do
files <- allFilesIn dir
mapM (perFileFunc n) files
myFunc dir n = allFilesIn dir >>= (\files -> mapM (perFileFunc n) files)
-- eta reduce (\x -> f x) ==> f
myFunc dir n = allFilesIn dir >>= mapM (perFileFunc n)