gpt4 book ai didi

haskell - 可以在 Haskell 中以纯代码读取文件吗?

转载 作者:行者123 更新时间:2023-12-02 19:14:04 25 4
gpt4 key购买 nike

我正在为 DSL 编写一个编译器。将源文件读入字符串后,所有其余步骤(解析、类型检查和代码生成)都是纯代码,将代码从一种表示形式转换为另一种表示形式。一切都很好,直到源文件中存在依赖项(想想 C 中的 #include 预处理器)。解析器需要读取依赖文件并递归地解析它们。这使它不再纯净。我必须将其从返回 AST 更改为 IO AST。此外,所有后续步骤(类型检查和代码生成)也必须返回 IO 类型,这需要进行重大更改。在这种情况下,处理读取依赖文件的好方法是什么?

附:我可以使用 unsafePerformIO,但这似乎是一个很糟糕的解决方案,可能会导致技术债务。

最佳答案

一个好的解决方案是解析为包含依赖关系信息的 AST,然后在解析器之外单独解析依赖关系。例如,假设您的格式可能是 #include行或内容行:

data WithIncludes = WithIncludes [ContentOrInclude]

data ContentOrInclude
= Content String
| Include FilePath

还有一个解析器 parse :: String -> WithIncludes这样这些文件:

  • file1 :

    before
    #include "file2"
    after
  • file2 :

    between

解析这些表示:

file1 = WithIncludes
[ Content "before"
, Include "file2"
, Content "after"
]

file2 = WithIncludes
[ Content "between"
]

您可以添加另一种类型来表示已解析导入的扁平化文件:

data WithoutIncludes = WithoutIncludes [String]

与解析、加载和递归展平分开包括:

flatten :: WithIncludes -> IO WithoutIncludes
flatten (WithIncludes ls) = WithoutIncludes . concat <$> traverse flatten' ls
where
flatten' :: ContentOrInclude -> IO [String]
flatten' (Content content) = pure [content]
flatten' (Include path) = do
contents <- readFile path
let parsed = parse contents
flatten parsed

那么结果是:

flatten file1 == WithoutIncludes
[ "before"
, "between"
, "after"
]

解析仍然是纯粹的,你只有一个 IO它周围的包装器驱动要加载的文件。您甚至可以重用此处的逻辑来加载单个文件:

load :: FilePath -> IO WithoutIncludes
load path = flatten $ WithIncludes [Include path]

在此处添加逻辑来检查导入周期也是一个好主意,例如通过向 flatten 添加累加器包含Set规范化的FilePath s,并检查每个 Include你没见过同样的FilePath已经。

对于更复杂的 AST,您可能希望共享未解析类型和已解析类型之间的大部分结构。在这种情况下,您可以通过是否已解析来参数化类型,并将未解析和已解析类型作为具有不同参数的基础 AST 类型的别名,例如:

data File i = File [ContentOrInclude i]

data ContentOrInclude i
= Content String
| Include i

type WithIncludes = File FilePath
type WithoutIncludes = File [String]

关于haskell - 可以在 Haskell 中以纯代码读取文件吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63907012/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com