Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
File 使用Haskell迭代文件_File_Haskell_Directory - Fatal编程技术网

File 使用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

我有一个Haskell函数,它对单个文件进行操作以生成地图。我想迭代一个目录中的所有文件,并应用此函数生成一个映射

我正试图这样做:

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)