gpt4 book ai didi

haskell - 在两个不同的模块中定义一个函数,或者解决方法

转载 作者:行者123 更新时间:2023-12-02 22:13:22 26 4
gpt4 key购买 nike

我在模块 A 中有一个函数 evalExpression::Exp -> Value,它在很大程度上依赖于参数 Exp 上的模式匹配.

文件已经变得足够大,需要更多的组织。我想将模块 A 拆分为模块 A.GHC.NumA.GHC.Types 等。

  • 有没有办法在 GHC 中将一个模块内联到另一个模块中?我尝试这样做,但出现错误“模块导入形成一个循环”

  • 有没有办法在两个不同的文件中编写相同的模块?

  • 我能否定义一个函数 A.evalExp 尝试(在 try and catch 的意义上)返回 A.GHC.Num.evalExp 的值,如果它缓存一个错误(非详尽的模式匹配),尝试返回 A.GHC.Types.evalExp,等等?

更新:

我尝试解决循环依赖,但 GHC 不相信,它说“模棱两可”。

最佳答案

不,你不能在多个文件之间拆分一个模块,你当然不能在不同的位置定义一个函数。最接近这个的是一个函数,它是类型类的一部分,在各种模块中定义了实例。但这可能不是您想要的。

但是, 可以编译相互递归的模块。从理论上讲,这应该 Just Work (tm) 但 GHC 需要一些跳圈才能做到这一点;见the User's Guide了解详情。如果您收到循环模块导入错误,这应该能让您使该版本正常工作。

没有“好”的方法来捕捉无穷无尽的模式匹配错误并尝试其他方法。有多种不太好的方法,但您可能不想去那里。

如果您的目标是在具有大量案例的单一数据类型上进行模式匹配,那么在不混淆相互递归模块或类型类的情况下拆分事物的最直接方法是在其他模块中使用单独的函数来获取内容每个构造函数作为直接参数,然后在导入其他构造函数并进行分派(dispatch)的模块中对所有情况进行单一模式匹配。

假设您有一个 Foo 类型,其中包含 AB 等情况,以及类似命名的模块。在“中央”模块中,您可以:

doStuff (A x y) = A.doStuffA x y
doStuff (B z) = B.doStuffB z

...等等。

在某些情况下,甚至可以以类似的方式拆分整个数据类型,并为每个构造函数创建一个单独的类型,例如:data Foo = A FooA | B FooB | ...。当您有可能以多种方式相互递归的复杂数据类型时,这是最有用的,经典示例是 AST。


好的,这是一种模拟您想要的东西的方法,无需做任何太粗略的事情。

首先,按照您理想的方式将您的功能分成不同的模块。然后进行以下更改:

  • 将结果类型更改为使用 Maybe,将结果包装在 Just 中并添加生成 Nothing 的包罗万象的默认情况.

  • 添加一个额外的参数 r,并将所有对 evalExp 的递归调用替换为 r

从中央模块导入每个包含 evalExp 案例的模块。如有必要,请使用合格的导入以避免歧义。定义每个 eval 函数的列表(它们应该都具有相同的类型),然后将“真实的”evalExp 定义为如下所示:

expCases = [A.GHC.Num.evalExp, A.GHC.Types.evalExpr {- etc... -} ]

evalExpCases exp = mapMaybe (\eval -> eval evalExp exp) expCases

evalExp exp = case evalExpCases exp of
(r:_) -> -- use the first result
[] -> -- no cases matched

本质上,这是使用 Maybe 来显式指示无穷无尽的模式,并用 fix 样式的构造替换直接递归,其中将组合的递归函数传递给每个(单独的非递归)案例集。

这很尴尬,但我不确定是否真的有更好的方法。可能有一种方法可以使用 Template Haskell 自动执行所有这些废话,但这可能与手动操作一样麻烦。

就我个人而言,我可能会咬紧牙关,将所有内容都放在一个模块中。

关于haskell - 在两个不同的模块中定义一个函数,或者解决方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14878737/

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