Haskell 中目录的流式递归下降

2023-11-22

我正在尝试使用 Haskell 进行目录结构的递归下降。我只想根据需要(懒惰地)检索子目录和文件。

我编写了以下代码,但是当我运行它时,跟踪显示在第一个文件之前访问了所有目录:

module Main where

import Control.Monad ( forM, forM_, liftM )
import Debug.Trace ( trace )
import System.Directory ( doesDirectoryExist, getDirectoryContents )
import System.Environment ( getArgs )
import System.FilePath ( (</>) )

-- From Real World Haskell, p. 214
getRecursiveContents :: FilePath -> IO [FilePath]
getRecursiveContents topPath = do
  names <- getDirectoryContents topPath
  let
    properNames =
      filter (`notElem` [".", ".."]) $
      trace ("Processing " ++ topPath) names
  paths <- forM properNames $ \name -> do
    let path = topPath </> name
    isDirectory <- doesDirectoryExist path
    if isDirectory
      then getRecursiveContents path
      else return [path]
  return (concat paths)

main :: IO ()
main = do
  [path] <- getArgs
  files <- getRecursiveContents path
  forM_ files $ \file -> putStrLn $ "Found file " ++ file

如何将文件处理与下降交错进行?问题是files <- getRecursiveContents path操作在以下操作之前执行forM_ in main?


这正是迭代器/协程旨在解决的问题。

你可以轻松地做到这一点pipes。我对你做的唯一改变getRecursiveContents是为了让它成为Producer of FilePath和到respond与文件名而不是返回它。这让下游立即处理文件名,而不是等待getRecursiveContents完全的。

module Main where

import Control.Monad ( forM_, liftM )
import Control.Proxy
import System.Directory ( doesDirectoryExist, getDirectoryContents )
import System.Environment ( getArgs )
import System.FilePath ( (</>) )

getRecursiveContents :: (Proxy p) => FilePath -> () -> Producer p FilePath IO ()
getRecursiveContents topPath () = runIdentityP $ do
  names <- lift $ getDirectoryContents topPath
  let properNames = filter (`notElem` [".", ".."]) names
  forM_ properNames $ \name -> do
    let path = topPath </> name
    isDirectory <- lift $ doesDirectoryExist path
    if isDirectory
      then getRecursiveContents path ()
      else respond path

main :: IO ()
main = do
    [path] <- getArgs
    runProxy $
            getRecursiveContents path
        >-> useD (\file -> putStrLn $ "Found file " ++ file)

这会在遍历树时立即打印出每个文件,并且不需要惰性IO。更改文件名的操作也很容易,因为您所要做的就是切换出文件名useD阶段与您的实际文件处理逻辑。

要了解更多信息pipes,我强烈推荐你阅读Control.Proxy.教程.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Haskell 中目录的流式递归下降 的相关文章

