我evalExpression :: Exp -> Value在一个模块A中有一个函数,它在很大程度上依赖于参数上的模式匹配Exp.
该文件已经变得足够大,需要更多的组织.我想将模块划分A成模块A.GHC.Num,A.GHC.Types等等.
要么
要么
A.evalExp尝试(在try和catch的意义上)返回值的函数,A.GHC.Num.evalExp如果它缓存错误(非穷举模式匹配),尝试返回 A.GHC.Types.evalExp,等等?更新:
我尝试解决循环依赖,但GHC不相信,它说"模糊发生".
不,您不能在多个文件之间拆分模块,并且您当然无法在不同位置定义函数.与此最接近的是一个函数,它是类型类的一部分,实例在各种模块中定义.但这可能不是你想要的.
但是,它是可以通过编译相互递归模块.从理论上讲,这应该是Just Work(tm),但是GHC需要一点箍跳来做它; 有关详细信息,请参阅"用户指南 ".如果您遇到循环模块导入错误,这应该让您使该版本工作.
没有"好的"方法可以捕获不竭的模式匹配错误并尝试其他方法.有许多不那么好的方法,但你可能不想去那里.
如果你的目标是有很多的情况下单个数据类型模式匹配,而不相互递归的模块或类型类搞乱分裂的事情了最直接的办法是在其他模块不同的功能是采取每个构造函数的内容作为直接参数,然后对导入其他模块并执行调度的模块中的所有情况进行单一模式匹配.
假设你有一个类型的Foo案件A,B(下略),具有类似名称的模块.在"中央"模块中,您可以:
doStuff (A x y) = A.doStuffA x y
doStuff (B z) = B.doStuffB z
Run Code Online (Sandbox Code Playgroud)
...等等.
在某些情况下,以类似的方式分割整个数据类型甚至是有意义的,并为每个构造函数创建一个单独的类型,例如:data Foo = A FooA | B FooB | ....当您有一个复杂的数据类型混乱时,这是最有用的,这些数据类型可能以多种方式相互递归,典型的例子是AST.
好的,这是一种模拟你想要的东西而不做任何粗略的事情的方法.
首先,按照理想的方式将功能分成不同的模块.然后进行以下更改:
更改要使用的结果类型Maybe,包装结果Just并添加生成的catch-all默认情况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
Run Code Online (Sandbox Code Playgroud)
本质上,这是使用Maybe以明确表示非穷尽性的图案,并用替换直接递归fix其中组合,递归函数在每个(个别非递归)组箱子传递式的结构.
这很尴尬,但我不确定是否有更好的方法.可能有一种方法可以使用Template Haskell自动化所有垃圾,但这可能与手动操作一样麻烦.
就个人而言,我可能只是咬紧牙关,把它全部放在一个模块中.
| 归档时间: |
|
| 查看次数: |
635 次 |
| 最近记录: |