Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/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
Haskell 在两个不同的模块中定义函数或解决方法_Haskell_Ghc - Fatal编程技术网

Haskell 在两个不同的模块中定义函数或解决方法

Haskell 在两个不同的模块中定义函数或解决方法,haskell,ghc,Haskell,Ghc,我在模块a中有一个函数evalExpression::Exp->Value,它严重依赖于参数Exp上的模式匹配 该文件已变得足够大,需要更多的组织。我想将模块A分成模块A.GHC.Num,A.GHC.Types,等等 在GHC中,有没有办法将一个模块内联到另一个模块中?我尝试过这样做,但出现错误“模块导入形成一个循环” 或 有没有办法在两个不同的文件中写入相同的模块 或 我是否可以定义一个函数a.evalExp,该函数尝试(在try-and-catch的意义上)返回a.GHC.Num.

我在模块
a
中有一个函数
evalExpression::Exp->Value
,它严重依赖于参数
Exp
上的模式匹配

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

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

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

  • 我是否可以定义一个函数
    a.evalExp
    ,该函数尝试(在try-and-catch的意义上)返回
    a.GHC.Num.evalExp
    的值,如果它缓存错误(非穷举模式匹配),则尝试返回
    a.GHC.Types.evalExp
    ,以此类推
更新


我试图解决循环依赖关系,但GHC没有说服我,它说“不明确的事件”。

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

但是,可以编译相互递归的模块。理论上,这应该是可行的(tm),但GHC需要一点跳圈来做到这一点;有关详细信息,请参阅。如果您遇到循环模块导入错误,这将使该版本正常工作

没有“好”的方法可以捕获一个取之不尽的模式匹配错误并尝试其他方法。有很多不太好的方法,但你可能不想去那里

如果您的目标是在具有大量实例的单个数据类型上进行模式匹配,那么在不干扰相互递归的模块或类型类的情况下,最简单的方法是在其他模块中使用单独的函数,这些函数将每个构造函数的内容作为直接参数,然后,一个单一的模式匹配模块中的所有案例,该模块导入其他案例并执行分派

假设您有一个类型
Foo
,其大小写为
a
B
,&c,且具有类似命名的模块。在“中央”模块中,您可以有:

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函数的列表(它们都应该具有相同的类型),然后定义“real”
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
样式的构造替换直接递归,其中组合的递归函数传递给每个(单独的非递归)案例集

这很尴尬,但我不确定有没有更好的办法。也许有一种方法可以使用模板Haskell自动化所有这些废话,但这可能和手动操作一样麻烦


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

我添加了标签haskell,但我不确定该问题是否属于该模块,因为该问题是GHC特有的。如有必要,请删除。关于第一点,一个明显的问题是:您确定无法避免循环导入吗?您能否以某种方式拆分
A
,从而消除循环导入的需要?对于大多数实际用途,Haskell通常可能是GHC特有的。别担心。它无疑是使用最广泛的编译器,大多数时候人们说“Haskell”的意思是“GHC对报告的解释加上一些未指明的GHC扩展”。谢谢你的回答。你能详细说明一下类型类的解决方案吗?我正在匹配包
extcore
中的
Language.Core.Core.Exp
。我有一些模式匹配表达式,比如
evalExp(Var((仅仅是M(P(“base”),[“GHC”],“Num”),“zp”)=用于base和ghc prim中的每个函数bultin。在我看来,问题在于匹配某些字符串。我希望我能在几个文件中匹配类型构造函数
Var
。EDIT:我认为可以通过将变量绑定到字符串,然后将包与正则表达式匹配,然后调用适当的eval@CarlosLópez Camey:类型类在这里可能帮不了你,因为你有一个预先存在的数据类型和非常同质的案例。是递归的吗?@camcann。我懂了。。是的,
evalExp
是递归的。@CarlosLópez Camey:啊,这让事情变得有点棘手。我会给你举一个可能的解决方案的例子,但我认为无论如何都会很尴尬。@CAMcCann:再次感谢你的洞察力。使用
evalExpCases
的解决方案肯定比使用额外的正则表达式匹配要快得多。