随机推荐

  • 使用适用于 Android 的 Smack Api 发送和接收消息

    自过去四天以来 我一直在尝试使用自己的 XMPP 和 Smack OpenFire 发送和接收聊天消息 根据Smack的 readme txt 我设置了连接并登录了用户 连接和登录的代码是这样的 public static String T
  • Magento - 从优惠券代码获取规则

    我必须检索与优惠券代码关联的规则 以便在报价中显示该规则的折扣百分比 最简单的方法是直接根据报价金额进行计算 但我想直接检索规则 然后从中获取折扣百分比 这就是我尝试过的 rule Mage getModel salesrule coupo
  • 编写新 DialogPreference 类的简洁方法?

    我正在通过扩展在 Android 中编写一些自定义首选项对话框DialogPreference班级 但是 我有点担心所需的样板代码量 因为似乎有很多行为需要测试 例如 这个数字首选项对话框的示例相当典型 http svn jimblackl
  • Python 中一张图中的多个图

    我是 python 新手 正在尝试使用 matplotlib 在同一个图中绘制多条线 我的 Y 轴的值存储在字典中 我在以下代码中在 X 轴中制作相应的值 我的代码是这样的 for i in range len ID AxisY PlotP
  • 在webview中加载flv视频的问题

    我想要load网络视图中的 flv 视频 我已经得到了帮助这个链接 但问题是我无法在模拟器中查看视频 这是我的代码 package com FlvTester import java lang reflect InvocationTarge
  • 来自闪亮应用程序的写入权限

    这是对此的后续问题 write csv 许可闪亮服务器 R 我正在使用一个闪亮的应用程序来搜索和保存一些数据 我在获取文件夹权限时遇到问题 读完这篇文章后 https groups google com forum topic shiny
  • Hadoop MapReduce 读取文本文件

    我正在尝试编写一个 MapReduce 程序 它可以读取输入文件并将输出写入另一个文本文件 我计划为此使用 BufferedReader 类 但我真的不知道如何在 MapReduce 程序中使用它 我怎样才能为其编写代码片段 附 我对 Ha
  • Meteor.js:查找所有文档并以相反的自然顺序返回

    我正在尝试返回集合中的所有文档 以将其与模板中的 each 一起使用 我的代码如下所示 return Answers find sort natural 1 但文档按自然顺序返回 而不是反向 有谁知道为什么 我从 MongoDB 文档中获取
  • WinMerge:如何在比较中忽略特定单词?

    当我在 Windows 平台上使用 WinMerge 比较 2 个文件时 您知道如何忽略特定单词吗 我的意思是我想对 WinMerge 说 不要关心那串单词 房子 花园等 所以当比较这两行时 the house is at london t
  • 由于来自 localhost 的 CORS 问题,请求失败

    我在 SO 和不同的博客上看到了几十个问题 并用 答案 谈论这个问题 但都无济于事 我的本地计算机 Ubuntu 16 04 上有一个 React js 应用程序 在本地 我尝试通过运行来测试它npm start它会打开浏览器http 本地
  • 列出所有当前打开的文件句柄? [复制]

    这个问题在这里已经有答案了 可能的重复 检查Python中打开了哪些文件 Hello 是否可以获得所有当前打开的文件句柄的列表 我认为它们存储在环境中的某个位置 我对这个函数感兴趣 因为我想安全地处理出现致命错误时打开的任何文件 即关闭文件
  • 使用 Python 使用 IAM 角色连接到 Redshift

    我正在使用 sqlalchemy 和 psycopg2 将 python 连接到 redshift engine create engine postgresql user password hostname port database n
  • Slick,如何将查询映射到继承表模型?

    Slick 如何将查询映射到继承表模型 IE 我有表A B C A 是 父 表 B 和 C 是 子 表 我想知道的是我应该如何使用 slick 对此进行建模 以便 A 将是抽象的 B C 具体类型 并且查询 A 中的行将导致 B 或 C 对
  • 为什么 for_each 通过 move 返回函数

    我正在阅读文档std for each here http en cppreference com w cpp algorithm for each并看到返回值是std move f 为什么标准强制在返回值中移动输入参数 既然输入参数是按值
  • C++11 中的 POD 和继承。 struct的地址==第一个成员的地址吗?

    我编辑了这个问题以避免分心 在任何其他问题有意义之前 需要先解决一个核心问题 向任何现在看来答案似乎不那么相关的人道歉 让我们设置一个具体的例子 struct Base int i 没有虚方法 也没有继承 通常是一个非常愚蠢和简单的对象 因
  • 如何在 Nuxt 3 应用程序中添加页面加载器

    我正在使用 Nuxt 3 构建一个应用程序 我想添加一个页面加载器直到网站加载 根据本文 有一种简单但有限的解决方案和一种完全定制的解决方案 内置
  • Oracle:消除表和模式名称之间的歧义

    假设我有模式A and B 在模式中A我想打电话包X在模式中B 然而 有一个包B在模式中A A package B B package X 当我从架构 A 调用时 begin b x foo end 它寻找程序X包装内B i e A B X
  • Python:freeze.py 在哪里?

    有人知道 2 6 5 的 freeze py 安装在哪里吗 我似乎无法在任何地方找到它 是不是被拔出来换成别的东西了 它就在它一直在的地方 在下面Tools 在源分布中
  • 如何使用 Work Light 通过服务器端 javascript 发出 HTTPS 请求?

    我正在玩弄IBM 工作灯 并且我正在尝试创建一个适配器来从Google 地点 API 我想调用这个网址 https maps googleapis com maps api place search json key AIzaSyCTlPm
  • Haskell 中目录的流式递归下降

    我正在尝试使用 Haskell 进行目录结构的递归下降 我只想根据需要 懒惰地 检索子目录和文件 我编写了以下代码 但是当我运行它时 跟踪显示在第一个文件之前访问了所有目录 module Main where import Control